Skip to content
Advertisement

Php cart session is not update the attributes, only the quantity

Im trying to update cart attributes but i don’t know why is not working, the quantity is updateing just fine but the nested attributes wont. I don’t figure’it out how to make this to work properly when updating the session cart im not that experienced. Some help is appreciated. Thanks!

Php Cart Class full code:

class Cart
{
    /**
     * An unique ID for the cart.
     *
     * @var string
     */
    protected $cartId;

    /**
     * Maximum item allowed in the cart.
     *
     * @var int
     */
    protected $cartMaxItem = 0;

    /**
     * Maximum quantity of a item allowed in the cart.
     *
     * @var int
     */
    protected $itemMaxQuantity = 0;

    /**
     * Enable or disable cookie.
     *
     * @var bool
     */
    protected $useCookie = false;

    /**
     * A collection of cart items.
     *
     * @var array
     */
    private $items = [];

    /**
     * Initialize cart.
     *
     * @param array $options
     */
    public function __construct($options = [])
    {
        if (!session_id()) {
            session_start();
        }

        if (isset($options['cartMaxItem']) && preg_match('/^d+$/', $options['cartMaxItem'])) {
            $this->cartMaxItem = $options['cartMaxItem'];
        }

        if (isset($options['itemMaxQuantity']) && preg_match('/^d+$/', $options['itemMaxQuantity'])) {
            $this->itemMaxQuantity = $options['itemMaxQuantity'];
        }

        if (isset($options['useCookie']) && $options['useCookie']) {
            $this->useCookie = true;
        }

        $this->cartId = md5((isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : 'SimpleCart') . '_cart';

        $this->read();
    }

    /**
     * Get items in  cart.
     *
     * @return array
     */
    public function getItems()
    {
        return $this->items;
    }

    /**
     * Check if the cart is empty.
     *
     * @return bool
     */
    public function isEmpty()
    {
        return empty(array_filter($this->items));
    }

    /**
     * Get the total of item in cart.
     *
     * @return int
     */
    public function getTotalItem()
    {
        $total = 0;

        foreach ($this->items as $items) {
            foreach ($items as $item) {
                ++$total;
            }
        }

        return $total;
    }

    /**
     * Get the total of item quantity in cart.
     *
     * @return int
     */
    public function getTotalQuantity()
    {
        $quantity = 0;

        foreach ($this->items as $items) {
            foreach ($items as $item) {
                $quantity += $item['quantity'];
            }
        }

        return $quantity;
    }

    /**
     * Get the sum of a attribute from cart.
     *
     * @param string $attribute
     *
     * @return int
     */
    public function getAttributeTotal($attribute = 'price')
    {
        $total = 0;

        foreach ($this->items as $items) {
            foreach ($items as $item) {
                if (isset($item['attributes'][$attribute])) {
                    $total += $item['attributes'][$attribute] * $item['quantity'];
                }
            }
        }

        return $total;
    }

    /**
     * Remove all items from cart.
     */
    public function clear()
    {
        $this->items = [];
        $this->write();
    }

    /**
     * Check if a item exist in cart.
     *
     * @param string $id
     * @param array  $attributes
     *
     * @return bool
     */
    public function isItemExists($id, $attributes = [])
    {
        $attributes = (is_array($attributes)) ? array_filter($attributes) : [$attributes];

        if (isset($this->items[$id])) {
            $hash = md5(json_encode($attributes));
            foreach ($this->items[$id] as $item) {
                if ($item['hash'] == $hash) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Add item to cart.
     *
     * @param string $id
     * @param int    $quantity
     * @param array  $attributes
     *
     * @return bool
     */
    public function add($id, $quantity = 1, $attributes = [])
    {
        $quantity = (preg_match('/^d+$/', $quantity)) ? $quantity : 1;
        $attributes = (is_array($attributes)) ? array_filter($attributes) : [$attributes];
        $hash = md5(json_encode($attributes));

        if (count($this->items) >= $this->cartMaxItem && $this->cartMaxItem != 0) {
            return false;
        }

        if (isset($this->items[$id])) {
            foreach ($this->items[$id] as $index => $item) {
                if ($item['hash'] == $hash) {
                    $this->items[$id][$index]['quantity'] += $quantity;
                    $this->items[$id][$index]['quantity'] = ($this->itemMaxQuantity < $this->items[$id][$index]['quantity'] && $this->itemMaxQuantity != 0) ? $this->itemMaxQuantity : $this->items[$id][$index]['quantity'];

                    $this->write();

                    return true;
                }
            }
        }

        $this->items[$id][] = [
            'id'         => $id,
            'quantity'   => ($quantity > $this->itemMaxQuantity && $this->itemMaxQuantity != 0) ? $this->itemMaxQuantity : $quantity,
            'hash'       => $hash,
            'attributes' => $attributes,
        ];

        $this->write();

        return true;
    }

    /**
     * Update item quantity.
     *
     * @param string $id
     * @param int    $quantity
     * @param array  $attributes
     *
     * @return bool
     */
    public function update($id, $quantity = 1, $attributes = [])
    {
        $quantity = (preg_match('/^d+$/', $quantity)) ? $quantity : 1;

        if ($quantity == 0) {
            $this->remove($id, $attributes);

            return true;
        }

        if (isset($this->items[$id])) {
            $hash = md5(json_encode(array_filter($attributes)));

            foreach ($this->items[$id] as $index => $item) {
                if ($item['hash'] == $hash) {
                    $this->items[$id][$index]['quantity'] = $quantity;
                    $this->items[$id][$index]['quantity'] = ($this->itemMaxQuantity < $this->items[$id][$index]['quantity'] && $this->itemMaxQuantity != 0) ? $this->itemMaxQuantity : $this->items[$id][$index]['quantity'];

                    $this->write();

                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Remove item from cart.
     *
     * @param string $id
     * @param array  $attributes
     *
     * @return bool
     */
    public function remove($id, $attributes = [])
    {
        if (!isset($this->items[$id])) {
            return false;
        }

        if (empty($attributes)) {
            unset($this->items[$id]);

            $this->write();

            return true;
        }
        $hash = md5(json_encode(array_filter($attributes)));

        foreach ($this->items[$id] as $index => $item) {
            if ($item['hash'] == $hash) {
                unset($this->items[$id][$index]);

                $this->write();

                return true;
            }
        }

        return false;
    }

    /**
     * Destroy cart session.
     */
    public function destroy()
    {
        $this->items = [];

        if ($this->useCookie) {
            setcookie($this->cartId, '', -1);
        } else {
            unset($_SESSION[$this->cartId]);
        }
    }

    /**
     * Read items from cart session.
     */
    private function read()
    {
        $this->items = ($this->useCookie) ? json_decode((isset($_COOKIE[$this->cartId])) ? $_COOKIE[$this->cartId] : '[]', true) : json_decode((isset($_SESSION[$this->cartId])) ? $_SESSION[$this->cartId] : '[]', true);
    }

    /**
     * Write changes into cart session.
     */
    private function write()
    {
        if ($this->useCookie) {
            setcookie($this->cartId, json_encode(array_filter($this->items)), time() + 604800);
        } else {
            $_SESSION[$this->cartId] = json_encode(array_filter($this->items));
        }
    }
}

Usage:

  // Include core Cart library
require_once 'class.Cart.php';

// Initialize Cart object
$cart = new Cart([
  // Can add unlimited number of item to cart
  'cartMaxItem'      => 0,

  // Set maximum quantity allowed per item to 99
  'itemMaxQuantity'  => 99,

  // Do not use cookie, cart data will lost when browser is closed
  'useCookie'        => false,
]);

     // Add item with ID #1003 with price, color, and size
        $cart->add('1003', 1, [
         'price'  => '5.99',
         'color'  => 'White',
         'size'   => 'XS',
        ]);

       // Set quantity for item #1003 to 2
         $cart->update('1003', 2, [
          'price'  => '5.99',
          'color'  => 'Red',
          'size'   => 'M',
        ]);

Nested output:

Array
(
    [1003] => Array
        (
            [0] => Array
                (
                    [id] => 1003
                    [quantity] => 1
                    [hash] => 9f6bf828c80134b8d3e07b058045fba6acd4e9ac
                    [attributes] => Array
                        (
                            [price] => 5.99
                            [color] => White
                            [size] => XS
                        )

                )

        )

)

Advertisement

Answer

I’ve checked the code.

When you call the update method there is a comparison between the $attributes already stored in the item, and the new $attributes you are trying to update. The comparison is made by hashing the two arrays…

As you may find… it will not match (hashes will be distinct). In order to update $attributes you should remove the if comparison:

if ($item['hash'] == $hash)

And add this two lines that updates the hash and attributes:

$this->items[$id][$index]['hash'] = $hash;
$this->items[$id][$index]['attributes'] = $attributes;

The final update method should be like this:

public function update($id, $quantity = 1, $attributes = [])
    {
        $quantity = (preg_match('/^d+$/', $quantity)) ? $quantity : 1;
        $attributes = (is_array($attributes)) ? array_filter($attributes) : [$attributes];

        if ($quantity == 0) {
            $this->remove($id, $attributes);

            return true;
        }

        if (isset($this->items[$id])) {

            $hash = md5(json_encode(array_filter($attributes)));

            foreach ($this->items[$id] as $index => $item) {

                    $this->items[$id][$index]['quantity'] = $quantity;
                    $this->items[$id][$index]['quantity'] = ($this->itemMaxQuantity < $this->items[$id][$index]['quantity'] && $this->itemMaxQuantity != 0) ? $this->itemMaxQuantity : $this->items[$id][$index]['quantity'];

                    $this->items[$id][$index]['hash'] = $hash;
                    $this->items[$id][$index]['attributes'] = $attributes;

                    $this->write();

                    return true;
            }
        }

        return false;
    }

Then when you call:

$cart->getItems()

You will see the item updated…

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement