Catàleg: diferència entre les revisions
Cap resum de modificació |
|||
| (Hi ha una revisió intermèdia que no es mostren del mateix usuari) | |||
| Línia 16: | Línia 16: | ||
Inicialment, la quantitat de productes és 0, però en cas que, desde la sessió es comprovi que hi ha productes, per cada producte revisarà la seva quantitat (es pot consultar [[Afegir productes al cistell des del catàleg#Exemple de model de dades|l'Exemple de model de dades de l'array <nowiki>$SESSION[cistell]</nowiki> amb productes]] per entendre el model de dades del cistell). | Inicialment, la quantitat de productes és 0, però en cas que, desde la sessió es comprovi que hi ha productes, per cada producte revisarà la seva quantitat (es pot consultar [[Afegir productes al cistell des del catàleg#Exemple de model de dades|l'Exemple de model de dades de l'array <nowiki>$SESSION[cistell]</nowiki> amb productes]] per entendre el model de dades del cistell). | ||
Un cop recuperi la quantitat del producte, sumarà aquesta quantitat al comptador. Això es realitzarà per cada producte, fins tenir la suma de totes les quantitats de tots els productes.<pre> | Un cop recuperi la quantitat del producte, sumarà aquesta quantitat al comptador. Això es realitzarà per cada producte, fins tenir la suma de totes les quantitats de tots els productes.<pre>// Comptador de productes al cistell | ||
// Comptador de productes al cistell | |||
$comptador = 0; // El comptador inicial és 0 | $comptador = 0; // El comptador inicial és 0 | ||
foreach ($_SESSION['cistell'] as $prod) { // Per cada producte | foreach ($_SESSION['cistell'] as $prod) { // Per cada producte | ||
| Línia 23: | Línia 22: | ||
$comptador = $comptador + (int)$prod['quantitat']; // Asignem que comptador és igual al comptador més la quantitat (convertida a int) | $comptador = $comptador + (int)$prod['quantitat']; // Asignem que comptador és igual al comptador més la quantitat (convertida a int) | ||
} | } | ||
} | }</pre> | ||
</pre> | |||
== Obtenció de productes amb i sense cerca == | == Obtenció de productes amb i sense cerca == | ||
| Línia 31: | Línia 29: | ||
Per tant, si es cerca per nom, ens arribarà el camp "nom" i aprovarà el següent condicional<pre> | Per tant, si es cerca per nom, ens arribarà el camp "nom" i aprovarà el següent condicional<pre> | ||
// Filtrar per nom | // Filtrar per nom | ||
if (!empty($_GET['nom'])) { // En cas que s'hagi rebut algun valor pel camp "nom" (i per tant fer una cerca per nom) | |||
$cerca = "nom"; // Definim que a la consulta SQL es filtrarà per nom | |||
$valor = "%" . $_GET['nom'] . "%"; // Afegim els % degut a que és sintaxis de les consultes SQL | |||
$sql = "SELECT * FROM productes WHERE $cerca LIKE :valor"; // Exemple: SELECT * FROM productes WHERE nom LIKE %pc% | |||
$stmt = $pdo->prepare($sql); | |||
$stmt->bindParam(':valor', $valor); | |||
$stmt->execute(); | |||
} | |||
</pre>En canvi, si ens arriba el camp "categoria", aprovarà el següent condicional<pre> | </pre>En canvi, si ens arriba el camp "categoria", aprovarà el següent condicional<pre> | ||
// Filtrar | // Filtrar per categoría | ||
} elseif (!empty($_GET['categoria'])) { // En cas que s'hagi rebut algun valor pel camp "categoria" (i per tant fer una cerca per categoria) | |||
$cerca = "categoria"; // Definim que a la consulta SQL es filtrarà per categoria | |||
$valor = "%" . $_GET['categoria'] . "%"; // Afegim els % degut a que és sintaxis de les consultes SQL | |||
$sql = "SELECT * FROM productes WHERE $cerca LIKE :valor"; // Exemple: SELECT * FROM productes WHERE categoria LIKE %periferic% | |||
$stmt = $pdo->prepare($sql); | |||
$stmt->bindParam(':valor', $valor); | |||
$stmt->execute(); | |||
</pre>Si pel contrari no arriba cap cerca (i per tant, volem obtenir tots els productes de la BD), s'aprovarà el següent condicional<pre> | </pre>Si pel contrari no arriba cap cerca (i per tant, volem obtenir tots els productes de la BD), s'aprovarà el següent condicional<pre>// En cas que no s'hagi enviat cap camp del formulari (no hi ha cap cerca) | ||
// En cas que no s'hagi enviat cap camp del formulari (no hi ha cap cerca) | } else { | ||
$sql = "SELECT * FROM productes"; // Consulta per defecte, tots els productes | |||
$stmt = $pdo->prepare($sql); | |||
$stmt->execute(); | |||
}</pre>Per últim, sigui quina sigui la consulta realitzada, la desarem a la variable $productes preparada per ser recorreguda per un foreach<pre> | |||
</pre>Per últim, sigui quina sigui la consulta realitzada, la desarem a la variable $productes preparada per ser recorreguda per un foreach<pre> | |||
$productes = $stmt->fetchAll(); | $productes = $stmt->fetchAll(); | ||
</pre> | </pre> | ||
| Línia 67: | Línia 64: | ||
</pre>Per tant, dins del catàleg hem de comprovar si hem rebut aquest missatge (ja sigui el d'error o èxit), i en cas afirmatiu, mostrar-lo. Just després de mostrar-lo l'eliminem, per que així únicament es mostri una sola vegada.<pre> | </pre>Per tant, dins del catàleg hem de comprovar si hem rebut aquest missatge (ja sigui el d'error o èxit), i en cas afirmatiu, mostrar-lo. Just després de mostrar-lo l'eliminem, per que així únicament es mostri una sola vegada.<pre> | ||
<!-- Missatge de confirmació d'accions --> | <!-- Missatge de confirmació d'accions --> | ||
<center> | |||
<?php if (isset($_SESSION['missatge_ok'])): // Quan s'enviï un missatge de confirmació ?> | |||
<p style="color: green; font-weight: bold;"> | |||
<?php | |||
echo htmlspecialchars($_SESSION['missatge_ok']); // Mostrem el missatge | |||
unset($_SESSION['missatge_ok']); // Eliminem el missatge, així al recarregar la pàgina no tornarà a sortir, únicament mostrant-se un sol cop | |||
?> | |||
</p> | |||
<?php endif; ?> | |||
</center> | |||
<!-- Missatge d'error --> | |||
<center> | |||
<?php if (isset($_SESSION['missatge_error'])): // Quan s'enviï un missatge d'error ?> | |||
<p style="color: red; font-weight: bold;"> | |||
<?php | |||
echo htmlspecialchars($_SESSION['missatge_error']); // Mostrem el missatge | |||
unset($_SESSION['missatge_error']); // Eliminem el missatge, així al recarregar la pàgina no tornarà a sortir, únicament mostrant-se un sol cop | |||
?> | |||
</p> | |||
<?php endif; ?> | |||
</center> | |||
</pre>Un exemple d'un missatge seria el següent: | </pre>Un exemple d'un missatge seria el següent: | ||
[[Fitxer:MissatgeExit.png|center|miniatura|345x345px]] | [[Fitxer:MissatgeExit.png|center|miniatura|345x345px]] | ||
| Línia 122: | Línia 119: | ||
Per això primer hem de saber si dins del cistell es troba el producte del que volem mostrar l'stock (mitjançant una cerca per ID de producte). En cas afirmatiu, desem a una variable la quantitat que hi ha dins del cistell<pre> | Per això primer hem de saber si dins del cistell es troba el producte del que volem mostrar l'stock (mitjançant una cerca per ID de producte). En cas afirmatiu, desem a una variable la quantitat que hi ha dins del cistell<pre> | ||
// Estoc reservat al cistell | // Estoc reservat al cistell | ||
$reservat = 0; | |||
if (isset($_SESSION['cistell'][$p['id']])) { // Dintre del cistell, comprova si algun dels productes té la mateixa ID que els productes retornats a la consulta SQL (comprova que el producte estigui al cistell) | |||
$reservat = (int)$_SESSION['cistell'][$p['id']]['quantitat']; // El reservat és, dins del cistell, la quantitat d'aquell producte | |||
} | |||
</pre>Un cop desada la quantitat d'aquell producte al cistell, restarem aquest nombre a l'stock de la BD, retornant el nombre d'unitats que podem afegir al cistell (una mena d'stock visible, per evitar haver d'anar retirant i afegint stock a la BD cada cop que es retira o s'afageix una unitat al cistell)<pre> | |||
$estoc_visible = $p['estoc'] - $reservat; // L'estoc visible (que no real) del producte és l'stock real menys al reservat | </pre>Un cop desada la quantitat d'aquell producte al cistell, restarem aquest nombre a l'stock de la BD, retornant el nombre d'unitats que podem afegir al cistell (una mena d'stock visible, per evitar haver d'anar retirant i afegint stock a la BD cada cop que es retira o s'afageix una unitat al cistell)<pre>$estoc_visible = $p['estoc'] - $reservat; // L'estoc visible (que no real) del producte és l'stock real menys al reservat | ||
// Així, si hi ha productes al cistell, els restem de l'stock, però no a la BD, ja que es possible que es retirin productes | // Així, si hi ha productes al cistell, els restem de l'stock, però no a la BD, ja que es possible que es retirin productes</pre>Uns punts clau per entedre aquesta gestió de l'stock són | ||
</pre>Uns punts clau per entedre aquesta gestió de l'stock són | |||
* L’stock visible és la quantitat de productes que l’usuari pot afegir al cistell. | * L’stock visible és la quantitat de productes que l’usuari pot afegir al cistell. | ||
| Línia 147: | Línia 143: | ||
</pre>Primer el càlcul de l'stock visible<pre> | </pre>Primer el càlcul de l'stock visible<pre> | ||
<?php | <?php | ||
// Estoc reservat al cistell | |||
$reservat = 0; | |||
if (isset($_SESSION['cistell'][$p['id']])) { // Dintre del cistell, comprova si algun dels productes té la mateixa ID que els productes retornats a la consulta SQL (comprova que el producte estigui al cistell) | |||
$reservat = (int)$_SESSION['cistell'][$p['id']]['quantitat']; // El reservat és, dins del cistell, la quantitat d'aquell producte | |||
} | |||
$estoc_visible = $p['estoc'] - $reservat; // L'estoc visible (que no real) del producte és l'stock real menys al reservat | |||
// Així, si hi ha productes al cistell, els restem de l'stock, però no a la BD, ja que es possible que es retirin productes | |||
?> | ?> | ||
</pre>Seguidament, la mostra de les característiques del producte (la imatge, el nom, la categoria, el preu, etc)<pre> | </pre>Seguidament, la mostra de les característiques del producte (la imatge, el nom, la categoria, el preu, etc)<pre> | ||
<!-- Mostrem la imatge --> | <!-- Mostrem la imatge --> | ||
<div class="product-image"> | |||
<img src="imatges/<?php echo htmlspecialchars($p['imatge']); ?>" | |||
alt="<?php echo htmlspecialchars($p['nom']); ?>"> | |||
</div> | |||
<!-- Mostrem el nom --> | |||
<h3><?php echo htmlspecialchars($p['nom']); ?></h3> | |||
<!-- Mostrem la categoria --> | |||
<p><strong>Categoria:</strong> <?php echo htmlspecialchars($p['categoria']); ?></p> | |||
<!-- Mostrem la descripció --> | |||
<p><?php echo htmlspecialchars($p['descripcio']); ?></p> | |||
<!-- Mostrem el preu --> | |||
<p>Preu: <?php echo number_format($p['preu'], 2); ?> €</p> | |||
</pre>Finalment, en cas de que l'stock visible (BD - Cistell) sigui 0, mostrarem un text indicant que no hi ha stock. En cas que si que n'hi hagi, mostrarem, definirem una entrada numèrica on l'usuari podrà indicar quin nombre d'unitats d'aquell producte vol afegir al cistell. | </pre>Finalment, en cas de que l'stock visible (BD - Cistell) sigui 0, mostrarem un text indicant que no hi ha stock. En cas que si que n'hi hagi, mostrarem, definirem una entrada numèrica on l'usuari podrà indicar quin nombre d'unitats d'aquell producte vol afegir al cistell. | ||
| Línia 180: | Línia 177: | ||
El botó per afegir un producte al cistell crida al codi processa.php definint el valor “afegir” a la variable “acció”, a més de passar la ID del producte i la quantitat<pre> | El botó per afegir un producte al cistell crida al codi processa.php definint el valor “afegir” a la variable “acció”, a més de passar la ID del producte i la quantitat<pre> | ||
<!-- Mostrem l'stock visible (stock de la BD menys el que hi ha el cistell) --> | <!-- Mostrem l'stock visible (stock de la BD menys el que hi ha el cistell) --> | ||
<p>Estoc disponible: <?php echo $estoc_visible; ?></p> | |||
<!-- Si l'stock visible es major a 0 (és a dir, l'stock a la BD, restant el que hi ha al cistell) --> | |||
<?php if ($estoc_visible > 0): ?> | |||
<!-- Mostrem el formulari per afegir al cistell --> | |||
<form action="processa.php?accio=afegir" method="post"> <!-- Acció és a proccessa.php definint la variable "accio" com "afegir" --> | |||
<input type="hidden" name="id" value="<?php echo (int)$p['id']; ?>"> <!-- Afegim un camp ocult el qual és per enviar la ID del producte (el client no ho ha de veure, ha de ser comunicació interna) --> | |||
<label> | |||
<!-- Definim la quantitat que podem afegir al cistell amb una sola operació --> | |||
Quantitat: | |||
<input type="number" | |||
name="quantitat" | |||
value="1" | |||
min="1" | |||
max="<?php echo $estoc_visible; ?>"> <!-- El nombre màxim d'unitats que es poden afegir al cistell és l'stock visible, per evitar afegir més productes dels possibles --> | |||
</label> | |||
<input type="submit" value="Afegeix al cistell"> | |||
</form> | |||
<?php else: ?> <!-- En cas que l'stock visible sigui igual a zero, mostrarem producte esgotat, sense la possibilitat d'agefir al cistell --> | |||
<p><strong>Producte esgotat</strong></p> | |||
<?php endif; ?> | |||
</pre>Tot aquest procés es realitza per cada producte | </pre>Tot aquest procés es realitza per cada producte | ||
Revisió de 01:53, 12 gen 2026
Inicialització de la sessió i connexió a la BD
Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML
session_start();
A partir d'aquí, l'element principal d'aquesta aplicació és el cistell, el qual està present a la sessió i requerit per la majoria de codis. Per això, hem de comprovar que estigui creat, i en cas que no ho estigui, que es creï.
// Inicialitzar cistell if (!isset($_SESSION['cistell']) || !is_array($_SESSION['cistell'])) { // Si el cistell no està inicialitzat o no és una array
$_SESSION['cistell'] = array();}
A més, hem de requerir una connexió a la BD. En aquest cas, dins del catàleg únicament mostrarem els productes i no farem cap modificació a la BD, per tant farem servir la connexió de lectura.
require_once "./connexioBD/connexioR.php";
Comptador del cistell
Dins de l'aplicació, hi ha un botó en forma de cistell que mostra la quantitat d'unitats de tots els productes es troba dins del cistell

Inicialment, la quantitat de productes és 0, però en cas que, desde la sessió es comprovi que hi ha productes, per cada producte revisarà la seva quantitat (es pot consultar l'Exemple de model de dades de l'array $SESSION[cistell] amb productes per entendre el model de dades del cistell).
Un cop recuperi la quantitat del producte, sumarà aquesta quantitat al comptador. Això es realitzarà per cada producte, fins tenir la suma de totes les quantitats de tots els productes.
// Comptador de productes al cistell
$comptador = 0; // El comptador inicial és 0
foreach ($_SESSION['cistell'] as $prod) { // Per cada producte
if (is_array($prod) && isset($prod['quantitat'])) { // Ens assegurem que el producte és una array i que el vector "quantitat" existeix
$comptador = $comptador + (int)$prod['quantitat']; // Asignem que comptador és igual al comptador més la quantitat (convertida a int)
}
}
Obtenció de productes amb i sense cerca
El següent pas serà fer una consulta SQL per recuperar els productes de la BD. En cas que s’hagi realitzat una cerca, ho sabrem ja que s’ha enviat un formulari GET amb el camp “nom” o el camp “categoria”
Per tant, si es cerca per nom, ens arribarà el camp "nom" i aprovarà el següent condicional
// Filtrar per nom
if (!empty($_GET['nom'])) { // En cas que s'hagi rebut algun valor pel camp "nom" (i per tant fer una cerca per nom)
$cerca = "nom"; // Definim que a la consulta SQL es filtrarà per nom
$valor = "%" . $_GET['nom'] . "%"; // Afegim els % degut a que és sintaxis de les consultes SQL
$sql = "SELECT * FROM productes WHERE $cerca LIKE :valor"; // Exemple: SELECT * FROM productes WHERE nom LIKE %pc%
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':valor', $valor);
$stmt->execute();
}
En canvi, si ens arriba el camp "categoria", aprovarà el següent condicional
// Filtrar per categoría } elseif (!empty($_GET['categoria'])) { // En cas que s'hagi rebut algun valor pel camp "categoria" (i per tant fer una cerca per categoria)
$cerca = "categoria"; // Definim que a la consulta SQL es filtrarà per categoria $valor = "%" . $_GET['categoria'] . "%"; // Afegim els % degut a que és sintaxis de les consultes SQL $sql = "SELECT * FROM productes WHERE $cerca LIKE :valor"; // Exemple: SELECT * FROM productes WHERE categoria LIKE %periferic% $stmt = $pdo->prepare($sql); $stmt->bindParam(':valor', $valor); $stmt->execute();
Si pel contrari no arriba cap cerca (i per tant, volem obtenir tots els productes de la BD), s'aprovarà el següent condicional
// En cas que no s'hagi enviat cap camp del formulari (no hi ha cap cerca)} else {
$sql = "SELECT * FROM productes"; // Consulta per defecte, tots els productes $stmt = $pdo->prepare($sql); $stmt->execute();}
Per últim, sigui quina sigui la consulta realitzada, la desarem a la variable $productes preparada per ser recorreguda per un foreach
$productes = $stmt->fetchAll();
Mostra de missatges d'error o èxit
Quan s'afageix un producte al cistell, el procés el realitza el codi processa.php, que depenent del resultat de l'operació, ens pot enviar un missatge d'èxit o d'error mitjançant la sessió
// Si processa.php realitza correctament l'operació, catàleg.php veuria el següent:
$_SESSION['missatge_ok'] = "S'ha afegit $quantitat {$producte['nom']} al cistell.";
// Si processa.php no realitza correctament l'operació, catàleg.php veuria el següent:
$_SESSION['missatge_error'] = "X" // Depenent de l'error es mostrarà un missatge o un altre
Per tant, dins del catàleg hem de comprovar si hem rebut aquest missatge (ja sigui el d'error o èxit), i en cas afirmatiu, mostrar-lo. Just després de mostrar-lo l'eliminem, per que així únicament es mostri una sola vegada.
<!-- Missatge de confirmació d'accions --> <center>
<?php if (isset($_SESSION['missatge_ok'])): // Quan s'enviï un missatge de confirmació ?> <p style="color: green; font-weight: bold;"> <?php echo htmlspecialchars($_SESSION['missatge_ok']); // Mostrem el missatge unset($_SESSION['missatge_ok']); // Eliminem el missatge, així al recarregar la pàgina no tornarà a sortir, únicament mostrant-se un sol cop ?> </p> <?php endif; ?></center>
<!-- Missatge d'error --> <center>
<?php if (isset($_SESSION['missatge_error'])): // Quan s'enviï un missatge d'error ?> <p style="color: red; font-weight: bold;"> <?php echo htmlspecialchars($_SESSION['missatge_error']); // Mostrem el missatge unset($_SESSION['missatge_error']); // Eliminem el missatge, així al recarregar la pàgina no tornarà a sortir, únicament mostrant-se un sol cop ?> </p> <?php endif; ?></center>
Un exemple d'un missatge seria el següent:

Botons de navegació i formulari de cerca
Navegació a la gestió del catàleg
A la part superior esquerra, es troba un botó que permet accedir als usuaris autoritzats a una secció de l'aplicació que permet realitzar tasques de gestió del catàleg.

Navegació al cistell
A la part superior dreta es troba un botó que permet accedir al cistell per comprar els productes. Aquest botó també mostra el valor de la variable $comptador, que representa la quantitat d'unitats individuals dels productes que hi ha al cistell.

Formulari de cerca
Per últim trobem un formulari de cerca que ens permet filtrar els productes per nom o categoria, amb un botó per realitzar la cerca i un altre per esborrar anteriors resultats.

Mostra de productes i gestió de l'stock
Gestió de l'stock segons unitats al cistell i a la BD
Abans de documentar la mostra de productes, definirem com gestionar la visualització de l’estoc.
Suposem que a la base de dades tenim 10 unitats en estoc i afegim 2 productes al cistell:
- A la base de dades encara apareixen 10 unitats, perquè la compra no s’ha completat.
- Tot i així, només queden 8 unitats disponibles per afegir al cistell, ja que 2 ja estan “reservades” dins del cistell.
Si només ens guiéssim per l’stock de la base de dades, podríem continuar afegint productes al cistell de manera indefinida fins a l’hora de la compra, cosa que generaria un problema si l’estoc real ja no és suficient.
És per això que hem de definir un “stock visible”, per evitar que els usuaris afegeixin mes productes dels possibles al cistell, però sense tocar la BD, en cas que es buidi el cistell.
Per això primer hem de saber si dins del cistell es troba el producte del que volem mostrar l'stock (mitjançant una cerca per ID de producte). En cas afirmatiu, desem a una variable la quantitat que hi ha dins del cistell
// Estoc reservat al cistell
$reservat = 0;
if (isset($_SESSION['cistell'][$p['id']])) { // Dintre del cistell, comprova si algun dels productes té la mateixa ID que els productes retornats a la consulta SQL (comprova que el producte estigui al cistell)
$reservat = (int)$_SESSION['cistell'][$p['id']]['quantitat']; // El reservat és, dins del cistell, la quantitat d'aquell producte
}
Un cop desada la quantitat d'aquell producte al cistell, restarem aquest nombre a l'stock de la BD, retornant el nombre d'unitats que podem afegir al cistell (una mena d'stock visible, per evitar haver d'anar retirant i afegint stock a la BD cada cop que es retira o s'afageix una unitat al cistell)
$estoc_visible = $p['estoc'] - $reservat; // L'estoc visible (que no real) del producte és l'stock real menys al reservat // Així, si hi ha productes al cistell, els restem de l'stock, però no a la BD, ja que es possible que es retirin productes
Uns punts clau per entedre aquesta gestió de l'stock són
- L’stock visible és la quantitat de productes que l’usuari pot afegir al cistell.
- L’stock de la BD es resta segons els productes del cistell. En el moment de fer la compra final, aquesta resta es fa a la BD en sí i s’actualitza l’stock
- Exemples
- Si hi ha 10 a la BD i 0 al cistell: Stock visible = 10
- Si hi ha 10 a la BD i 5 al cistell: Stock visible = 5
- Si hi ha 10 a la BD i 8 al cistell stock visible = 2
Mostra de productes
Un cop definit el procés de gestió de l'stock, podem definir com es mostren els productes.
A partir de la variables $productes, la qual incorpora el resultat de la consulta SQL segons hi hagi o no hagut una cerca prèvia, mostrarem els productes.
Mitjançant un foreach per cada producte mostrarem tots els detalls del producte
<?php foreach ($productes as $p): ?>
Primer el càlcul de l'stock visible
<?php // Estoc reservat al cistell $reservat = 0; if (isset($_SESSION['cistell'][$p['id']])) { // Dintre del cistell, comprova si algun dels productes té la mateixa ID que els productes retornats a la consulta SQL (comprova que el producte estigui al cistell)
$reservat = (int)$_SESSION['cistell'][$p['id']]['quantitat']; // El reservat és, dins del cistell, la quantitat d'aquell producte}
$estoc_visible = $p['estoc'] - $reservat; // L'estoc visible (que no real) del producte és l'stock real menys al reservat // Així, si hi ha productes al cistell, els restem de l'stock, però no a la BD, ja que es possible que es retirin productes ?>
Seguidament, la mostra de les característiques del producte (la imatge, el nom, la categoria, el preu, etc)
<!-- Mostrem la imatge --> <div class="product-image">
<img src="imatges/<?php echo htmlspecialchars($p['imatge']); ?>" alt="<?php echo htmlspecialchars($p['nom']); ?>"></div>
<!-- Mostrem el nom --> <h3><?php echo htmlspecialchars($p['nom']); ?></h3>
<!-- Mostrem la categoria --> <p><strong>Categoria:</strong> <?php echo htmlspecialchars($p['categoria']); ?></p>
<!-- Mostrem la descripció --> <p><?php echo htmlspecialchars($p['descripcio']); ?></p>
<!-- Mostrem el preu --> <p>Preu: <?php echo number_format($p['preu'], 2); ?> €</p>
Finalment, en cas de que l'stock visible (BD - Cistell) sigui 0, mostrarem un text indicant que no hi ha stock. En cas que si que n'hi hagi, mostrarem, definirem una entrada numèrica on l'usuari podrà indicar quin nombre d'unitats d'aquell producte vol afegir al cistell.
La entrada numèrica tindrà com a màxim l'stock visible (Stock BD = 10; Cistell = 2; Stock visible = 8 i per tant únicament podrà afegir 8 unitats més al cistell)
El botó per afegir un producte al cistell crida al codi processa.php definint el valor “afegir” a la variable “acció”, a més de passar la ID del producte i la quantitat
<!-- Mostrem l'stock visible (stock de la BD menys el que hi ha el cistell) -->
<p>Estoc disponible: <?php echo $estoc_visible; ?></p>
<!-- Si l'stock visible es major a 0 (és a dir, l'stock a la BD, restant el que hi ha al cistell) -->
<?php if ($estoc_visible > 0): ?>
<!-- Mostrem el formulari per afegir al cistell -->
<form action="processa.php?accio=afegir" method="post"> <!-- Acció és a proccessa.php definint la variable "accio" com "afegir" -->
<input type="hidden" name="id" value="<?php echo (int)$p['id']; ?>"> <!-- Afegim un camp ocult el qual és per enviar la ID del producte (el client no ho ha de veure, ha de ser comunicació interna) -->
<label>
<!-- Definim la quantitat que podem afegir al cistell amb una sola operació -->
Quantitat:
<input type="number"
name="quantitat"
value="1"
min="1"
max="<?php echo $estoc_visible; ?>"> <!-- El nombre màxim d'unitats que es poden afegir al cistell és l'stock visible, per evitar afegir més productes dels possibles -->
</label>
<input type="submit" value="Afegeix al cistell">
</form>
<?php else: ?> <!-- En cas que l'stock visible sigui igual a zero, mostrarem producte esgotat, sense la possibilitat d'agefir al cistell -->
<p><strong>Producte esgotat</strong></p>
<?php endif; ?>
Tot aquest procés es realitza per cada producte
Un exemple de com es veuria un producte seria el següent

Fluxe de l'aplicació
Si és la primera vegada que s'entra a l'aplicació, el flux serà el següent:
- Es crea el cistell
- Comptador del cistell mostra 0 unitats
- Obtenció de productes sense cerca
- Mostra de productes (amb l'stock de tots els productes obtinguts de la BD)
- S'afageix un producte amb X unitats al cistell
- Es redirigeix al catàleg
Si s'entra al catàleg després d'afegir un producte al cistell, el flux serà el següent:
- Comptador del cistell mostra X unitats (les afegides)
- Obtenció de productes sense cerca
- Mostra del missatge d'èxit
- Mostra de productes (amb l'stock real calculat d'aquell producte afegit, no obtingut de la BD)
Codi complet
<?php
// Iniciem la sessió i requerim la connexió a la BD
session_start();
require_once "./connexioBD/connexioR.php";
// Inicialitzar cistell
if (!isset($_SESSION['cistell']) || !is_array($_SESSION['cistell'])) { // Si el cistell no està inicialitzat o no és una array
$_SESSION['cistell'] = array();
}
// Comptador de productes al cistell
$comptador = 0; // El comptador inicial és 0
foreach ($_SESSION['cistell'] as $prod) { // Per cada producte
if (is_array($prod) && isset($prod['quantitat'])) { // Ens assegurem que el producte és una array i que el vector "quantitat" existeix
$comptador = $comptador + (int)$prod['quantitat']; // Asignem que comptador és igual al comptador més la quantitat (convertida a int)
}
}
try {
// Filtrar per nom
if (!empty($_GET['nom'])) { // En cas que s'hagi rebut algun valor pel camp "nom" (i per tant fer una cerca per nom)
$cerca = "nom"; // Definim que a la consulta SQL es filtrarà per nom
$valor = "%" . $_GET['nom'] . "%"; // Afegim els % degut a que és sintaxis de les consultes SQL
$sql = "SELECT * FROM productes WHERE $cerca LIKE :valor"; // Exemple: SELECT * FROM productes WHERE nom LIKE %pc%
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':valor', $valor);
$stmt->execute();
// Filtrar por categoría
} elseif (!empty($_GET['categoria'])) { // En cas que s'hagi rebut algun valor pel camp "categoria" (i per tant fer una cerca per categoria)
$cerca = "categoria"; // Definim que a la consulta SQL es filtrarà per categoria
$valor = "%" . $_GET['categoria'] . "%"; // Afegim els % degut a que és sintaxis de les consultes SQL
$sql = "SELECT * FROM productes WHERE $cerca LIKE :valor"; // Exemple: SELECT * FROM productes WHERE categoria LIKE %periferic%
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':valor', $valor);
$stmt->execute();
// En cas que no s'hagi enviat cap camp del formulari (no hi ha cap cerca)
} else {
$sql = "SELECT * FROM productes"; // Consulta per defecte, tots els productes
$stmt = $pdo->prepare($sql);
$stmt->execute();
}
$productes = $stmt->fetchAll();
} catch (PDOException $e) {
die("Error BD: " . htmlspecialchars($e->getMessage()));
}
?>
<!-- Inici HTML -->
<!DOCTYPE html>
<html lang="ca">
<head>
<meta charset="UTF-8">
<title>Catàleg de Productes</title>
<link rel="stylesheet" href="./css/stylesCataleg.css"> <!-- Definim el full d'estils -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" integrity="sha512-..." crossorigin="anonymous" referrerpolicy="no-referrer" /> <!-- Referència d'icones -->
</head>
<body>
<!-- Botó per anar al cistell -->
<p>
<a href="cistell.php" class="cart-button">
<i class="fas fa-shopping-cart"></i>
<span class="cart-count"><?php echo $comptador; ?></span>
</a>
</p>
<!-- Botó administració del catàleg -->
<a href="./administracioCataleg/administracioCataleg.php" class="admin-link">
Administració del catàleg
</a>
<h1>Catàleg de Productes</h1>
<!-- Formulari de cerca -->
<form method="get" action="cataleg.php">
<fieldset>
<legend>Cerca de productes</legend>
<label>
Nom:
<input type="text" name="nom"
value="<?php // En cas de tenir un valor del formulari (refresquem la pàgina amb el formulari enviat)
if (isset($_GET['nom'])) { // El camp tindrà ja definida la cerca especificada anteriorment
echo htmlspecialchars($_GET['nom']);
} else { // En cas contrari, estarà buit
echo '';
}?>">
</label>
<label>
Categoria:
<input type="text" name="categoria"
value="<?php // En cas de tenir un valor del formulari (refresquem la pàgina amb el formulari enviat)
if (isset($_GET['categoria'])) { # El camp tindrà ja definida la cerca especificada anteriorment
echo htmlspecialchars($_GET['categoria']);
} else { // En cas contrari, estarà buit
echo '';
}?>">
</label>
<input type="submit" value="Cerca">
<a href="cataleg.php">
<button type="button">Esborrar cerca</button>
</a>
</fieldset>
</form>
<!-- Missatge de confirmació d'accions -->
<center>
<?php if (isset($_SESSION['missatge_ok'])): // Quan s'enviï un missatge de confirmació?>
<p style="color: green; font-weight: bold;">
<?php
echo htmlspecialchars($_SESSION['missatge_ok']); // Mostrem el missatge
unset($_SESSION['missatge_ok']); // Eliminem el missatge, així al recarregar la pàgina no tornarà a sortir, únicament mostrant-se un sol cop
?>
</p>
<?php endif; ?>
</center>
<!-- Missatge d'error -->
<center>
<?php if (isset($_SESSION['missatge_error'])): // Quan s'enviï un missatge d'error?>
<p style="color: red; font-weight: bold;">
<?php
echo htmlspecialchars($_SESSION['missatge_error']); // Mostrem el missatge
unset($_SESSION['missatge_error']); // Eliminem el missatge, així al recarregar la pàgina no tornarà a sortir, únicament mostrant-se un sol cop
?>
</p>
<?php endif; ?>
</center>
<!-- Mostra de productes -->
<!-- En cas que la consulta realitzada anteriorment no tingui resultats (generalment per una cerca no correcte)-->
<?php if (empty($productes)): ?>
<p>No s’han trobat productes.</p>
<?php endif; ?>
<!-- En cas que la consulta realitzada anteriorment hagi obtingut resultats -->
<div class="catalog">
<?php foreach ($productes as $p): ?> <!-- Per cada producte obtingut a la consulta -->
<?php
// Estoc reservat al cistell
$reservat = 0;
if (isset($_SESSION['cistell'][$p['id']])) { // Dintre del cistell, comprova si algun dels productes té la mateixa ID que els productes retornats a la consulta SQL (comprova que el producte estigui al cistell)
$reservat = (int)$_SESSION['cistell'][$p['id']]['quantitat']; // El reservat és, dins del cistell, la quantitat d'aquell producte
}
$estoc_visible = $p['estoc'] - $reservat; // L'estoc visible (que no real) del producte és l'stock real menys al reservat
// Així, si hi ha productes al cistell, els restem de l'stock, però no a la BD, ja que es possible que es retirin productes
?>
<div class="product-card">
<!-- Mostrem la imatge -->
<div class="product-image">
<img src="imatges/<?php echo htmlspecialchars($p['imatge']); ?>"
alt="<?php echo htmlspecialchars($p['nom']); ?>">
</div>
<!-- Mostrem el nom -->
<h3><?php echo htmlspecialchars($p['nom']); ?></h3>
<!-- Mostrem la categoria -->
<p><strong>Categoria:</strong> <?php echo htmlspecialchars($p['categoria']); ?></p>
<!-- Mostrem la descripció -->
<p><?php echo htmlspecialchars($p['descripcio']); ?></p>
<!-- Mostrem el preu -->
<p>Preu: <?php echo number_format($p['preu'], 2); ?> €</p>
<!-- Mostrem l'stock visible (stock de la BD menys el que hi ha el cistell) -->
<p>Estoc disponible: <?php echo $estoc_visible; ?></p>
<!-- Si l'stock visible es major a 0 (és a dir, l'stock a la BD, restant el que hi ha al cistell) -->
<?php if ($estoc_visible > 0): ?>
<!-- Mostrem el formulari per afegir al cistell -->
<form action="processa.php?accio=afegir" method="post"> <!-- Acció és a proccessa.php definint la variable "accio" com "afegir" -->
<input type="hidden" name="id" value="<?php echo (int)$p['id']; ?>"> <!-- Afegim un camp ocult el qual és per enviar la ID del producte (el client no ho ha de veure, ha de ser comunicació interna) -->
<label>
<!-- Definim la quantitat que podem afegir al cistell amb una sola operació -->
Quantitat:
<input type="number"
name="quantitat"
value="1"
min="1"
max="<?php echo $estoc_visible; ?>"> <!-- El nombre màxim d'unitats que es poden afegir al cistell és l'stock visible, per evitar afegir més productes dels possibles -->
</label>
<input type="submit" value="Afegeix al cistell">
</form>
<?php else: ?> <!-- En cas que l'stock visible sigui igual a zero, mostrarem producte esgotat, sense la possibilitat d'agefir al cistell -->
<p><strong>Producte esgotat</strong></p>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</body>
</html>