Reprendre le site statique de pizzeria et le rendre dynamique avec des concepts de PHP procédural (inclusions de pages).
.
└── pizza-website-php/
├── assets/
│ ├── css
│ ├── doc
│ ├── images
│ └── pdf
├── config/
│ └── parameters.php
├── data/
│ └── db.sql
├── src/
│ ├── action/
│ │ ├── add_cart.php
│ │ ├── check_email_exists.php
│ │ ├── confirm_cart.php
│ │ ├── login.php
│ │ ├── remove_cart.php
│ │ ├── send_contact_mail.php
│ │ ├── send_reset_link_password.php
│ │ ├── update_password.php
│ │ └── update_status_order.php
│ ├── model/
│ │ ├── order.php
│ │ ├── product.php
│ │ ├── user.php
│ │ └── database.php
│ ├── service/
│ │ ├── auth.php
│ │ ├── cart.php
│ │ ├── csrf.php
│ │ ├── debug.php
│ │ ├── flashMessage.php
│ │ ├── mailer.php
│ │ ├── order.php
│ │ └── validation.php
│ └── template/
│ ├── section/
│ │ ├── account.php
│ │ ├── cart_item.php
│ │ ├── form_checkout.php
│ │ ├── form_contact.php
│ │ ├── form_forgot_password.php
│ │ ├── form_login.php
│ │ ├── form_reset_password.php
│ │ ├── map.php
│ │ ├── product_type.php
│ │ ├── product.php
│ │ ├── service.html
│ │ └── table_orders.php
│ └── shared/
│ ├── banner.php
│ ├── button_cart.php
│ ├── button_shopping_cart.php
│ ├── button_whatsapp.php
│ ├── footer.php
│ ├── head.php
│ └── menu.php
├── bootstrap.php
├── carte.php
├── checkout.php
├── confirmation.php
├── forgot_password.php
├── index.php
├── login.php
├── maintenance.php
├── profile.php
├── reset_password.php
└── shopping_cart.php
-
[assets] : Ressources web statiques comme les fichiers CSS, javaScript et images
-
[config] : Fichiers utiles à la configuration du projet
-
[src/includes] : Les portions de pages séparé en 2 catégories.
- [shared] Commune à toute les pages
- [section] Portions de page plus spécifique
-
[src] : Traitement métiers appélé par les actions et portions de page
- [action] : fonction d'action utilisateurs (formulaires)
- [model] : fonction communiquant avec la base de donnnée
- [service] : fonction de traitement spécifique
- [template] : sous gabarits de page inclus depuis les pages
-
[data] : Base de données SQL
-
boostrap.php : Fichier de chargement de toutes les dépendances nécéssaires à l'éxécution du site.
-
carte.php : Page affichant la liste des produits et type de produits
-
checkout.php : Page de validation du panier
-
confirmation.php : Page de confirmation une fois le panier validé
-
forgot_password.php : Page de saisie lors de l'oubli du mot
-
index.php : Page d'acceuil
-
login.php : Page de connexion
-
maintenance.php : Page de maintenance
-
profile.php : Page de profil et de commande réservé aux utilisateurs authentifiés
-
reset_password: Page de saisie du nouveau mot de passe.
-
shopping_cart.php : Page d'affichage du panier
- Une page PHP peut inclure une autre page ou un morceau de page grâce à l'instruction include qui sera remplacée par le contenu de la page demandée. Cette technique permet de placer une portion du site dans un fichier (Ex: shared/header.php) que l'on inclura dans toutes les pages. Cela permet de centraliser le code du header et permettra aussi une maintenance plus efficace.
<head>
<?php include 'src/includes/shared/head.php'; ?>
</head>
Documentation :
- Faire appel à un fichier de configuration pour des paramètres qui changent peu ou pas (Ex: Accès à la base de données)
Il est donc possible de stocker ces données dans des constantes.
La portée d'une constante est globale. Les constantes peuvent être accédé depuis partout dans un script sans tenir compte de la portée.
define("DATABASE_USER", "root");
define("DATABASE_PASSWORD", "");
define("DATABASE_URL","mysql:host=127.0.0.1:3306;dbname=pizza_website");
$connexion = new PDO(DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD,
[PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"]);
Documentation :
- La portee d'une variable dépend du contexte dans lequel la variable est définie.
La variable définie dans une fonction est locale à la fonction.
Les variables ci dessus sont locales:
- $fullname
- $message
- $header
function sendEmail(string $firstname, string $lastname, string $email, string $phone, string $message) : bool
{
include '../../config/parameters.php';
$fullname = $firstname. ' '. $lastname;
$message = filter_var($message, FILTER_SANITIZE_STRING);
$fullname = filter_var($fullname, FILTER_SANITIZE_STRING);
$header = "MIME-Version: 1.0\r\n";
$header .= 'From:'.$fullname.'<'.$email.'>' . "\n";
$header .= 'Content-Type:text/html; charset="utf-8"' . "\n";
$header .= 'Content-Transfer-Encoding: 8bit';
if (mail(CONTACT_EMAIL, "Contact - pizzabilly.com", $message, $header)) {
return true;
} else {
return false;
}
}
- Toute variable définie en dehors d’une fonction a une portée globale. Une variable qui a une portée globale est accessible « globalement », c’est-à-dire dans tout le script sauf dans les espaces locaux d’un script.
Les variables ci dessus sont globales:
- $message
- $connexion
$connexion = null;
$message = '';
if (MAINTENANCE_MODE) {
header('Location:maintenance.php');
}
try {
$connexion = new PDO(DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD,
[PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"]);
- En PHP, une variable globale doit être déclarée à l'intérieur de chaque fonction afin de pouvoir être utilisée dans cette fonction.
function getProductTypes() : array
{
global $connexion;
$statement = $connexion->prepare('SELECT * FROM product_type');
Documentation:
<?php
$productTypes = getProductTypes();
foreach($productTypes as $productType) {
$linkProductType = 'carte.php?product-type-id='. $productType['id']; ?>
<li><a class="black-button <?php if ($_GET['product-type-id'] === $productType['id']) echo 'active'; ?>" href="<?= $linkProductType ?>"><?= $productType['type'] ?></a></li>
<?php } ?>
Documentation:
<?php
if ($currentPage === 'contact') { ?>
class="active"
<?php } ?>>La carte</a></li>
<?php
if (isset($_GET['product_id']) && !empty($_GET['product_id'])) {
unset($_SESSION['cart_item'][$_GET['product_id']]);
} else {
unset($_SESSION['cart_item']);
}
switch ($_POST['status']) {
case PAYMENT_STATUS_CANCELLED:
setFlash('status_order', 'La commande a bien été annulée', 'alert-success');
break;
case PAYMENT_STATUS_PAID:
setFlash('status_order', 'La commande a bien été payé', 'alert-success');
break;
}
Documentation:
function isValidForm(array $postDatas) : bool
{
if (empty($postDatas)) {
return false;
}
foreach ($postDatas as $key => $value) {
if (empty($value)) {
return false;
}
}
return true;
}
$isValid = isValidForm($_POST);
Documentation:
- Les fonctions définies par l'utilisateur
- Les arguments de fonction
- Les valeurs de retour
- Fonction interne
$connexion = new PDO(DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD]);
Documentation:
- Connexions et gestionnaire de connexion
- Objet PDO qui représente une connexion à la base
- Classe représentant une connexion PHP à un serveur de base de données
function getOrderItems(int $id)
{
global $connexion;
$sql = "SELECT o.id, o.ordered_at, pt.type, p.name, p.price, ot.quantity, (p.price * ot.quantity) as total
FROM `order` o
INNER JOIN order_item ot ON ot.order_id = o.id
INNER JOIN product p ON p.id = ot.product_id
INNER JOIN product_type pt ON pt.id = p.product_type_id
WHERE o.id = :order_id";
$statement = $connexion->prepare($sql);
$statement->bindParam(':order_id', $id);
$statement->setFetchMode(PDO::FETCH_ASSOC);
$statement->execute();
return $statement->fetchAll();
}
Documentation:
- Prépare une requête à l'exécution et retourne un objet
- Classe représentant une requête préparée
- Lie un paramètre à un nom de variable spécifique
- Exécute une requête préparée
- Retourne un tableau contenant toutes les lignes
- Mode de récupération pour les requêtes
- Constantes PDO
try {
$connexion = new PDO(DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD);
// Configure un attribut de base de données => PDO::ERRMODE_EXCEPTION :
// émet une exception.
$connexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $exception) {
$message = $exception->getMessage();
sendNotification('Connexion Error', $message);
header('Location:maintenance.php');
}
Documentation:
<?php
$linkProductType = 'carte.php?product-type-id='. $productType['id'];
?>
<p><?= getProductTypeDescription($_GET['product-type-id']); ?></p>
Documentation:
<form name="contact-form" method="POST" action="src/scripts/send_email.php">
$isValid = isValidForm($_POST);
if ($isValid) {
function isValidForm(array $postDatas) : bool
{
if (empty($postDatas)) {
return false;
}
foreach ($postDatas as $key => $value) {
if (empty($value)) {
return false;
}
}
return true;
}
$_SESSION['cart_item'][$product['id']]['quantity'] = (int)$_POST['quantity'];
$_SESSION['cart_item'][$product['id']]['name'] = $product['name'];
$_SESSION['cart_item'][$product['id']]['product_type_id'] = $product['product_type_id'];
$_SESSION['cart_item'][$product['id']]['price'] = (int)$product['price'];
Documentation:
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
return true;
} else {
return false;
}
Documentation:
if (!isset($_SESSION['auth']['logged'])) {
$data = array_merge($_POST, $_SESSION);
$data['password'] = hashPassword($data['password']);
$userId = createUser($data);
} else {
$user = getUserBy('email', $_POST['email']);
$data = array_merge($user, $_SESSION);
$userId = $user['id'];
}
Documentation:
- $_POST : Un tableau associatif des valeurs passées au script courant via le protocole HTTP
- $_SESSION : Un tableau associatif des valeurs stockées dans les sessions.
- Fusionner des tableaux
function computeTotalOrder(array $cartItem) : float
{
return array_sum(array_column($cartItem, 'total'));
}
Documentation:
$statOrder['total'] = count($orders);
$statOrder['status'] = array_count_values(array_column($orders, 'status'));
Documentation:
- Compte le nombre de valeur d'un tableau
- Compte tous les éléments d'un tableau ou quelque chose d'un objet
$orderedAt = (new DateTime())->format('Y-m-d H:i:s');
Documentation:
<p class="copyright">© Pizza Food - Pizzeria <?= date('Y'); ?></p>
Documentation:
<?php
ob_start();
?>
<?php
$scriptJavascript = ob_get_contents();
ob_end_clean();
?>
Documentation:
Documentation:
- Enclenche la temporisation de sortie
- Retourne le contenu du tampon de sortie
- Détruit les données du tampon et eteint la temporisation de sortie
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$_SESSION['cart_item'][$product['id']]['quantity'] = (int)$_POST['quantity'];
$_SESSION['cart_item'][$product['id']]['name'] = $product['name'];
$_SESSION['cart_item'][$product['id']]['product_type_id'] = $product['product_type_id'];;
$_SESSION['cart_item'][$product['id']]['price'] = (int)$product['price'];
function hashPassword(string $password) : string
{
return password_hash($password, PASSWORD_DEFAULT);
}
if (password_verify($password, $user['password'])) {
$_SESSION['auth']['logged'] = true;
$_SESSION['auth']['user'] = $user;
return true;
}
Documentation:
<script>
function checkEmail(data)
{
if (data.length !== 0) {
const xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
const result = JSON.parse(this.responseText);
if (result.exists) {
document.getElementById('email').style.border = '2px solid red';
document.getElementById('checkout').disabled = true;
document.querySelector('p.caption').innerText = 'Email deja existant';
} else {
document.getElementById('email').style.border = '2px solid green';
document.getElementById('checkout').removeAttribute("disabled");
document.querySelector('p.caption').innerText = '';
}
}
}
xmlHttp.open('GET', 'src/action/check_email_exists.php?email=' + data, true);
xmlHttp.send();
}
}
</script>
if (!empty($userEmail)) {
$isExists = ['exists' => true, 'email' => $email];
}
echo json_encode($isExists);
Documentation:
- [XMLHttpRequest] (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
- Exemple W3C
- La syntaxe Heredoc PHP est un moyen d'écrire de gros blocs de texte à l'intérieur de PHP, sans les délimiteurs classiques entre guillemets simples et doubles. Il s'appuie sur <<< et un jeton qui marquera également la fin de la chaîne.
$header = <<<EOT
<html>
<body>
<h1>Commande numéro {$customerData['order_id']} de {$customerData['fullname']}</h1>
<dl>
<dt style="float:left;font-size:24px">Email</dt>
<dd style="font-size:24px">{$customerData['email']}</dd>
<dt style="float:left;font-size:24px">Téléphone</dt>
<dd style="font-size:24px">{$customerData['phone']}</dd>
<dt style="float:left;font-size:24px">Adresse</dt>
<dd style="font-size:24px">{$customerData['address']}</dd>
<dl>
<h2>Détail de la commande</h2>
<table style="border:1px solid black;border-collapse:collapse;border-spacing:20px">
<tr>
<th style="padding: 10px;font-size:24px;text-transform:uppercase;text-align:center">Type de produit</th>
<th style="padding: 10px;font-size:24px;text-transform:uppercase;text-align:center">Produit</th>
<th style="padding: 10px;font-size:24px;text-transform:uppercase;text-align:center">Quantité</th>
<th style="padding: 10px;font-size:24px;text-transform:uppercase;text-align:center">Price</th>
<th style="padding: 10px;font-size:24px;text-transform:uppercase;text-align:center">Total</th>
</tr>
<tbody>
EOT;
Documentation:
-
L'opérateur Null coalescent (??) a été ajouté comme un sucre syntaxique pour les cas de besoin le plus commun d'utiliser une troisième conjonction avec la fonction isset(). Il retourne le premier opérande s'il existe et n'a pas une valeur null; et retourne le second opérande sinon.
$orderId = $_GET['order_id'] ?? $_GET['order_id'];
Documentation:
- Sécurité