You don’t say where you are trying to do $cart->check('name'). I’m guessing it is something you want include in new add() method logic?
However, in the add() method, $cart is an array but you are trying to use it as an object by running its check() method (which does not exist).
One way you could go, is to key your $cart array with the product id rather than letting it be a sequential numeric index as you are currently.
//set $order as you have in your existing code
//get the session as you are currently doing
$session = $this->request->getSession();
$cart = $session->read('cart');
//change the way you put items on the cart array
if (isset($cart[$order->product_id])) {
//product is already in the cart
//take whatever action your business rules suggest
} else {
$cart[$order->product_id] = $order;
}
You also might consider going a step further and making a Cart object that encapsulates the basic features of your cart. This will decouple your cart implementation from the rest of your code. This could be a simple class that did not extend anything else.
I’ve sketched one out that will insert cart items and return an array of all the items.
Also after inserting your can get a result boolean and success/error message from the object.
Suppose you build it in a new directory Lib (App\Lib)
Code for the example Cart class
<?php
namespace App\Lib;
use Cake\ORM\Entity;
/**
* Simple example Cart Class
*
* @package App\Lib
*/
class Cart
{
/**
* @var bool
*/
protected $result;
/**
* @var string message from last action
*/
protected $message = 'No cart action has been taken';
/**
* @var array
*/
protected $cart_contents = [];
/**
* Place the entity in the the cart
*
* Key by entity->id by default. Use a provided
* key otherwise
*
* @param Entity $product entity containing a
* @param null|int|string $key
*/
public function insert($product, $key = null)
{
$this->clearResult();
if (!isset($product->id) && is_null($key)) {
$this->setResult(
false,
'\'id\' was not found on the entity and no other key was provided'
);
}
$key = $key ?? $product->id;
//do other insertion logic here for example
if(isset($this->cart_contents[$key])) {
$this->setResult(false, 'The item is already in the cart');
} else {
$this->cart_contents[$key] = $product;
$this->setResult(true, 'The item was added to the cart');
}
return $this;
}
/**
* Return the current cart contents
*
* Messaging is set to 'no action' since we don't return
* this object and so the result can't be read from the return value
* @return array
*/
public function getContents()
{
$this->clearResult();
return $this->cart_contents;
}
/**
* If no action has been performed return false
*
* @return bool
*/
public function result()
{
return $this->result ?? false;
}
/**
* The message from the last action
*
* @return string
*/
public function message()
{
return $this->message;
}
/**
* Set/reset the default state of the object's activity reporting
*/
protected function clearResult()
{
$this->result = null;
$this->message = 'No cart action has been taken';
}
/**
* Create a report for the outside world
*
* @param bool $result
* @param string $message
*/
protected function setResult($result, $message)
{
$this->result = $result;
$this->message = $message;
}
}
With this class you simplify the logic in your controller and make things easier to read. Revising the code from my previous answer:
//set $order as you have in your existing code
//get the session as you are currently doing
$session = $this->request->getSession();
// if there is no cart on the session yet make a new one
$cart = $session->read('cart') ?? new Cart();
$cart->insert($order);
// failure to insert still returns a valid cart, always store it
$session->write('cart', $cart);
if($cart->result() {
$this->Flash->success($cart->message();
} else {
$this->Flash->error($cart->message();
}
And if the business rules for how you handle duplicates changes, your controller code will not have to be modified. You could for example increase the number of a single product in the cart and send a message back saying ‘There are now x widgits in the cart.’
I created the Lib directory at the root of the project and also in the src folder to test. And then the cart.php class. Where should I create the directory? I get this error above in the insert () method.
Well, none of the code I wrote was tested. It was only an example I threw together to give you an idea about how you might approach this problem.
If you actually want to go down this path, you will have a little work to do I’m sure.
But the error you are seeing sounds like it is related to the result of your Session->read. It has returned an array rather than an object. This might be related to some leftover data in the session from your previous code…
You can debug the value returned from the session and see what it is and how you should actually be using it.
The way I set the namespace in my sample class means the file should be at:
I’ll be interested in any observations you have regarding the viability of the class. I plan on expanding soon for a project I’m working on that needs a simple little shopping cart.