The examples on this site are currently tested to work on Phalcon V3.4 and Phalcon Devtools V3.2 Some issues may arise when using later versions.

Please get in touch or post a comment below the post if you encounter a problem.


In this post we will extend the functionality of the shop window with a navbar showing the number of items in the cart and two navbar buttons to empty the cart or proceed to the checkout page.

Edit the file app/views/product/displayGrid.phtml and add the following code a the top of the page

<div class="container-fluid">
    <nav class="navbar navbar-default navbar-fixed-top">
        <ul class="list-inline nav navbar-nav navbar-right">
            <li><button id="checkOut" onclick="window.location.href='<?php echo $this->url->getBaseUri()?>scorder/checkOut'" type="button" class="btn btn-primary navbar-btn center-block">Check Out</button></a></li>
            <li><button id="emptyCart" type="button" class="btn btn-primary navbar-btn center-block">Empty Cart</button></li>
            <li><span style="font-size:40px;margin-right:0px;" class="glyphicon glyphicon-shopping-cart navbar-btn"></span></li>
            <li><div class="navbar-text" id="cart" style="font-size:12pt;margin-left:0px;margin-right:0px;"><?php echo $totalItems;?><div></li>
            <li><div class="navbar-text" style="font-size:14pt;margin-left:0px;">Item(s)</div></li>
        <ul>
    </nav>
</div>

One slight problem is that now that we have added a fixed navbar to the top of the page the grid is floating underneath and obscuring some of our shop window. To resolve this place the following div container around the block of code you added in step one which renders the grid.

<div style="padding-top:7%" class="container-fluid"><?php echo $this->getContent(); ?></div>
<div class="container-fluid">
    <!-- put the code which renders the grid in here -->
</div>

This will put some padding around your grid and ensure it doesn't float under the navbar. The additional <div> containing echo $this->getContent() will ensure any flash error messages are pulled in above the shop window but below the fixed-top navbar.

Next we need to add a function to the controller which will put some items in the cart when called.

Add the following function to the app/controllers/ProductController.php file

public function addItemAction()
{
	$productid = $this->request->getPost('productid');
	if ($this->session->has('cart')) {
		$cart = $this->session->get('cart');
		if (isset($cart[$productid])) {
			$cart[$productid]=$cart[$productid]+1; //add one to product in cart
		}
		else {
			$cart[$productid]=1; //new product in cart
		}
	}
	else {
		$cart[$productid]=1; //new cart
	}
	$this->session->set('cart',$cart); // make the cart a session variable
}

The cart will be stored in a PHP associative array taking the form $productid => $qty. The productid is the index into the array. That element in the array will store the quantity of that product in the cart. This is the stored in the session. The various if statements check is there already a session and if there is - are there already any of those items in the cart?

Normally this function would be called by a $_POST request from a form. In this example we don't have a form. Also having to submit the page and leave the shop window just to add one item to the cart would detract from the user experience. Rather than doing a submit we will do a jquery Asynchronous Javascript And XML function call. This will allow the data to be passed in a $_POST request as if it came from a form but rather than leaving the page the submit will be performed in the background while the user continues to look at the shop window. Ajax can be a little bit confusing if you're not used to it but the modern web is built on this kind of user experience and jquery has done a good job of making it easier to use.

Before we proceed we have one small problem to resolve. The scaffolder puts a link to a jquery hosted on the google Content Delivery Network in app/views/index.volt. The only problem with this is that its set up to load after the view itself and the link is put in at the bottom of the page. This means that jquery calls aren't available from within the view itself. To resolve this problem edit app/views/index.volt and move the two links which load jquery and bootstrap above the div which contains the echo $this->getContent() which will pull in the view.

Now jquery will be loaded at the top of the page. To observe this - right click and select view page source from your displayGrid.phtml page in the browser. 

Now that issue is resolved you can go ahead and add your jquery code. Add the following script tag at the bottom of your apps/views/displayGrid.pthml file.

<script>
$(".bth,.addItem").click(function() {
	var total = parseInt($('#cart').text());
	var i=$(this).val();
	$('#cart').text(total);
	$.ajax({
	  type: "POST",
	  url: "<?php echo $this->url->getBaseUri()?>" + "product/addItem",
	  data: "productid=" + i,
	  dataType: "html",
	  success: function() {
		  total=total+1;
		  $('#cart').text(total);
	  },
	  error: function() {
		  alert("problem communicating with the server");
	  }
	});
});
</script>

The addItem buttons will now add items to the cart. The quantity of each item which has been added will be stored in the session variable containing the cart and the div container in the navbar indicating the total number of items in the cart will be updated. The sucess function within the jquery call ensures that this will only happen if we get a success response from the server indicating that the item has been added to the cart.

In the next post I'll show you how to make sure the contents of the cart are loaded when the page loads and we'll add a function to empty the cart.