sandwichbar online order website

The place to talk about things that are related to CMS Made simple, but don't fit anywhere else.
Post Reply
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

sandwichbar online order website

Post by HarmO »

Hi,
I would like your feedback on this:

i need to make a online order website for a company that makes sandwiches.
they want this to speed up the queue they have in front of their shop every noon.

i've been looking at the modules "product" & "cart2" the last 2 days, but was unable to set it up orders with different options (except with SKU codes which they don't have).

For example people want to order a ham cheese sandwich with extra pickles as topping for Tom and 1 ham cheese sandwich with mayonnaise for Linda.

Within the product detail page they should be able to select some options and add it to the cart. (options do change the price).

No need for shipping, taxes or online payments for this shop.
But i would like to use FEU.

What do you think? Will this work with the above mentioned modules or do i need to build my own shopping cart??
Kind regards,
HarmO
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

Re: sandwichbar online order website

Post by HarmO »

Ok, i made a simple shopping cart UDT that adds my items into the session variable shopping_cart (see code below).

Now the only thing i'm struggling with is this: i want to check if the description tag of a newly added product is different from an existing product line so i can add twice the same product, but with different descriptions... (example ham sandwich on white bread and ham sandwich on brown bread.)

Code: Select all

if(isset($_POST["cartaction"]) and !empty($_POST["cartaction"]))
{
	switch($_POST["cartaction"]){
		case "add":
			if(isset($_SESSION["shopping_cart"]))
			{  
				$item_array_id = array_column($_SESSION["shopping_cart"], "item_id");
				if(!in_array($_POST["itemID"], $item_array_id))
				{  
					$count = count($_SESSION["shopping_cart"]);  
					$item_array = array(   
						'item_id'			=>     $_POST["itemID"],  
						'item_name'			=>     $_POST["name"],
						'item_details'		=>     $_POST["details"],
						'item_price'		=>     $_POST["price"],  
						'item_quantity'		=>     $_POST["quantity"] 
					);  
					$_SESSION["shopping_cart"][$count] = $item_array;  
				}  
				elseif(in_array($_POST["itemID"], $item_array_id))
				{  
					$cart_item = array_search($_POST["itemID"], $item_array_id);
					$_SESSION["shopping_cart"][$cart_item]['item_quantity']= $_SESSION["shopping_cart"][$cart_item][item_quantity]+$_POST["quantity"];
				}  
			}  
			else
			{  
				   $item_array = array(  
						'item_id'			=>     $_POST["itemID"],  
						'item_name'			=>     $_POST["name"],  
						'item_details'		=>     $_POST["details"],
						'item_price'		=>     $_POST["price"],  
						'item_quantity'		=>     $_POST["quantity"]  
				   );  
				   $_SESSION["shopping_cart"][0] = $item_array;  
			}
			break;
		case "eddit":
			$_SESSION["shopping_cart"][$_POST["cart_item"]]['item_quantity'] = $_POST["quantity"];
			break;
		case "remove":
			unset($_SESSION["shopping_cart"][$_POST["cart_item"]]);
			$_SESSION["shopping_cart"]=array_values($_SESSION["shopping_cart"]);
			break;
	}
}
Kind regards,
HarmO
User avatar
velden
Dev Team Member
Dev Team Member
Posts: 3483
Joined: Mon Nov 28, 2011 9:29 am
Location: The Netherlands

Re: sandwichbar online order website

Post by velden »

I don't see a description tag in your code.

I think it might be possible to make a hash of the description and use it as the key for the array:

$_SESSION["shopping_cart"][YOUR_HASH_VALUE] = $item_array;
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

Re: sandwichbar online order website

Post by HarmO »

Sorry, my descriptiontag is $_POST["details"].
Kind regards,
HarmO
User avatar
velden
Dev Team Member
Dev Team Member
Posts: 3483
Joined: Mon Nov 28, 2011 9:29 am
Location: The Netherlands

Re: sandwichbar online order website

Post by velden »

Then you might use that to create the hash.

One warning: never trust user input. Those $_POST variables are user input so be careful to check their values before further processing.
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

Re: sandwichbar online order website

Post by HarmO »

I was counting on sanitizing the user input, no worries there.
i see where your getting at, but in my case the check should now be on the combination of 2 variables: $_POST["itemID"] and $_POST["details"].

I'm not realy a PHP programmer so if i just can do the check in this part, i don't have to reorganize my cart's mechanism for the keys, nor do i need to redo my cart template ect.

Code: Select all

$item_array_id = array_column($_SESSION["shopping_cart"], "item_id");
//check if already in cart
if(!in_array($_POST["itemID"], $item_array_id)) //not in the cart yet?
{
    add to the end of the cart
}
else{
    Modify line in cart
}
Kind regards,
HarmO
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

Re: sandwichbar online order website

Post by HarmO »

I made it work with the hash, thanks for the idea Velden.

will be posting details after i finished up the project.
Kind regards,
HarmO
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

Re: sandwichbar online order website

Post by HarmO »

So i promised my simple solution and here it is:

Well it is not that simple but this way i did not have to work with the e-commerce suite which was to advanced for my use case.

As suggested by Velden i created a plugin called function.simplecart.php in the "/assets/plugins" folder.

in this plugin i wrote the next function, where again as suggested by Velden, i generate a ripemd160 hash for each line in the cart.

Code: Select all

<?php
function smarty_cms_function_simplecart()
{
	if(isset($_POST["cartaction"]) and !empty($_POST["cartaction"]))
	{
		switch($_POST["cartaction"]){
			case "add":
				//check vars
				
				$postItemId = "";
				if(isset($_POST["itemID"])){ 
					$postItemId = filter_input(INPUT_POST, 'itemID', FILTER_SANITIZE_SPECIAL_CHARS);
				}
				$postName = "";
				if(isset($_POST["name"])){
					$postName = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_SPECIAL_CHARS);
				}
				$postDetails = "";
				if(isset($_POST["details"])){
					$postDetails = filter_input(INPUT_POST, 'details', FILTER_SANITIZE_SPECIAL_CHARS);
				}
				$postPrice = "";
				if(isset($_POST["price"])){
					$postPrice = filter_input(INPUT_POST, 'price', FILTER_SANITIZE_SPECIAL_CHARS);
				}
				$postQuantity = ""; 
				if(isset($_POST["quantity"])){
					$postQuantity = filter_input(INPUT_POST, 'quantity', FILTER_SANITIZE_SPECIAL_CHARS);
				}
				$postRemark ="";
				if(isset($_POST["remark"])){  
					 $postRemark = filter_input(INPUT_POST, 'remark', FILTER_SANITIZE_SPECIAL_CHARS);
				}

				$postHash = hash('ripemd160', urlencode($postItemId."-".$postDetails."-".$postRemark));
				
						
				if(isset($_SESSION["cart"][lines])) //if shoppingcart exists
				{  
					$item_array_id = array_column($_SESSION["cart"][lines], "item_hash");
					
					if(!in_array($postHash, $item_array_id))
					{  
						$count = count($_SESSION["cart"][lines]);  
						$item_array = array(   
							'item_id'			=>	$postItemId,  
							'item_name'			=>	$postName,
							'item_details'		=>	$postDetails,
							'item_price'		=>	$postPrice,  
							'item_quantity'		=>	$postQuantity,
							'item_remark'		=>	$postRemark,
							'item_hash'			=>	$postHash
						);  
						$_SESSION["cart"][lines][$count] = $item_array;  
					}  
					else //if(in_array($posthash, $item_array_id))
					{  
						$cart_item = array_search($postHash, $item_array_id);
						$_SESSION["cart"][lines][$cart_item]['item_quantity']= $_SESSION["cart"][lines][$cart_item][item_quantity]+$postQuantity;
					} 
				}  
				else
				{  
					   $item_array = array(  
							'item_id'			=>	$postItemId,  
							'item_name'			=>	$postName,
							'item_details'		=>	$postDetails,
							'item_price'		=>	$postPrice,  
							'item_quantity'		=>	$postQuantity,
							'item_remark'		=>	$postRemark,
							'item_hash'			=>	$postHash
					   );  
					   $_SESSION["cart"][lines][0] = $item_array;
				}
				break;
			case "eddit":
				$postCartItem = filter_var($_POST["cart_item"], FILTER_SANITIZE_SPECIAL_CHARS);
				$postQuantity = filter_var($_POST["quantity"], FILTER_SANITIZE_SPECIAL_CHARS);
				$_SESSION["cart"][lines][$postCartItem]['item_quantity'] = $postQuantity;
				break;
			case "remove":
				$postCartItem = filter_var($_POST["cart_item"], FILTER_SANITIZE_SPECIAL_CHARS);
				unset($_SESSION["cart"][lines][$postCartItem]);
				$_SESSION["cart"][lines]=array_values($_SESSION["cart"][lines]);
				break;
			case "empty":
				unset($_SESSION["cart"][lines]);
				break;
		}
		$_SESSION["cart"][details][itemcount] = array_sum(array_column($_SESSION["cart"][lines], "item_quantity"));
		if (count($_SESSION["cart"][lines]) > 0)
		{
			foreach($_SESSION["cart"][lines] as $line)
			{
				$grantotal=$grantotal+($line[item_price]*$line[item_quantity]);
			}
			$_SESSION["cart"][details]["grandtotal"]= $grantotal;
		}
		else
		{
			$_SESSION["cart"][details]["grandtotal"]= 0;
		}
		
		
	}
	if(!isset($_SESSION["cart"][details]))
	{
	   $_SESSION["cart"][details][itemcount] = 0;
	   $_SESSION["cart"][details]["grandtotal"]= 0;
	}
}
?>
Next i made sure to load the {simplecart} function as first on the page with the add to cart button.

Next i had a LISE instance with products
this is my summary template:

Code: Select all

<div class="products">
	{foreach from=$items item=item}
	{LISELoader item='category' force_array=1 value=$item->fielddefs.cat->value assign='cats'}
	<div class="product">
		{if $item->fielddefs.foto->value}
			<div class="text-center">
				{CGSmartImage src="{$item->fielddefs.foto->GetImagePath(true)}/{$item->fielddefs.foto->value}" filter_resize='h,100' noembed=1}
			</div>
		{/if}
		<form method="post" action="{cms_selflink href=8}" class="add_to_cart">
			<p class="title"><strong>{$item->title}</strong></p>
			{if 'Broodje'|in_array:$cats}
				<select name="details" class="details">
					{foreach $shop.broodjes as $broodje}
						<option value="{$broodje}">{$broodje}</option>
					{/foreach}
				</select>
			{/if}
			{if !empty($item->desc)}<p>{$item->desc}</p>{/if}
			<div class="prijs">€ {$item->price}</div>
			<input type="hidden" name="cartaction" class="cartaction" value="add">
			<input type="hidden" name="itemID" class="itemID" value="{$item->alias}{if 'Broodje'|in_array:$cats}-{$cats|implode:'-'}{/if}">
			<input type="hidden" name="name" class="name" value="{if 'Broodje'|in_array:$cats}{$cats|implode:'-'} {/if}{$item->title}">
			<input type="hidden" name="price" class="price" value="{$item->price}">
			<input type="hidden" name="quantity" class="quantity" value="1">
			<button type="submit" name="add_to_cart" class="cartbutton"><i class="fa fa-cart-plus"></i></button>
			<a href="{$item->url}" class="button">Opmerking</a>
		</form>
	</div>
	{/foreach}
	</div>
and detail template:

Code: Select all

{include file='cms_template:Prinske-Vars'}
{LISELoader item='category' force_array=1 value=$item->fielddefs.cat->value assign='cats'}
<div class="product" id="productdetail">
	<form method="post" action="{cms_selflink href=2}" class="add_to_cart">
		<p class="title"><strong>{$cats|implode:'-'} {$item->title}</strong></p>
		{if $item->fielddefs.cat->value|strstr:'1'}
			<select name="details" class="details">
				{foreach $shop.broodjes as $broodje}
					<option value="{$broodje}">{$broodje}</option>
				{/foreach}
			</select>
		{/if}
		{if !empty($item->desc)}<p>{$item->desc}</p>{/if}
		<div class="prijs">€ {$item->price}</div>
		<input type="hidden" name="cartaction" value="add">
		<input type="hidden" name="itemID" class="itemID" value="{$item->alias}{if 'Broodje'|in_array:$cats}-{$cats|implode:'-'}{/if}">
		<input type="hidden" name="name" class="name" value="{if 'Broodje'|in_array:$cats}{$cats|implode:'-'} {/if}{$item->title}">
		<input type="hidden" name="price" class="price" value="{$item->price}">
		<input type="hidden" name="quantity" class="quantity" value="1">
		<textarea name="remark" id="remark" cols="30" rows="10" placeholder="{$_t.form.remark}"></textarea>
		<button type="submit" name="add_to_cart" class="cartbutton"><i class="fa fa-cart-plus"></i></button>
	</form>
</div>
I also made sure that on submit of the add-to-cart form, the page did not reload and the cart-icon with the number of items got updated.
In the summary page a reload would mean you have to scroll all the way down again to continue.

Preventing a reload was don with a little Jquery functions you can call on each form:

Code: Select all

$(".products .product").each(function(){
	$("form", this).on( "submit", function(event) {
		event.preventDefault(); 
		var posturl = $(this).attr("action") + "?showtemplate=false"; //console.log('posturl: '+ posturl);
		var postdata = $(this).serialize(); //console.log('postdata: '+ postdata);
		
		$.post(posturl,postdata,function(data) { 
			$(".cart.items").text(data);
// updates the 
		});
	});
});
next you want the see and maybe modify the cart....

Code: Select all

{if $smarty.session.cart.details.itemcount > 0}
	<div class="showcart">
	{foreach $smarty.session.cart.lines $line}
		<div class="cart-item">
			<div class="name">
				{$line.item_name|escape}{if $line.item_details} ({$line.item_details|escape}{if !empty($line.item_remark)} - {$line.item_remark}{/if}){/if}
			</div>
			<div class="price">
				{if $line.item_quantity gt 1}
				<form action="{cgsimple::self_url()}" method="post" class="minus1">
					<input type="hidden" name="cartaction" value="eddit">
					<input type="hidden" name="cart_item" value="{$line@key|escape}">
					<input type="hidden" name="quantity" value="{$line.item_quantity|escape -1}">
					<button type="submit" name="eddit"><i class="fa fa-minus"></i></button>
				</form>
				{else}
				<button type="submit" name="eddit" disabled><i class="fa fa-minus"></i></button>
				{/if}
				{$line.item_quantity|escape}
				<form action="{cgsimple::self_url()}" method="post" class="add1">
					<input type="hidden" name="cartaction" value="eddit">
					<input type="hidden" name="cart_item" value="{$line@key|escape}">
					<input type="hidden" name="quantity" value="{$line.item_quantity|escape +1}">
					<button type="submit" name="eddit"><i class="fa fa-plus"></i></button>
				</form>
				<span>€{($line.item_price*$line.item_quantity)|string_format:"%.2f"}</span>
				<form action="{cgsimple::self_url()}" method="post" class="remove">
					<input type="hidden" name="cartaction" value="remove">
					<input type="hidden" name="cart_item" value="{$line@key|escape}">
					<button type="submit" name="remove"><i class="fa fa-trash"></i></button>
				</form>
			</div>
		</div>
	{/foreach}
		<div class="grandtotal">Totaal: € {$smarty.session.cart.details.grandtotal}</div>
	</div>
{else}
	<p>Het winkelwagentje is leeg</p>
{/if}
{/function}
there will probably be some improvements to be made on the plugin.
All the rest is layout and setup work.

I hope i helped someone by sharing my solution.
Kind regards,
HarmO
User avatar
velden
Dev Team Member
Dev Team Member
Posts: 3483
Joined: Mon Nov 28, 2011 9:29 am
Location: The Netherlands

Re: sandwichbar online order website

Post by velden »

Bedankt voor je uitleg! Nog erg uitgebreid voor een 'niet PHP-programmeur'.

Paar opmerkingen:

Aan een array in php kun je gewoon nieuwe elementen toevoegen zonder daarvoor per se een index op te geven.

http://php.net/manual/en/language.types.array.php

Code: Select all

$arr[key] = value;
$arr[] = value;
// key may be an integer or string
// value may be any value of any type
Dat zou je code iets eenvoudiger maken en wat dubbele zaken eruit kunnen.

Ik denk dat

Code: Select all

$_SESSION["cart"][lines]
zou 'moeten' zijn

Code: Select all

$_SESSION['cart']['lines']
omdat, voor zover ik het zie, 'lines' als een normale string moet worden behandeld.

Verder vind ik het tricky dat je de gegevens van de bezoeker overneemt, zoals de prijs bijvoorbeeld. Ik neem aan dat de website eigenaar de bedragen nog een keer controleert alvorens te leveren?
Het is anders relatief eenvoudig om de prijzen te beinvloeden.

Je zou dat kunnen oplossen door met codes voor de producten en opties te werken en daarvan de data uit LISE op te vragen en die dan in de sessie op te slaan. Maar dat maakt het uiteraard een stukje complexer.

Mooie handleiding zo!
HarmO
Power Poster
Power Poster
Posts: 251
Joined: Thu Jan 26, 2012 3:22 pm
Location: Belgium

Re: sandwichbar online order website

Post by HarmO »

Hi Velden,
Thank you for the feedback.
i did my best, but as you could see, there are many improvements one could make on my code :-)

i'll improve my code for the $_SESSION['cart']['lines'] as you suggested.

Many plug&play cart solutions use this implementation.
Yes we could get the information from the DB instead, but this would have complicated things and budget was limited ;-)

The owner of the sandwich bar does checks all orders, then confirms to the customer so this solution is sufficient.

I'm also curious to the tutorial Rolf is making...
Kind regards,
HarmO
Post Reply

Return to “The Lounge”