Les migrations sont un pilier essentiel pour la gestion de la base de données dans les frameworks modernes comme Symfony et Laravel. Pourtant, les approches diffèrent.
Là où Symfony favorise une configuration explicite et un couplage direct à Doctrine, Laravel mise sur un système fluide, où l'élégance syntaxique prime, et où les développeurs bénéficient de raccourcis efficaces grâce à Eloquent.
Une migration est donc une classe prête à l'emploi avec une structure pensée pour les besoins courants. Découvrons ensemble de quoi il en retourne !
Les bases des migrations
Qu'est-ce qu'une migration ?
Une migration est un fichier scripté qui décrit comment une base de données doit évoluer. Elle permet de versionner les modifications (création de tables, ajout de colonnes, etc.) et de garantir que tous les environnements de développement et de production restent synchronisés.
Par ailleurs, après avoir défini la structure de votre base de données, vous pouvez facilement peupler vos tables avec les seeders.
Simple et puissant
Avec Laravel, une migration est une classe générée via la commande Artisan make:migration
:
1return new class extends Migration 2{ 3 /** 4 * Run the migrations. 5 */ 6 public function up(): void 7 { 8 Schema::create('users', function (Blueprint $table) { 9 $table->id();10 $table->string('name');11 $table->string('email')->unique();12 $table->timestamp('email_verified_at')->nullable();13 $table->string('password');14 $table->rememberToken();15 $table->timestamps();16 17 // ...18 });19 }20 21 public function down(): void22 {23 Schema::dropIfExists('users');24 Schema::dropIfExists('password_reset_tokens');25 Schema::dropIfExists('sessions');26 }27};
Ce code provient directement du repository de Laravel lui-même, il permet de versionner la création de la table users
.
Pour créer un nouveau fichier de migration vous passerez par une commande artisan :
1php artisan make:migration create_products_table2# ou3php artisan make:migration CreateProductsTable
Mais elle peut être créée en même temps que votre Modèle avec l'option -m
:
1php artisan make:model Product -m
La classe générée dans le dossier database/migrations
contient deux méthodes : up()
et down()
.
La méthode up()
exécute la migration. On y retrouve le nom de la table. La valeur $table
est une instance de Blueprint
et permet d'utiliser de nombreuses méthodes pour créer les colonnes de sa table ou effectuer d'autres changements.
La méthode down()
inverse la migration. C'est le code exécuté lorsque vous faites un rollback
de vos migrations.
Revenir en arrière
Il se peut que vous souhaitiez revenir sur une migration précédemment exécutée. Voyons les 4 commandes possibles pour ce faire.
php artisan migrate:rollback
Cette commande annule le dernier lot de migrations enregistré dans la table existante. Un "lot" (batch) désigne un groupe de migrations exécutées ensemble lors d'une même commande php artisan migrate
.
1php artisan migrate:rollback
Vous pouvez spécifier le nombre de lots à annuler avec l’option --step
:
1php artisan migrate:rollback --step=2
php artisan migrate:reset
La commande php artisan migrate:reset
diffère de rollback
. Avec reset
, toutes les migrations appliquées sont annulées, peu importe quand elles ont été exécutées.
1php artisan migrate:reset
php artisan migrate:refresh
La commande php artisan migrate:refresh
annule toutes les migrations, puis les exécute à nouveau. Cela permet de reconstruire la base de données depuis zéro. Vous pouvez utiliser l'option --step
pour limiter les migrations concernées.
1php artisan migrate:refresh --step=1
php artisan migrate:fresh
La commande php artisan migrate:fresh
supprime toutes les tables de la base de données, puis exécute à nouveau toutes les migrations. Contrairement à refresh
, elle ne revient pas sur les migrations mais supprime directement les tables.
1php artisan migrate:fresh
Gérer des cas complexes
Les relations entre tables
Les bases de données relationnelles nécessitent de gérer des relations (one-to-many
, many-to-many
). Laravel facilite cela via des méthodes intégrées pour les clés étrangères et leurs contraintes.
Prenons l'exemple d'une relation belongsTo()
(many-to-one
) :
1return new class extends Migration 2{ 3 public function up(): void 4 { 5 Schema::create('products', function (Blueprint $table) { 6 $table->id(); 7 $table->timestamps(); 8 9 // Première syntaxe10 $table->unsignedBigInteger('order_id');11 $table->foreign('order_id')->references('id')->on('orders');12 13 // Deuxième syntaxe14 $table->foreignId('order_id')->constrained();15 16 // Troisième syntaxe17 $table->foreignIdFor(\App\Models\Product::class)->constrained();18 });19 }20};
Conventions Laravel pour les clés étrangères
Laravel s'attend à ce que les noms des tables et des clés étrangères suivent ces conventions :
-
Nom de la table : au pluriel (exemple :
orders
). -
Nom de la clé étrangère : au singulier, suivi de
_id
(exemple :order_id
).
Respecter ces conventions garantit un code plus clair et compatible avec le reste de l'écosystème Laravel et son ORM.
Aller plus loin
Indexation et optimisation des performances
Utiliser des index : Ajoutez des index aux colonnes fréquemment utilisées dans les requêtes pour améliorer les performances. Cela réduit le temps de recherche dans des tables volumineuses. Pour un guide pratique, consultez ce tutoriel vidéo sur les index dans Laravel.
1$table->index('column_name');
Pour des recherches complexes, pensez aussi à des index composites :
1$table->index(['column1', 'column2']);
Sous-requêtes : Exploitez les sous-requêtes pour des calculs avancés ou pour récupérer des données liées sans créer des relations complexes dans vos modèles. Par exemple, voici comment inclure une sous-requête dans un champ calculé :
1$users = User::query()2 ->addSelect([3 'total_orders' => Order::selectRaw('COUNT(*)')4 ->whereColumn('orders.user_id', 'users.id')5 ])->get();
Pour plus de détails, consultez ce tutoriel sur les sous-requêtes dans Laravel.
Modifier les colonnes avec précaution : Privilégiez des migrations non bloquantes pour éviter des temps d'arrêt prolongés. Par exemple, au lieu de modifier directement une colonne existante, créez une nouvelle colonne, migrez les données, puis supprimez l’ancienne colonne :
1Schema::table('users', function (Blueprint $table) { 2 $table->string('new_column')->nullable(); 3}); 4 5// Migrer les données via un script artisan ou un job 6DB::table('users')->update(['new_column' => DB::raw('old_column')]); 7 8Schema::table('users', function (Blueprint $table) { 9 $table->dropColumn('old_column');10});
Réindexation : Après des modifications majeures (comme le changement de type d’une colonne ou la suppression de nombreuses lignes), reconstruisez les index pour maintenir des performances optimales. Utilisez des commandes SQL spécifiques ou intégrez des scripts Artisan adaptés.
Calculs de distance : Dans des projets nécessitant une gestion géospatiale (comme trouver les magasins proches d’un utilisateur), vous pouvez utiliser la fonction SQL ST_Distance
combinée à un scope Eloquent. Voici un exemple :
1$coordinates = [5.93333, 43.116669]; 2 3$shops = Shop::query() 4 ->addDistance($coordinates) 5 ->latest() 6 ->get(); 7 8// Dans le modèle Shop 9public function scopeAddDistance(Builder $query, array $coordinates): void10{11 $query12 ->when(is_null($query->getQuery()->columns), static fn (Builder $query) => $query->select('*'))13 ->selectRaw(14 expression: 'ST_Distance(15 ST_SRID(Point(longitude, latitude), 4326),16 ST_SRID(Point(?, ?), 4326)17 ) AS distance',18 bindings: $coordinates19 );20}
Pour un guide complet, explorez ce tutoriel vidéo sur le calcul de distance avec Eloquent.
Conclusion
Laravel fournit un puissant système de gestion des bases de données via ses migrations et ses outils avancés. En respectant les conventions, en adoptant de bonnes pratiques, et en exploitant des fonctionnalités comme les index, les sous-requêtes ou les calculs géospatiaux, vous pouvez garantir une base de données performante, maintenable et évolutive.
A lire
Autres articles de la même catégorie
Testez vos règles personnalisées PHPStan
PHPStan offre la possibilité de créer vos propres règles de validation, voyons comment tester unitairement l'une d'entre elles !
Mathieu De Gracia
Tour d'horizon des façades
Présentation du fonctionnement des façades, leurs avantages et inconvénients. Pourquoi faut-il les considérer dans un écosystème Laravel ?
Marc COLLET
Optimisez votre application avec le chunk de Laravel
Voyons ce que propose Laravel pour traiter de grandes quantités de données efficacement
Mathieu De Gracia