Winkelmand

Inleiding Winkelmand maken Winkelmand vullen Winkelmand tonen Order plaatsen

Inleiding

Dit hoofdstuk gaat over het winkelmandje. Als een klant aan het bestellen is wil je de bestelde producten nog niet vastleggen in de database voordat de klant zijn bestelling gaat afronden. Tot die tijd moeten wel ergens de voorlopige bestelgegevens worden opgeslagen. Dit gaan we regelen door de $_SESSION variabele te gebruiken. Je weet uit het vorige hoofdstuk al dat je de gegevens van de gebruiker kan opslaan in deze variabele en dat zolang de klant is aangemeld en de browser niet wordt afgesloten deze gegevens beschikbaar blijven.

In de vorige hoofdstukken hebben we code ontwikkeld voor de eigenaren van het bedrijf. Producten kunnen daarin worden toegevoegd, bewerkt en verwijderd. Bovendien mag een medewerker dat alleen doen als deze is ingelogd. Maak eerst een nieuwe map klant en kopieer daar de bestanden index.php, database.php, algemeen.php en product.php heen.
Verwijder in algemeen.php alle acties uit het menu die niet door klanten mogen worden uitgevoerd.
Verwijder uit index.php alle cases in de switch die niet door klanten mogen worden uitgevoerd.
Verwijder uit product.php alle functies die niet door klanten mogen worden uitgevoerd.

Als autorisatie ook al klaar is kopieer je ook index.php en autorisatie.php. In het voorbeeld hieronder is autorisatie nog niet aanwezig.

We gaan hier niet voor alles volledig uitgewerkte code geven. Eigen productie is gewenst.

Aan het einde van dit hoofdstuk weet je :

  • Hoe je een winkelmand maakt;
  • Wat een associatieve array is;
  • Hoe je een winkelmand vult en toont;
  • Welke SQL queries er gemaakt moeten worden;

Winkelmand maken

In index.php plaatsen we acties om de winkelmand aan te maken en te vullen. De functies die deze acties moeten gaan doen plaatsen we in winkelmand.php Op de eerste regel in index.php moet session_start(); komen te staan want net als bij autorisatie moeten we nu bij ieder bezoek onthouden wat er in de winkelmand zit. Staat session_start(); nog niet in index.php voeg die dan toe. Op de volgende regel maken we het winkelmandje.

 // Als er nog geen winkelwagen aanwezig is maak er dan één
 if(!isset($_SESSION['winkelwagen']))
 {
	$_SESSION['winkelwagen']=array();
 }
 

Je ziet dat we een array gaan gebruiken als winkelwagen. We gebruiken een associatieve rij. Voorbeelden van associatieve rijen zijn o.a. $_GET, $_POST, en $_SESSION. Associatieve rijen bevatten key, value paren waarin de key de index in de rij is en value de waarde van het element in de rij behorende bij index key. Voorbeeld:

<?php
$Leeftijd=array("Peter"=>"35","Ben"=>"37","Kees"=>"43");
$Leeftijd["John"]=57;
echo "Kees is " . $Leeftijd['Peter'] . " jaar oud en John is " . $Leeftijd['John'] . " jaar oud.";
?>
 

Je kunt alle waarden in een associatieve rij als volgt benaderen.

<?php
$Leeftijd=array("Peter"=>"35","Ben"=>"37","Kees"=>"43");
$Leeftijd["John"]=57;
// algemeen 
$uitvoer="";
foreach($Leeftijd as $key=>$value)
{
  uitvoer .=  "Het element met index key=" . $key . " heeft de waarde value=" . $value."<br>";
}
// in dit geval met zinvolle naamgeving
foreach($Leeftijd as $naam=>$leeftijd)
{
  uitvoer .=  "$naam is $leeftijd." jaar oud<br>";
}
?>
 
Opdrachten
  1. Test de bovenstaande "Leeftijd" voorbeelden.
  2. Vervang Leeftijd in het voorbeeld door $_SESSION['winkelwagen']
  3. Wat zou je als de keys in de array $_SESSION['winkelwagen'] willen gebruiken en wat de waarden?

Winkelmand vullen

In de vorige paragraaf hebben we gezien dat in $_SESSION['winkelwagen'] een associatieve array is aangemaakt die de lijst met bestelde producten tijdelijk moet gaan opslaan. Pas als de klant de bestelling bevestigd moet de inhoud van de array naar de database worden overgezet. Als de productenlijst op de goed manier is aangemaakt is per product een invoerveld voor het aantal dat de klant wil kopen en een bestelknop om deze aan het winkelmandje toe te kunnen voegen. Als op de bestelknop wordt gedrukt moet naar de server niet alleen het aantal maar ook het id van het product worden opgestuurd. Ik neem even aan dat je in het formulier de namen "aantal" en "productid" hebt gebruikt. De functie die achter de bestelknop wordt geplaatst moet dan in ieder geval de volgende code bevatten

$aantal="";
$id="";
if(isset($_POST["productid"]))
{
	$id=trim($_POST["productid"]);
}
if(isset($_POST["aantal"]))
{
	$aantal=trim($_POST["aantal"]);
}
if( !empty($id) )
{
	$_SESSION['winkelwagen'][$id]=$aantal;
}
Opdrachten
  1. Leg deze code aan je zelf uit.
  2. Wat gebeurt er er als twee keer het zelfde product wordt besteld, b.v. eerst met aantal 6 en daarna met aantal 2?
  3. Wat wil je dat er gebeurd als de klant een spatie opstuurt, geen getal of een getal kleiner of gelijk aan 0?
  4. Hoe is de uitvoer geregeld?
  5. Kopieer uit de actie.php van het vorige hoofdstuk de functie toonArtikelenLijst en plaats deze in de actie.php van de klantensite pas deze aan zodat de wijzig en verwijder knop worden vervangen door een veld voor het gewenste aantal met name="aantal" en een knop bestel. Voeg bij de klantensite aan het menu een knop "Toon producten" en doe dit ook bij de switch een actie "Toon producten" zodanig dat de productenlijst wordt getoond.
  6. Zorg ervoor dat als de bestelknop wordt ingedrukt bovenstaande code wordt uitgevoerd.

Als de klant een spatie opstuurt, geen getal of een getal kleiner of gelijk aan 0, dan willen we eigenlijk het hele product uit de winkelmand verwijderen. Het volgende voorbeeld doet dit:

$aantal="";
$id="";
if(isset($_POST["productid"]))
{
	$id=trim($_POST["productid"]);
}
if(isset($_POST["aantal"]))
{
	$aantal=(int)trim($_POST["aantal"]);
}
if( !empty($id) )
{
	if( is_int($aantal) && $aantal>0 )
	{
		$_SESSION['winkelwagen'][$id]=$aantal;
	}
	else
	{
		// Verwijder $_SESSION['winkelwagen'][$id] 
		unset($_SESSION['winkelwagen'][$id]);
	}
}

Winkelmand tonen

Er zijn verschillende manieren om de winkelmand te tonen. Je kunt de toonArtikelenLijst als basis gebruiken voor een nieuwe functie of je kunt de toonArtikelenLijst van een parameter ( function toonArtikelenLijst( $alswinkelwagen ) {...} ) voorzien zodat de uitvoer conditioneel kan worden gemaakt. Wat in ieder geval moet gebeuren is dat we uit de datbase niet alle maar alleen de producten uit de winkelmand opvragen. Dus niet alleen
"SELECT * FROM product"
maar
"SELECT * FROM product WHERE <conditie> ".
Wat moet de conditie zijn?

MYSQL geeft de mogelijkheid om in de conditie een lijst aan te bieden van te selecteren items. De query
"SELECT * FROM product WHERE `id` IN ( '12', '15' , '110')"
geeft als resultaat de records uit de tabel waar de id gelijkj is aan 12, 15 en 110. Alle andere records woorden niet opgehaald.

Hoe maak je "WHERE `id` IN ( '12', '15' , '110')" uitgaande van $_SESSION['winkelwagen']?
Hier maken we gebruik van foreach loop uit paragraaf 2 van dit hoofdstuk.

 $conditie = "";
 if( count($_SESSION['winkelwagen'])>0 )
 {
	$conditie = "WHERE `id` IN (";
	$first=true;
	foreach($_SESSION['winkelwagen'] as $id => $aantal)
	{
		if( $first ) $first=false;
		else $conditie .= ",";
		$conditie .= "'$id'";
	}
	$conditie .= ")";
 }
 

Natuurlijk moeten na het uitvoeren van de query de aantallen van de bestelde producten getoond worden en eventueel weer worden veranderd. Je kunt dan bijvoorbeeld de volgende code gebruiken in de while lus van het maken van de productentabel:

$aantal="";
if(isset($_SESSION['winkelwagen'][$id])) $aantal = $_SESSION['winkelwagen'][$id];
Opdrachten
  1. Leg bovenstaande code weer aan je zelf uit.
  2. Zorg voor een actie "Toon winkelwagen" en code zodanig dat de inhoud van de winkelwagen wordt getoond en er een knop "bevestig order" of iets dergelijks komt. Na het indrukken van de knop moet de order worden opgeslagen in de database. Daar gaat de volgende paragraaf over.

Order plaatsen

Een order behoort bij een klant en bevat producten. In de database bevat de order tabel alleen een verwijzing naar de klant. De order_product tabel bevat de koppeling naar de order. Om de order met zijn producten moeten drie dingen gebeuren:

  1. Er moet een record worden toegevoegd aan de order tabel met de id van de klant aanwezig in $_SESSION["klantnummer"].
  2. Het id van die order moet worden opgehaald.
  3. Met dit orderid en de inhoud van $_SESSION['winkelwagen'] moeten records worden toegevoegd aan de order_product tabel.

Echter als het plaatsen van de artikelen in de order_product tabel mislukt zitten we in de database opgescheet met een lege order. We moeten er dus voor zorgen dat als dit gebeurd ook de order weer uit de database wordt verwijderd. MySQL regelt dit door gebruik te maken van transacties. Je start een transactie, gaat er onderweg iets mis dan annuleer je die transactie (rollback) anders gaat de transactie door (commit).

Een voorbeeld van de benodigde set queries en instructies om een order van klant 1 die de 6 exemplaren van product 1 en 3 exemplaren van product 2. op te slaan is:

 // $db is een bestaande myqli connectie.
 // Als alles goed gaat is dit de af tehandelen reeks instructies:
 $klantid = 1; // Moet natuurlijk het id van de ingelogde klant worden
 $datum="2020-12-01"; // Moet natuurlijk de huidige datum worden.
 $db->begin_transaction();
 $query1= "INSERT INTO `order`  ( klantid, datum ) VALUES ('$klantid','$datum')";
 $res=$db->query($query1); // er moet nu nog wel worden gecontroleerd of er iets fout gaat
 //pak de laatst gemaakte order in deze sessie
 $order_id = $db->insert_id;
 $query2= "INSERT INTO `order_product`  ( orderid, productid, aantal, prijs  ) VALUES ";
 $query2.="('$order_id','1', '6',(SELECT prijs FROM product WHERE id = '1')),";
 $query2.="('$order_id','2', '3',(SELECT prijs FROM product WHERE id = '2'))";
 $res=$db->query($query2); // er moet nu nog wel worden gecontroleerd of er iets fout gaat
 $db->commit();
 

Je moet natuurlijk onderweg wel alle queries controleren. Treedt er ergens een fout op dan moet de statement $db->rollback(); worden uitgevoerd..

Natuurlijk moet dit natuurlijk wel netjes in een functie terecht komen. Je zult dus iets moeten doen als het voorbeeld in PHP en MySQL: invoeren. $query2 moet worden opgebouwd uit de winkelmand op ongeveer de zelfde wijze als $conditie bij het tonen van de winkelmand. Het klantid moet na inloggen uit $_SESSION worden opgehaald. Tenslotte moet de datum de huidige datum worden.