Tutoriel MVC · Chapitre 08

Configurer SQLite
et les migrations.

Donnez une mémoire durable à l’application et faites évoluer son schéma sans improvisation.

CONFIGSQLITEMIGRATIONSDATA

Une application qui oublie tout après chaque requête n’est pas encore terminée.

Les contrôleurs et les vues donnent déjà l’impression que l’application fonctionne. Pourtant, sans stockage durable, aucune tâche ne survivra au prochain démarrage. Nous allons donner une mémoire réelle au projet avec SQLite et une histoire de schéma reproductible grâce aux migrations.

Le but n’est pas seulement de créer un fichier .sqlite. Vous apprendrez où il doit vivre, comment le configurer sans exposer de secret, comment construire la table tasks sur toute machine et comment faire évoluer cette structure sans improviser directement en production.

Projet du chapitre

Configurez une base SQLite privée, créez la migration tasks, vérifiez migrate et rollback, puis préparez des bases distinctes pour développement, tests et production.

08.1

Pourquoi une base de données ?

Jusqu’ici, l’application sait recevoir une tâche et afficher une interface, mais une donnée conservée seulement dans une variable disparaît à la fin de la requête. Une base apporte une mémoire durable partagée par toutes les requêtes.

Une base relationnelle organise les informations dans des tables, lignes et colonnes. Elle peut imposer des types, des valeurs obligatoires, des identifiants uniques et des relations que le code seul ne garantit pas toujours.

SQLite stocke toute la base dans un fichier et ne demande aucun serveur séparé. Cela en fait un excellent choix pour apprendre, tester, développer localement et déployer de petites applications.

À retenir

La base garantit la persistance et une partie essentielle de l’intégrité des données.

08.2

Configurer avec l’environnement

Le code doit savoir quel pilote utiliser et où trouver la base, mais ces valeurs changent entre ordinateur, tests et production. Elles appartiennent donc à l’environnement plutôt qu’aux classes PHP.

Le fichier .env local peut définir DB_CONNECTION=sqlite et DB_DATABASE=runtime/database/app.sqlite. phpaml.json décrit les choix non secrets du projet, tandis que les secrets ne doivent jamais être commités.

Utilisez aml env:init pour créer l’environnement à partir d’un exemple documenté. Une nouvelle installation doit pouvoir comprendre les variables attendues sans recevoir les valeurs privées de votre machine.

À retenir

Le dépôt documente les clés; chaque environnement possède ses propres valeurs.

phpaml — zsh
DB_CONNECTION=sqlite
DB_DATABASE=runtime/database/app.sqlite
08.3

Choisir le chemin du fichier SQLite

Le fichier SQLite contient de vraies données et évolue pendant l’exécution. Il ne doit pas vivre dans public, où un visiteur pourrait le télécharger, ni dans un dossier de code versionné.

PHPAML place les données d’exécution sous runtime/database. Le serveur Web doit pouvoir écrire dans ce dossier, mais public/index.php reste le seul point d’entrée accessible depuis Internet.

Utilisez un chemin absolu résolu depuis la racine du projet pour éviter qu’un changement de répertoire courant crée accidentellement une seconde base vide.

À retenir

Une base SQLite est une donnée privée d’exécution, jamais une ressource publique.

08.4

Comprendre PDO et la connexion

PDO fournit une interface commune aux bases SQL. Une connexion SQLite utilise un DSN commençant par sqlite:, puis le chemin du fichier. Le framework centralise cette création afin que les modèles ne reconstruisent pas la connexion.

Activez le mode d’erreur par exceptions et les contraintes de clés étrangères. Une erreur silencieuse produit des données incohérentes; une exception claire peut être journalisée et transformée en réponse appropriée.

Préparez toujours les requêtes contenant des valeurs externes. Les paramètres liés séparent le code SQL des données et empêchent une saisie utilisateur de modifier la structure de la requête.

À retenir

La connexion est centralisée; les valeurs externes passent par des paramètres préparés.

08.5

Concevoir la table tasks

Avant d’écrire une migration, décrivez ce que représente une tâche. Elle possède un identifiant, un titre, une description facultative, un état de complétion et des dates de création et modification.

Choisissez les contraintes selon le métier : title ne peut pas être null, completed reçoit une valeur par défaut et id est la clé primaire. Une contrainte en base protège aussi les écritures provenant d’un script ou d’une future API.

N’ajoutez pas toutes les colonnes imaginables. Un schéma minimal et explicite évolue mieux qu’une table remplie de champs hypothétiques et rarement compris.

À retenir

Le schéma traduit les invariants durables du métier en contraintes de données.

08.6

Créer une migration

Une migration est une modification de schéma versionnée et reproductible. Elle décrit comment avancer avec up() et, lorsque cela est sûr, comment revenir avec down().

Le nom create_tasks_table indique l’intention. Le numéro ou horodatage ordonne les migrations afin que toutes les installations appliquent exactement la même histoire.

Une migration doit rester déterministe : elle ne dépend pas de données présentes seulement sur votre ordinateur et ne demande pas une décision interactive pendant le déploiement.

À retenir

Le schéma appartient à l’histoire versionnée du projet, pas à une manipulation manuelle.

phpaml — zsh
final class CreateTasksTable extends Migration
{
    public function up(): void
    {
        Schema::create('tasks', function (Blueprint $table): void {
            $table->id();
            $table->string('title', 120);
            $table->text('description')->nullable();
            $table->boolean('completed')->default(false);
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('tasks');
    }
}
08.7

Exécuter et vérifier les migrations

aml migrate applique uniquement les migrations absentes et enregistre leur exécution dans une table interne. Relancer la commande ne doit pas recréer les tables déjà présentes.

Après l’exécution, vérifiez le statut, la structure réelle de tasks et les contraintes importantes. Une commande qui termine sans erreur ne prouve pas à elle seule que le schéma correspond à votre intention.

Exécutez les migrations dans la CI sur une base neuve. Cela détecte les dépendances cachées à une base locale déjà modifiée manuellement.

À retenir

Une migration est fiable lorsqu’elle construit la bonne base depuis zéro de manière répétable.

phpaml — zsh
aml make:migration create_tasks_table
aml migrate
aml migrate:status
08.8

Annuler sans perdre les données

Le rollback exécute down() sur le dernier lot. Supprimer une table annule bien sa structure, mais détruit aussi ses lignes : une opération techniquement réversible peut donc rester dangereuse.

En développement, rollback aide à corriger une migration récente. En production, préférez souvent une nouvelle migration corrective, sauvegardez avant l’opération et évaluez l’impact sur les versions de code encore actives.

Certaines transformations de données nécessitent plusieurs étapes : ajouter une colonne nullable, remplir les valeurs, puis renforcer la contrainte dans une migration ultérieure.

À retenir

Avant un rollback, distinguez réversibilité du schéma et récupération réelle des données.

phpaml — zsh
aml migrate:rollback
# Verify data impact before production rollback.
08.9

Séparer développement, test et production

Chaque environnement doit posséder sa propre base. Les tests ne doivent jamais toucher les tâches du développeur, et une commande locale ne doit jamais pouvoir effacer la production.

Utilisez une base temporaire ou dédiée aux tests, recréée automatiquement. Les données de démonstration proviennent de seeders ou fixtures explicites plutôt que d’une copie incontrôlée de production.

En production, limitez les permissions, sauvegardez le fichier SQLite et empêchez plusieurs déploiements concurrents d’exécuter les mêmes migrations sans coordination.

À retenir

Les environnements partagent le schéma, jamais leurs données ni leurs secrets.

08.10

Sauvegarder et diagnostiquer

Une base dans un fichier simplifie la sauvegarde, mais copier un fichier pendant une écriture peut être risqué. Utilisez les mécanismes SQLite appropriés ou arrêtez brièvement les écritures pour obtenir un instantané cohérent.

En cas d’erreur, vérifiez le chemin réellement résolu, l’existence du dossier, les permissions, l’extension PDO SQLite et le statut des migrations. Une base vide inattendue indique souvent un mauvais chemin plutôt qu’une perte magique.

Surveillez la taille, l’espace disque et la fréquence des sauvegardes. Testez aussi la restauration : une sauvegarde non restaurable n’est qu’un sentiment de sécurité.

À retenir

La persistance est complète seulement lorsque sauvegarde, diagnostic et restauration sont prévus.

Atelier guidé

Construisez la base de l’application.

  1. Initialisez .env et sélectionnez SQLite.
  2. Placez la base dans runtime/database.
  3. Créez la migration tasks avec ses contraintes.
  4. Appliquez et inspectez la migration.
  5. Testez un rollback sur des données temporaires.
  6. Recréez la base entièrement depuis zéro.
  7. Configurez une base distincte pour les tests.
  8. Documentez sauvegarde et restauration de production.

Correction raisonnée

Prouvez que le schéma ne dépend pas de votre ordinateur.

Supprimez uniquement la base de test, recréez-la avec les migrations, puis exécutez les vérifications. Si tout fonctionne sans modification manuelle, l’histoire du schéma est réellement reproductible.

En résumé

La base est maintenant durable, privée et reproductible.

Vous avez séparé la configuration du code, placé SQLite dans runtime, conçu un schéma minimal et transformé ce schéma en migrations versionnées. Vous savez aussi pourquoi rollback, sauvegarde et séparation des environnements exigent de la prudence.

  • gardez la base hors de public et du dépôt
  • décrivez la configuration dans .env et phpaml.json
  • versionnez chaque changement de schéma
  • testez les migrations depuis une base vide
  • sauvegardez avant toute opération destructive

Au chapitre 9, nous construirons le modèle Task qui utilisera cette base pour lire, créer, modifier et supprimer les tâches avec des requêtes sûres et des transactions.

Chapitre 07Chapitre 09 · À venir 🔒