Maßtrisez l'art de créer des données de test professionnelles
Objectifs : Comprendre, installer et utiliser les fixtures Symfony
Durée : 2 heures
Niveau : Débutant à intermédiaire
Une fixture = ensemble de données factices (mais réalistes) pour alimenter votre base de données
đ E-commerce : Produits, catĂ©gories, commandes, clients
đ Blog : Articles, auteurs, commentaires, catĂ©gories
đ± RĂ©seau social : Utilisateurs, posts, likes, followers
đŒ Gestion : EmployĂ©s, dĂ©partements, projets, tĂąches
# Installation via Composer composer require --dev doctrine/doctrine-fixtures-bundle # Le bundle est automatiquement activé
Note : --dev = uniquement en développement, pas en production
// config/bundles.php
return [
// ... autres bundles
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => [
'dev' => true,
'test' => true
],
];
// src/DataFixtures/AppFixtures.php
namespace App\DataFixtures;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
// Création d'un utilisateur
$user = new User();
$user->setEmail('admin@example.com');
$user->setName('Administrateur');
// Persistance (prépare la sauvegarde)
$manager->persist($user);
// Sauvegarde définitive
$manager->flush();
}
}
# Chargement (supprime les données existantes) php bin/console doctrine:fixtures:load # Ajout sans supprimer php bin/console doctrine:fixtures:load --append
public function load(ObjectManager $manager): void
{
// Création d'un admin
$admin = new User();
$admin->setEmail('admin@blog.com');
$admin->setName('Administrateur');
$admin->setRoles(['ROLE_ADMIN']);
$manager->persist($admin);
// Création d'articles en boucle
for ($i = 1; $i <= 10; $i++) {
$article = new Article();
$article->setTitle('Article ' . $i);
$article->setContent('Contenu de l\'article ' . $i);
$article->setAuthor($admin);
$article->setCreatedAt(new \DateTimeImmutable());
$manager->persist($article);
}
$manager->flush(); // Sauvegarde tout
}
Résultat : 1 admin + 10 articles en quelques secondes !
Pour réutiliser des objets créés dans une fixture depuis une autre fixture
// UserFixtures.php
public const ADMIN_REFERENCE = 'admin-user';
$admin = new User();
// ... configuration
$manager->persist($admin);
// Création de la référence
$this->addReference(
self::ADMIN_REFERENCE,
$admin
);
// ArticleFixtures.php
public function load(ObjectManager $manager): void
{
// Récupération de la référence
$admin = $this->getReference(
UserFixtures::ADMIN_REFERENCE
);
$article = new Article();
$article->setAuthor($admin);
// ...
}
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
class ArticleFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
// Utilise des références de UserFixtures
$admin = $this->getReference(UserFixtures::ADMIN_REFERENCE);
// ...
}
// Déclare que cette fixture dépend de UserFixtures
public function getDependencies(): array
{
return [UserFixtures::class];
}
}
Important : Symfony charge automatiquement UserFixtures AVANT ArticleFixtures
composer require --dev fakerphp/faker
use Faker\Factory;
public function load(ObjectManager $manager): void
{
$faker = Factory::create('fr_FR'); // En français
for ($i = 0; $i < 20; $i++) {
$user = new User();
$user->setName($faker->name()); // "Marie Dubois"
$user->setEmail($faker->email()); // "marie.d@gmail.com"
$user->setPhone($faker->phoneNumber()); // "01 23 45 67 89"
$manager->persist($user);
}
$manager->flush();
}
$faker->word() - Un mot$faker->sentence() - Une phrase$faker->paragraph() - Un paragraphe$faker->text(100) - Texte de 100 car.$faker->numberBetween(1, 100)$faker->randomFloat(2, 0, 999)$faker->dateTimeBetween('-1 year')$faker->randomElement(['A', 'B'])public function load(ObjectManager $manager): void
{
$faker = Factory::create('fr_FR');
// Création de catégories
$categories = [];
for ($i = 0; $i < 5; $i++) {
$category = new Category();
$category->setName($faker->word());
$category->setDescription($faker->sentence());
$manager->persist($category);
$categories[] = $category;
}
// Création de produits
for ($i = 0; $i < 50; $i++) {
$product = new Product();
$product->setName($faker->productName());
$product->setDescription($faker->text(200));
$product->setPrice($faker->randomFloat(2, 10, 500));
$product->setStock($faker->numberBetween(0, 100));
$product->setCategory($faker->randomElement($categories));
$manager->persist($product);
}
$manager->flush();
}
Cause : Bundle pas installé
Solution :
composer require --dev doctrine/doctrine-fixtures-bundle
Cause : Nom de référence incorrect
Solution : Utiliser des constantes
Cause : Mauvais ordre de chargement
Solution : Implémenter DependentFixtureInterface
Cause : Trop d'objets en mémoire
Solution : Flush par batch de 100
// MAUVAIS - Garde tout en mémoire
for ($i = 0; $i < 10000; $i++) {
$entity = new Entity();
$manager->persist($entity);
}
$manager->flush(); // Boom ! đ„
// BON - Flush par batch
for ($i = 0; $i < 10000; $i++) {
$entity = new Entity();
$manager->persist($entity);
// Tous les 100 objets
if ($i % 100 === 0) {
$manager->flush();
$manager->clear(); // LibÚre la mémoire
}
}
$manager->flush(); // Sauvegarde finale
src/DataFixtures/ âââ UserFixtures.php # Utilisateurs (en premier) âââ CategoryFixtures.php # CatĂ©gories âââ ProductFixtures.php # Produits (dĂ©pend des catĂ©gories) âââ OrderFixtures.php # Commandes (dĂ©pend des users et produits) âââ AppFixtures.php # Fixture globale (optionnelle)
# Charger les fixtures php bin/console doctrine:fixtures:load # Ajouter sans supprimer php bin/console doctrine:fixtures:load --append # Mode verbose (détaillé) php bin/console doctrine:fixtures:load -v # Sans confirmation php bin/console doctrine:fixtures:load --no-interaction
# Valider le schéma php bin/console doctrine:schema:validate # Voir les entités php bin/console doctrine:mapping:info # Exécuter du SQL php bin/console doctrine:query:sql "SELECT COUNT(*) FROM user"
Entités : User, Article, Comment
class UserFixtures extends Fixture
{
private UserPasswordHasherInterface $hasher;
public function __construct(
UserPasswordHasherInterface $hasher
) {
$this->hasher = $hasher;
}
public function load(ObjectManager $manager): void
{
$user = new User();
$password = $this->hasher->hashPassword(
$user,
'password123'
);
$user->setPassword($password);
$manager->persist($user);
$manager->flush();
}
}
public function load(ObjectManager $manager): void
{
// Données selon l'environnement
if ($_ENV['APP_ENV'] === 'dev') {
// Beaucoup de données pour le dev
$this->createManyEntities($manager, 1000);
} else {
// Peu de données pour les tests
$this->createManyEntities($manager, 10);
}
}
use Symfony\Component\HttpFoundation\File\UploadedFile; $imagePath = '/path/to/image.jpg'; $uploadedFile = new UploadedFile($imagePath, 'image.jpg', 'image/jpeg', null, true); $product->setImage($uploadedFile);
Questions ? N'hésitez pas !