Les Seeders : Organiser la génération de données
Bienvenue dans ce dixième épisode de notre série sur Laravel 12 ! 🚀 Aujourd'hui, nous allons enfin parler des seeders et voir comment les utiliser avec les factories pour générer des fausses données de manière organisée.
Introduction
Précédemment, nous avons mis en place les factories avec Laravel. Aujourd'hui, nous allons utiliser les seeders et les factories ensemble pour pouvoir générer assez facilement des fausses données et organiser la façon dont nous voulons les générer.
Les seeders peuvent nous servir pour plusieurs choses :
- Environnement de développement : Peupler notre base de données pour avoir quelque chose de prêt pour tester
- Staging : Créer un environnement de test réaliste
- Tests automatisés : Recréer un environnement contrôlé pour nos tests
- Production (moins recommandé) : Restaurer des sauvegardes ou initialiser des données
📌 Au programme :
- ✅ Comprendre le rôle des seeders
- ✅ Découvrir le DatabaseSeeder principal
- ✅ Créer des seeders personnalisés
- ✅ Améliorer les factories avec des états
- ✅ Organiser la génération de données complexes
- ✅ Utiliser les collections et le design pattern fluent
Le fichier DatabaseSeeder principal
Dans le dossier database/seeders
, nous trouvons un fichier DatabaseSeeder.php
. C'est une classe qui hérite de Seeder
et contient une seule méthode run()
:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
// User::factory(10)->create();
// User::factory()->create([
// 'name' => 'Test User',
// 'email' => 'test@example.com',
// ]);
}
}
Cette méthode run()
est appelée à chaque fois qu'on exécute :
php artisan db:seed
Créer un seeder personnalisé
Pour organiser nos données proprement, créons un seeder spécifique pour nos recettes avec ingrédients :
php artisan make:seeder RecipesWithIngredientsSeeder
Cette commande génère automatiquement une classe dans le dossier seeders
:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class RecipesWithIngredientsSeeder extends Seeder
{
public function run(): void
{
// Logique de seeding ici
}
}
Organiser les seeders dans DatabaseSeeder
Pour une approche propre, nous allons appeler notre seeder personnalisé depuis le DatabaseSeeder
principal :
public function run(): void
{
$this->call([
RecipesWithIngredientsSeeder::class,
]);
}
Avantages de cette approche :
- Séparation claire des responsabilités
- Aperçu direct de ce qui sera seedé
- Facilité de maintenance avec plusieurs seeders
- Possibilité d'exécuter des seeders individuellement
Améliorer les factories avec des états
Avant de remplir notre seeder, améliorons notre RecipeFactory
. Actuellement, nous avons :
public function definition(): array
{
return [
'title' => fake()->words(3, true),
'user_id' => fake()->boolean() ? User::factory()->create()->id : null,
];
}
Le problème ici est le boolean()
qui donne une chance sur deux d'avoir un utilisateur ou null
. Pour garantir qu'une recette ait toujours un utilisateur, nous pouvons créer un état personnalisé.
Créer un état "withUser"
Ajoutons une méthode à notre RecipeFactory
:
public function withUser(): static
{
return $this->state(fn (array $attributes) => [
'user_id' => User::factory()->create()->id,
]);
}
Maintenant, nous pouvons utiliser cette méthode pour nous assurer qu'une recette a toujours un utilisateur :
Recipe::factory()->withUser()->create();
La méthode state()
permet d'écraser certains attributs selon nos besoins spécifiques.
Implémenter le seeder RecipesWithIngredientsSeeder
Voici l'implémentation complète de notre seeder :
<?php
namespace Database\Seeders;
use App\Models\Ingredient;
use App\Models\Recipe;
use Illuminate\Database\Seeder;
class RecipesWithIngredientsSeeder extends Seeder
{
public function run(): void
{
// Créer 50 ingrédients
$ingredients = Ingredient::factory()
->count(50)
->create();
// Créer 20 recettes avec utilisateurs et ingrédients aléatoires
Recipe::factory()
->count(20)
->withUser()
->create()
->each(function ($recipe) use ($ingredients) {
// Attacher entre 2 et 6 ingrédients aléatoires
$randomIngredients = $ingredients
->random(random_int(2, 6))
->pluck('id');
$recipe->ingredients()->attach($randomIngredients);
});
}
}
Comprendre le design pattern fluent
Le code ci-dessus illustre le design pattern fluent de Laravel. Chaque méthode renvoie un type spécifique qui permet de chaîner d'autres méthodes :
Recipe::factory()
→ Instance de RecipeFactory->count(20)
→ Toujours RecipeFactory->withUser()
→ Toujours RecipeFactory->create()
→ Collection de modèles Recipe->each()
→ Méthode de Collection Laravel
Cette approche est très satisfaisante pour le développeur et évite de stocker des variables intermédiaires.
Méthodes utiles des collections Laravel
La méthode each()
Similaire à un foreach
amélioré, elle permet de boucler sur chaque élément d'une collection :
$recipes->each(function ($recipe) {
// Traitement pour chaque recette
});
La méthode random()
Permet de piocher aléatoirement un ou plusieurs éléments :
// Piocher 3 ingrédients aléatoires
$ingredients->random(3);
// Nombre variable entre 2 et 6
$ingredients->random(random_int(2, 6));
La méthode pluck()
Extrait une colonne spécifique de chaque modèle et retourne un tableau :
// Si on a 3 ingrédients avec les IDs 12, 45, 78
$ingredients->pluck('id'); // [12, 45, 78]
Exécuter les seeders
Pour exécuter nos seeders, nous avons plusieurs options :
Option 1 : Seeder seul
php artisan db:seed
Option 2 : Migration + Seeder
php artisan migrate:fresh --seed
Cette commande :
- Supprime toutes les tables (
drop
) - Recrée toutes les migrations
- Exécute automatiquement les seeders
Option 3 : Seeder spécifique
php artisan db:seed --class=RecipesWithIngredientsSeeder
Résultat attendu
Après avoir exécuté nos seeders, nous obtenons :
- 50 ingrédients générés avec des noms aléatoires
- 20 recettes avec des titres réalistes
- Chaque recette est liée à un utilisateur
- Chaque recette a entre 2 et 6 ingrédients attachés aléatoirement
- Les relations many-to-many sont correctement configurées
Bonnes pratiques
1. Séparation des responsabilités
Créez un seeder par entité ou groupe d'entités logiques :
$this->call([
UserSeeder::class,
CategorySeeder::class,
RecipesWithIngredientsSeeder::class,
]);
2. Utilisation des états de factory
Préférez les états personnalisés plutôt que la logique conditionnelle :
// ✅ Bon
Recipe::factory()->withUser()->create();
// ❌ Moins bon
Recipe::factory()->create(['user_id' => User::factory()->create()->id]);
3. Gestion des dépendances
Créez d'abord les modèles dont dépendent les autres :
// Les utilisateurs d'abord
$users = User::factory(10)->create();
// Puis les recettes qui dépendent des utilisateurs
Recipe::factory(20)->withUser()->create();
Cas d'usage avancés
Seeders conditionnels
public function run(): void
{
if (app()->environment('local', 'staging')) {
$this->call([
DemoDataSeeder::class,
]);
}
}
Seeders avec progress bar
public function run(): void
{
$this->command->info('Creating ingredients...');
Ingredient::factory(100)->create();
$this->command->info('Creating recipes...');
Recipe::factory(50)->withUser()->create();
}
Conclusion
Les seeders, combinés aux factories, offrent une solution puissante et élégante pour :
- Générer des données de test cohérentes et réalistes
- Organiser la création de données complexes avec des relations
- Automatiser l'initialisation de votre environnement de développement
- Faciliter les tests en créant des jeux de données contrôlés
Le design pattern fluent de Laravel rend le code expressif et agréable à écrire, tout en gardant une logique claire et maintenable.
Prochaines étapes
Dans le prochain épisode, nous verrons comment utiliser ces données seedées dans nos vues et contrôleurs, et comment optimiser les requêtes avec les relations Eloquent.
💡 Astuce : N'hésitez pas à expérimenter avec différentes combinaisons de factories et d'états pour créer des données qui correspondent exactement à vos besoins de test !
Vidéos de la playlist

Premiers pas et structure de Laravel 12

Les vues avec Blade et TailwindCSS

Passer des données aux vues

Le M dans MVC

Les migrations

Eloquent

Relations HasMany/BelongsTo

Relations BelongsToMany

Les Factories

Les Seeders
Réservez une session de mentorat personnalisée pour accélérer votre apprentissage et résoudre vos problèmes techniques.
Réserver une session de mentorat