Le CASCADE DELETE en PHP avec PDO

Pour les développeur ayant suivi un cours sur Symfony, lors de la modélisation des entités, vous avez sans doute croisé le CASCADE DELETE quand vous aviez deux entité avec une relation oneToMany.

Exemple de situation où un cascade delete est utile

Par exemple une entité Category a une relation de un à plusieurs avec l’entité Product. Quand vous effacez une catégorie, et pour éviter que des produits se retrouvent sans catégorie, vous allez aussi effacer les produits correspondant à cette catégorie. Il y a effacement en cascade, l’effacement de la catégorie efface automatiquement les produits rattachés.

En SQL vous pouvez mettre une contrainte de CASCADE DELETE de cette façon :

CREATE TABLE utilisateurs (
    id INT PRIMARY KEY,
    nom VARCHAR(100)
);

CREATE TABLE commandes (
    id INT PRIMARY KEY,
    utilisateur_id INT,
    FOREIGN KEY (utilisateur_id) REFERENCES utilisateurs(id) ON DELETE CASCADE
);

Ce n’est pas avec Category et Product mais vous l’aurez compris. Si vous n’avez pas fait de contrainte, vous devriez le faire manuellement.

DELETE FROM commandes WHERE utilisateur_id = 1;
DELETE FROM utilisateurs WHERE id = 1;

C’est un peu fastidieux, et pas garanti dans la théorie, il peut se produire un événement qui fait que la seconde requête ne soit pas exécutée (même si c’est peu probable, mais si nous considérons une application de grande échelle et profesionnelle, on ne peut tolérer çà)

Donc pour garantir que les deux requêtes sont exécutées, nous devons utiliser le mécanisme de transaction.

Qu’est ce qu’une transaction?

Imaginez que vous retirez du cash à un ATM, vous entrez votre code vous récupérez votre carte, mais à la fin vous ne percevez pas vos billets et le ticket sort avec une erreur. Vous vous demandez si votre compte en banque ne s’est pas diminué de la somme que vous vouliez retirer, malgré le fait que vous n’avez pas perçu vos billets ! (rassurez vous ce n’est pas le cas !). le mécanisme de transaction fait que comme le s billets ne sont pas sortis, le débit sur votre compte n’est pas effectif.

Eh bien c’est le même mécanisme dans la requêtes SQL.

START TRANSACTION;

DELETE FROM commandes WHERE utilisateur_id = 1;
DELETE FROM utilisateurs WHERE id = 1;

COMMIT;

Dans MySQL, par défaut vous êtes en AUTOCOMMIT, mais dans l’absolu, une requête SQL doit avoir la forme ci-dessus.

Si une des requêtes échoue, il se produira un ROLLBACK, pour revenir à un état comme si rien ne s’est passé.

BEGIN;

DELETE FROM commandes WHERE utilisateur_id = 42;
DELETE FROM utilisateurs WHERE id = 42;

-- Si les 2 passent bien
COMMIT;

-- Si erreur ou condition non respectée
ROLLBACK;
// Dans la console SQL, vous pouvez explicitement faire un ROLLBACK pour annuler une requête si le COMMIT n'est pas invoqué

Le mécanisme de cascade avec PDO en PHP

function deleteQuestion(PDO $pdo, int $id): array
{
    try {
        // Démarrer la transaction
        $pdo->beginTransaction();

        // Supprimer d'abord les réponses
        $stmt = $pdo->prepare("DELETE FROM reponses WHERE fk_question = :id");
        $stmt->execute(['id' => $id]);

        // Puis supprimer la question
        $stmt = $pdo->prepare("DELETE FROM questions WHERE id = :id");
        $stmt->execute(['id' => $id]);

        // Tout est ok → commit
        $pdo->commit();

        return ['success' => true];
    } catch (Exception $e) {
        // En cas d'erreur → rollback
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        return ['success' => false, 'error' => $e->getMessage()];
    }
}

Si vous êtes codeur, cette façon de procéder paraitra plus simple :

Utilisation des vraies méthodes transactionnelles de PDO (beginTransaction, commit, rollBack).

Exécution séparée des requêtes (plus clair et plus sûr que tout mettre dans une seule string).

Retour structuré (['success' => true] ou ['success' => false, 'error' => ...]) pour facilement tester côté front.

Typage de la fonction (PDO $pdo, int $id : array) → un peu plus robuste.

A propos de l'auteur

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *