3
votes

I am trying to store multiple values(products) in my session so that i can display them in a basket. However for some reason it only stores one product..

In the first pages controller I created an array in witch I will store my selected products later:

public function indexAction()
    {

            $em = $this->getDoctrine()->getManager();
            $products = $em->getRepository('MpShopBundle:Product')->findAll();

            $session = $this->getRequest()->getSession();

            $item = array();

            $session->set('itemCart', $item);

               return $this->render('MpShopBundle:Frontend:index.html.twig',  array(
               'products'=>$products       
               ));

    }

Then when a user selects a product a new page opens with the products detail(product is selected by id). Then if the user adds the product to the cart he is taken to the basket page and I save the product in an array with session:

public function viewAction($id)
    {


        $em = $this->getDoctrine()->getManager();
        $product = $em->getRepository('MpShopBundle:Product')->find($id);

        $session = $this->getRequest()->getSession();

        $itemCart = $session->get('itemCart');

        array_push($itemCart, $product);

        $session->set('itemCart', $itemCart);

        return $this->render('MpShopBundle:Frontend:product_details.html.twig', array(
        'product'=>$product
        ));

    }

In the basket page I get the products:

public function summaryAction()
    {


            $em = $this->getDoctrine()->getManager();
            $products = $em->getRepository('MpShopBundle:Product')->findAll();

            $session = $this->getRequest()->getSession();
            $itemCart = $session->get('itemCart');

               return $this->render('MpShopBundle:Frontend:product_summary.html.twig',  array(
               'products'=>$products,
               ));
    }

Now in my twig I display them like this. First i get the products:{% set items = app.session.get('itemCart') %}. Then i go cycle through them and try to display:

  {% for item in items %}
                <tr>
                  <td> <img width="60" src="{{ asset('bundles/mpFrontend/assets/products/4.jpg') }}" alt=""/></td>

                  <td>{{ item.model }}</td>
                  <td>
                    <div class="input-append"><input class="span1" style="max-width:34px" placeholder="1" id="appendedInputButtons" size="16" type="text"><button class="btn" type="button"><i class="icon-minus"></i></button><button class="btn" type="button"><i class="icon-plus"></i></button><button class="btn btn-danger" type="button"><i class="icon-remove icon-white"></i></button>             </div>
                  </td>
                  <td>$120.00</td>
                  <td>$25.00</td>
                  <td>$15.00</td>
                  <td>$110.00</td>
                </tr>

                {% endfor %}

The first product is displayed. When I go back and select another product, the new product overlaps the older one and is the only one shown. Why?

PROBLEM FOUND. HOW To FIX IT? Ok so I think I found my problem. Im only getting one value because when I add my first product to the basket I go back to my index page to select another product myy indexController $item = array(); part and makes my array empty again. Thats the problem. But if i select the first product and just browse back without reloading the page and add a new product it works. So what can I do with my indexController to make it not empty my cart everytime I go back?

2

2 Answers

2
votes

Well, I think the very basic solution can be:

public function indexAction()
{
    ...
    if (!$session->get('itemCart')) {
         $session->set('itemCart', array());
    } 

Then I believe it would be better to abstract managing session data freely in those controllers, maybe better to wrap it in a dedicated service and/or within an event logic, and use that one inside the controllers. This way you can avoid code duplication, you obtain better reusable code and responsibilities in one shot.

-----EDIT2-----

What you're asking now it's a long story and maybe I'm not the best to explain it.

What I meant (was just a thought and not a things that must be done) was:

//IndexAction method

// You could "wrap" this part of the code:
$session = $this->getRequest()->getSession();
$item = array();
$session->set('itemCart', $item);

// with a service (see Symfony DOC) like "CartSession" or 
// simply "Cart" and use it there like:
$this->cartSession->init();
// or  
$this->cart->init();
// And inside the init method you can use the logic you want; 
// Any further changes or if you want to move the session from $_SESSION to another storage mechanism, 
// this doesn't impact on your controller code but only inside your service. 

and

// viewAction method

// You could "wrap" this part of the code:
$session = $this->getRequest()->getSession();
$itemCart = $session->get('itemCart');
array_push($itemCart, $product);
$session->set('itemCart', $itemCart);

// inside the same service previously defined and used in indexAction
$this->cart->add($itemCart);

However I can suggest to read something about:

1
votes

I think you should add a new item to the cart array by using

$item[] = $product;

instead of

array_push($itemCart, $product);

From PHP's manual:

Note: If you use array_push() to add one element to the array it's better to use $array[] = because in that way there is no overhead of calling a function.

Note: array_push() will raise a warning if the first argument is not an array. This differs from the $var[] behaviour where a new array is created.

Since your array is null to start, I'm not confident that you receive an array in the viewAction controller. I would change the viewAction to:

$itemCart = $session->get('itemCart');
if(!is_array($itemCart){
    $itemCart = array();
}
$itemCart[] = $prodcut;

$session->set('itemCart', $itemCart);