Activer les contraintes d’intégrité référentielle de SQLite avec le DoctrineBundle

J’ai eu l’occasion de réutiliser SQLite il y a peu, et de redécouvrir ce qui m’avait déjà surpris auparavant : si les contraintes d’intégrité référentielle sont supportées depuis la version 3.6.19, elles sont désactivées par défaut.

Foreign key constraints are disabled by default (for backwards compatibility), so must be enabled separately for each database connection.

SQLite mettant à disposition l’instruction PRAGMA foreign_keys, j’ai créé la commande Symfony CheckSQLiteForeignKeySupportCommand.php. Une fois intégrée à votre application, vous pouvez lancer

bin/console sqlite:check-foreign-key-support

pour tester le statut des contraintes d’intégrité référentielle de la connexion Doctrine par défaut. Pour tester une autre connexion, passez son nom à l’option --connection (-c) :

bin/console sqlite:check-foreign-key-support -c sqlite

Si votre installation n’est pas antédiluvienne, vous devriez obtenir

 [WARNING] Foreign keys support is disabled.

Le but est maintenant de changer ce message !

Dans l’invite de commande de SQLite, on pourrait lancer PRAGMA foreign_keys = ON pour les activer le temps de la session. Ici, nous voulons plutôt que cette commande soit exécutée par Doctrine dès qu’une connexion est ouverte. Il fut un temps où une telle fonctionnalité aurait été implémentée en souscrivant à l'événement postConnect, mais on préférera maintenant passer par un middleware.

The logic implemented on top of these events can be implemented using driver middlewares.

Et devinez quoi ? Parmi les middlewares fournis par Doctrine, on peut trouver un EnableForeignKeys ! Reste à l’activer.

Depuis la version 2.6 du DoctrineBundle, les services implémentant Doctrine\DBAL\Driver\Middleware se voient attribuer le tag doctrine.middleware qui provoque leur activation pour toutes les connexions. Tout ce que nous avons à faire, c’est donc de configurer un service pour EnableForeignKeys !

services:
    Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys: ~

Si vous ne voulez l’activer que pour des connexions spécifiques, il faudra définir vous-mêmes un tag doctrine.middleware par connexion dont l’attribut connection sera son nom.

services:
    Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys:
        tags:
            - doctrine.middleware:
                  connection: sqlite

Et voilà !

bin/console sqlite:check-foreign-key-support

 [OK] Foreign keys support is enabled.