aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Développement Web

Migration et Seeder Laravel : schéma et données de test

Une migration Laravel est la façon de versionner le schéma de ta base de données exactement comme tu versionnes ton code. Au lieu d'ouvrir les tables à la main dans un client SQL, tu décris chaque changement de schéma dans une classe PHP ; cette classe permet à toute ton équipe et à ton serveur de construire la même structure avec une seule commande. Un seeder, lui, est le moyen officiel de remplir ce schéma avec des données de test réalistes. En les utilisant ensemble, monter le projet de zéro se résume à une ligne, et la plupart des problèmes du type « ça marchait sur ma machine » disparaissent.

Qu'est-ce qu'une migration et pourquoi vaut-elle mieux que le SQL manuel ?

Écrire le schéma à la main pose deux gros problèmes : aucun historique des changements n'est conservé, et la base de chacun finit légèrement différente. Les migrations résolvent les deux. Chaque fichier est nommé avec un timestamp, donc l'ordre est sans ambiguïté ; la méthode up() applique le changement et la méthode down() l'annule. Comme les migrations vivent dans Git, l'historique de ton schéma avance en même temps que celui de tes commits.

  • Reproductible : la même commande construit la même structure sur chaque machine.
  • Réversible : tu peux annuler un mauvais changement avec down().
  • Traçable : la table migrations enregistre quel fichier a été exécuté, donc il ne tourne jamais deux fois.

Créer ta première migration

La commande Artisan génère à la fois le fichier et son squelette. Utilise --create pour une toute nouvelle table et --table pour en modifier une existante :

php artisan make:migration create_posts_table

# Pour ajouter une colonne à une table existante :
php artisan make:migration add_status_to_posts_table --table=posts

Le fichier généré se trouve sous database/migrations/. Une migration create_posts_table ressemble à ceci :

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('slug')->unique();
            $table->text('body');
            $table->boolean('published')->default(false);
            $table->timestamps();
        });
    }

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

$table->id() crée une clé primaire auto-incrémentée, et timestamps() ajoute les colonnes created_at et updated_at. Il existe une API fluide pour la plupart des types de colonnes : string, text, integer, boolean, json, decimal et bien d'autres.

Exécuter et annuler des migrations

Pour appliquer toutes les migrations en attente :

php artisan migrate

Voici les commandes que tu utiliseras le plus pendant le développement :

  • php artisan migrate:rollback — annule le dernier lot de migrations.
  • php artisan migrate:rollback --step=2 — revient sur les deux dernières étapes.
  • php artisan migrate:fresh — supprime toutes les tables et reconstruit de zéro.
  • php artisan migrate:refresh — annule tout puis relance.
  • php artisan migrate:status — liste les migrations déjà exécutées.

Attention en production : migrate:fresh et refresh détruisent les données. Sur un serveur en ligne, utilise uniquement php artisan migrate --force ; le drapeau --force permet l'exécution en production sans demande de confirmation.

Relations et index

Tu relies les tables avec des clés étrangères, et Laravel propose un raccourci pratique :

Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->foreignId('post_id')
          ->constrained()
          ->cascadeOnDelete();
    $table->text('body');
    $table->timestamps();
});

foreignId('post_id')->constrained() crée automatiquement une clé étrangère qui référence la colonne id de la table posts. cascadeOnDelete() garantit que lorsqu'un article est supprimé, ses commentaires le sont aussi. N'oublie pas d'ajouter un index aux colonnes souvent interrogées avec $table->index('slug') ; sur de grandes tables, cela améliore nettement la vitesse de lecture.

Générer des données de test avec un seeder

Une fois le schéma prêt, tu écris un seeder pour le remplir. Artisan génère aussi la classe du seeder :

php artisan make:seeder PostSeeder

La classe se trouve sous database/seeders/ et insère des enregistrements dans sa méthode run() :

<?php

namespace Database\Seeders;

use App\Models\Post;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    public function run(): void
    {
        Post::create([
            'title'     => 'Bonjour le monde',
            'slug'      => 'bonjour-le-monde',
            'body'      => 'Le corps du premier article.',
            'published' => true,
        ]);
    }
}

Pour exécuter un seeder seul, passe son nom de classe :

php artisan db:seed --class=PostSeeder

Pour enchaîner tous les seeders, utilise call() dans DatabaseSeeder ; php artisan db:seed exécute cette classe principale :

public function run(): void
{
    $this->call([
        UserSeeder::class,
        PostSeeder::class,
        CommentSeeder::class,
    ]);
}

Des données réalistes et en masse avec les factories

Écrire quelques lignes à la main suffit pour de petits projets, mais un vrai test exige des centaines d'enregistrements. C'est là qu'intervient la factory : elle décrit comment un seul enregistrement est généré et laisse la bibliothèque Faker faire le reste.

php artisan make:factory PostFactory --model=Post
public function definition(): array
{
    return [
        'title'     => fake()->sentence(),
        'slug'      => fake()->unique()->slug(),
        'body'      => fake()->paragraphs(3, true),
        'published' => fake()->boolean(80),
    ];
}

Ensuite, une seule ligne dans le seeder produit 50 articles réalistes :

Post::factory()->count(50)->create();

Tu peux aussi enchaîner des données liées via les factories : Post::factory()->count(10)->hasComments(5)->create() crée cinq commentaires pour chaque article. Cette approche alimente les démos et les tests automatisés avec des données cohérentes mais variées.

Un flux de travail pratique et les erreurs courantes

Au quotidien, la remise à zéro la plus propre reconstruit schéma et données en une seule commande :

php artisan migrate:fresh --seed

Quelques règles pratiques t'éviteront des ennuis :

  • Une fois qu'une migration a été exécutée et commitée, ne la modifie pas — écris-en une nouvelle. La modification ne prend effet que sur les machines qui ne l'ont pas encore exécutée.
  • Remplis toujours la méthode down() pour qu'elle soit l'exact inverse de up(), et teste réellement que l'annulation fonctionne.
  • Utiliser updateOrCreate dans les seeders évite les doublons quand tu relances le même seeder une seconde fois.
  • Ne mets jamais de données de production en dur dans un seeder ; hormis les données de référence fixes (pays, rôles), les seeders servent au test et au développement.

Questions fréquentes

Quelle est la différence entre une migration et un seeder ?

Une migration définit et versionne la structure de la base (tables, colonnes, index, relations). Un seeder insère des données dans cette structure. L'une construit le squelette, l'autre le remplit d'enregistrements de test ou d'exemple. Elles ont des rôles distincts mais travaillent ensemble.

Exécuter des migrations sur un serveur en ligne supprime-t-il les données ?

php artisan migrate n'applique que les nouvelles migrations en attente et ne touche jamais aux données existantes. Les commandes qui détruisent les données sont migrate:fresh et migrate:refresh ; ne les utilise pas en production. Sur un serveur en ligne, privilégie toujours migrate --force.

Comment ajouter une colonne plus tard ?

Ne modifie pas l'ancienne migration. Crées-en une nouvelle avec make:migration add_x_to_y_table --table=y, ajoute la colonne dans up() avec par exemple $table->string('x')->nullable(), annule-la dans down() avec $table->dropColumn('x'), puis lance php artisan migrate.

Tu veux une couche base de données propre et testable dans ton projet ? Je conçois et implémente des structures de migration, seeder et factory Laravel adaptées aux besoins de ton projet. Pour en discuter, contacte-moi.

Devamı için