Aller au contenu

Opérations CRUD

erabliere/
├── includes/
│ ├── db.php connexion, chargée par toutes les pages
│ ├── categories.php liste blanche des catégories
│ ├── validation.php contrôles partagés
│ ├── header.php repris du chapitre sur la composition
│ └── footer.php
├── init.sql structure et données de départ
├── produits.php liste, création, suppression
└── produit-modifier.php édition d'un produit
<?php
return [
'sirop' => 'Sirops',
'tartinade' => 'Tartinades',
'confiserie' => 'Confiseries',
'coffret' => 'Coffrets',
];
État des fichiers à ce stade (Progression)

✅ Fichier(s) complété(s) à ce stade
📝 Fichier(s) travaillé(s) dans cette section

erabliere/
├── includes/
│ ├── db.php 📝
│ ├── categories.php ✅
│ ├── validation.php
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql
├── produits.php
└── produit-modifier.php

Plutôt que de recopier les (mêmes) instructions de connexion à la base de données dans chaque page, il est préférable de les écrire une fois, dans un fichier distinct, puis de l’importer au besoin dans les pages communicant avec la base de données.

<?php
/**
* Ouvre la connexion à la base de données et définit la variable $pdo pour la
* page appelante.
*/
const BD_HOTE = 'localhost';
const BD_NOM = 'erabliere';
const BD_UTILISATEUR = 'root';
const BD_MOT_DE_PASSE = '';
// Identification de la base de données
$dsn = 'mysql:host=' . BD_HOTE . ';dbname=' . BD_NOM . ';charset=utf8mb4';
// Options utilisées par PDO lors de la communication avec la base de données
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
// Tentative de connexion à la base de données
try {
$pdo = new PDO($dsn, BD_UTILISATEUR, BD_MOT_DE_PASSE, $options);
} catch (PDOException $e) {
http_response_code(500); // indique au client (navigateur) que le serveur a rencontré une condition inattendue
exit('Connexion à la base de données impossible.');
}
  • ERRMODE_EXCEPTION demande à PDO de lever une exception lorsqu’une opération échoue. Elle est le comportement par défaut depuis PHP 8.
  • DEFAULT_FETCH_MODE évite de répéter PDO::FETCH_ASSOC à chaque lecture. Les lignes arrivent sous forme de tableaux associatifs, avec les noms de colonnes comme clés.
  • EMULATE_PREPARES à false demande que les requêtes préparées soient réellement préparées par le serveur, plutôt que reconstituées par PDO avant l’envoi.
État des fichiers à ce stade (Progression)

✅ Fichier(s) complété(s) à ce stade
📝 Fichier(s) travaillé(s) dans cette section

erabliere/
├── includes/
│ ├── db.php ✅
│ ├── categories.php ✅
│ ├── validation.php
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql 📝
├── produits.php
└── produit-modifier.php

Nous allons créer la table produits et la peupler de quelques données pour faciliter le développement de nos pages CRUD.

La structure de la table et les données de départ tiennent dans un fichier SQL, exécuté une fois depuis phpMyAdmin.

-- init.sql
-- Structure et données de départ. À exécuter dans la BD erabliere.
DROP TABLE IF EXISTS produits;
CREATE TABLE produits (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100) NOT NULL,
categorie VARCHAR(40) NOT NULL,
prix DECIMAL(6, 2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
cree_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
INSERT INTO produits (nom, categorie, prix, stock) VALUES
('Sirop d''érable doré 540 ml', 'sirop', 14.50, 12),
('Sirop d''érable ambré 540 ml', 'sirop', 15.25, 7),
('Beurre d''érable 250 g', 'tartinade', 9.95, 0),
('Gelée d''érable 190 ml', 'tartinade', 11.00, 9),
('Tire sur la neige', 'confiserie', 6.25, 30),
('Coffret découverte', 'coffret', 39.00, 5);
  1. Démarrez Apache et MySQL dans le panneau XAMPP.
  2. Ouvrez http://localhost/phpmyadmin, puis créez la base de données erabliere si elle n’existe pas, avec l’interclassement utf8mb4_general_ci.
  3. Sélectionnez la base de données, ouvrez l’onglet « SQL », collez le contenu de init.sql et exécutez.
  4. Vérifiez dans l’onglet « Parcourir » que les six produits apparaissent, avec leur date de création.
État des fichiers à ce stade (Progression)

✅ Fichier(s) complété(s) à ce stade
📝 Fichier(s) travaillé(s) dans cette section

erabliere/
├── includes/
│ ├── db.php ✅
│ ├── categories.php ✅
│ ├── validation.php
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql ✅
├── produits.php
└── produit-modifier.php

CRUD est l’acronyme des quatre opérations de base sur des données persistantes :

  • create (créer) : Ajouter une ou plusieurs nouvelles données. Utilise l’opération INSERT.
  • read (lire) : Récupérer des données complètes, agrégées ou filtrées. Utilise l’opération SELECT.
  • update (modifier) : Modifier une ou plusieurs données existantes. Utilise l’opération UPDATE.
  • delete (supprimer) : Supprimer une ou plusieurs données existantes. Utilise l’opération DELETE.
01

Afficher la liste des produits

LireSELECT

Voir ce que contient le catalogue, sans rien modifier.

L’utilisateur ouvre la page. Le tableau se remplit avec les produits de la base de données, triés par nom.

02

Ajouter un produit au catalogue

CréerINSERT

Enregistrer un nouveau produit à partir d'un formulaire.

L’utilisateur remplit le formulaire en bas de la liste et l’envoie. Si tout est valide, le produit apparaît dans le tableau et un message le confirme. Sinon le formulaire revient, rempli, avec les messages d’erreur.

03

Corriger un produit existant

ModifierUPDATE

Charger les valeurs actuelles dans un formulaire, puis enregistrer les modifications.

Depuis la liste, l’utilisateur clique sur « Modifier ». Le formulaire s’ouvre déjà rempli avec les valeurs actuelles. Il change ce qu’il veut et enregistre les nouvelles valeurs.

04

Retirer un produit du catalogue

SupprimerDELETE

Supprimer une ligne sans utiliser une requête GET susceptible d'être déclenchée par le simple suivi d'un lien.

Chaque ligne du tableau a un bouton « Supprimer » mis dans un formulaire. L’envoi du formulaire retire la ligne, et la liste revient avec un message.

État des fichiers à ce stade (Progression)

✅ Fichier(s) complété(s) à ce stade
📝 Fichier(s) travaillé(s) dans cette section

erabliere/
├── includes/
│ ├── db.php ✅
│ ├── categories.php ✅
│ ├── validation.php 📝
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql ✅
├── produits.php
└── produit-modifier.php

La création et la modification vérifient les mêmes champs, et leurs deux formulaires réaffichent les valeurs et les messages de la même façon. Plutôt que d’écrire deux fois les mêmes conditions, on met les trois fonctions dans un fichier chargé par les deux pages.

includes/validation.php

Les trois fonctions partagées par la création et la modification.

La spécification
  • Responsabilités : Règles communes à l’ajout et à la correction d’un produit.
  • Fonction Validation des champs du formulaire :

    • Nom : obligatoire, 100 caractères au plus.
    • Catégorie : doit figurer dans la liste admise.
    • Prix : nombre décimal positif ou nul.
    • Stock : nombre entier positif ou nul.
    • => Rend les erreurs ou anomalies rattachées à leur champ, et les valeurs converties dans leur type approprié (décimal, entier, etc.).
  • Fonction Fournit la valeur à réafficher dans un champ.
  • Fonction Fournit le message d’erreur (si présent) associé à un champ.
  • N’interroge pas la base de données et n’effectue pas de redirection.
État des fichiers à ce stade (Progression)

✅ Fichier(s) complété(s) à ce stade
📝 Fichier(s) travaillé(s) dans cette section

erabliere/
├── includes/
│ ├── db.php ✅
│ ├── categories.php ✅
│ ├── validation.php ✅
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql ✅
├── produits.php 📝
└── produit-modifier.php
produits.php

L'affichage de la liste de produits, le formulaire d'ajout et la suppression; dans un seul fichier.

La spécification
  • Responsabilités : affichage, ajout et suppression

    • Affiche les informations des produits triés par nom, avec le prix mis en forme.
    • Permet d’ajouter un produit et d’en retirer un.
  • Une suppression (retrait de produit) exige l’envoi d’un formulaire, jamais le suivi d’un lien.
  • Ajout refusé : l’écran revient avec les anomalies et les valeurs saisies.
  • Ajout ou retrait accepté : la liste de produits mise à jour revient avec une confirmation (affichée une seule fois).
  • Recharger l’écran après une opération ne la répète pas.
VérificationLa suppression passe par POST et se termine par une redirection. La redirection est-elle encore utile, puisqu'un second DELETE ne supprimerait rien de plus ?

Elle reste utile, pour une autre raison que le doublon. Sans elle, la page affichée est la réponse à un POST : la rafraîchir fait réapparaître la demande de confirmation du navigateur, et revenir dessus par l’historique renvoie le même envoi. La redirection ramène l’utilisateur sur une page consultable en GET, dont le rafraîchissement n’est qu’une relecture.

État des fichiers à ce stade (Progression)

✅ Fichier(s) complété(s) à ce stade
📝 Fichier(s) travaillé(s) dans cette section

erabliere/
├── includes/
│ ├── db.php ✅
│ ├── categories.php ✅
│ ├── validation.php ✅
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql ✅
├── produits.php ✅
└── produit-modifier.php 📝
produit-modifier.php

Charger un produit par son identifiant, puis enregistrer les changements.

La spécification
  • Responsabilités : Modifie un produit désigné par son identifiant.
  • Validation de l’identifiant:

    • Identifiant n’est pas un entier : refus avant toute requête.
    • Identifiant sans produit correspondant : écran « introuvable ».
  • L’identifiant est transmis à l’arrivée et au renvoi, et vérifié les deux fois.
  • Enregistrement des nouvelles données

    • Enregistrement refusé : le formulaire revient avec les anomalies et les valeurs saisies.
    • Enregistrement accepté : retour à la liste avec une confirmation.
erabliere/
├── includes/
│ ├── db.php ✅
│ ├── categories.php ✅
│ ├── validation.php ✅
│ ├── header.php ✅
│ └── footer.php ✅
├── init.sql ✅
├── produits.php ✅
└── produit-modifier.php ✅
  • Après exécution de init.sql, la table produits contient six lignes.
  • La liste affiche les produits triés, avec le libellé de catégorie et non sa clé.
  • Un formulaire de création vide affiche toutes les erreurs d’un coup, et conserve les valeurs correctes.
  • Après un ajout réussi, l’adresse est produits.php et le rafraîchissement n’ajoute rien.
  • Le message de confirmation apparaît une fois, puis disparaît.
  • produit-modifier.php?id=9999 affiche une page « introuvable » et non une erreur PHP.
  • produit-modifier.php?id=abc est refusé avant toute requête vers la base de données.
  • Un nom contenant <b>gras</b> s’affiche tel quel dans la liste.
  • Aucune requête n’assemble de valeur par concaténation dans la chaîne SQL.

Quiz. Pourquoi la suppression passe-t-elle par un formulaire POST plutôt que par un lien ?

Quiz. Pourquoi confier la création de la table à un fichier SQL plutôt qu'à une page PHP ?

Quiz. Pourquoi effacer le message de session juste après l'avoir lu ?

Quiz. Dans quel cas query() convient-il, plutôt que prepare() suivi de execute() ?