09 - Symfony : Les fixtures avancées avec jointures
Objectifs
- ✅ Comprendre le principe des dépendances entres les fixtures
- ✅ Partager des objets entre fixtures
Pré-requis
Avoir terminé la quête
Introduction
Tu sais aujourd'hui créer des fixtures pour des entités n'ayant pas de dépendances. C'est ce que tu as appliqué pour créer des catégories dans ton Wild Series. Avec cette quête, tu vas apprendre à créer des fixtures comportant des dépendances.
Sommaire
Ajouter des références aux fixtures
Pour découvrir le principe de fixtures ayant des dépendances, nous allons créer des fixtures de séries (Program). Tu peux également appliquer les exemples de cette quête dans ton wild series.
Tu as déjà vu, dans une précédente quête, comment créer des fixtures pour les catégories.
Il s'agissait de fixtures sans dépendance car la table catégorie ne contient pas de clé étrangère.
Pour une série, c'est une autre histoire ! En effet, pour créer une nouvelle série (entité Program), nous aurons besoin d'avoir dans la base des catégories.
Pour cela, tu vas devoir modifier légèrement tes fixtures concernant les Category.
L'objectif est que chaque catégorie créée soit mise de côté pour être réutilisée pour d'autres fixtures.
Tu vas donc ajouter une référence pour chaque objet créé.
<?php
namespace App\DataFixtures;
use App\Entity\Category;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class CategoryFixtures extends Fixture
{
public const CATEGORIES = [
'Action',
'Aventure',
'Animation',
'Fantastique',
'Horreur',
];
public function load(ObjectManager $manager)
{
foreach (self::CATEGORIES as $categoryName) {
$category = new Category();
$category->setName($categoryName);
$manager->persist($category);
$this->addReference('category_' . $categoryName, $category);
}
$manager->flush();
}
}
Nous avons ajouté ici une référence pour chaque catégorie créée à l'aide de
$this->addReference('category_' . $categoryName, $category);
Attention, il est préférable que le nom de la référence ne contienne pas d'espace pour des raisons de lisibilité et de cohérence. Lors des prochaines quêtes, tu seras amené à utiliser un référencement numérique.
Le premier paramètre est le nom que l'on décide de donner à la référence (on utilise la clé du tableau pour avoir une référence différente pour chaque catégorie créée). Le second paramètre est l'objet fraichement créé.
Ceci permet de mettre de côté cet objet $category afin de pouvoir l'utiliser quand, par exemple, nous écrirons les fixtures d'un Program (qui a besoin d'un objet Category pour être créé).
En suivant cet exemple, nous avons créé ces références :
| Référence | Valeur |
|---|---|
| category_Action | Objet Category ayant pour name "Action" |
| category_Aventure | Objet Category ayant pour name "Aventure" |
| category_Animation | Objet Category ayant pour name "Animation" |
| category_Fantastique | Objet Category ayant pour name "Fantastique" |
| category_Horreur | Objet Category ayant pour name "Horreur" |
Vérifie que tout fonctionne en jouant les fixtures
# symfony console doctrine:fixtures:load
# Ou pour aller plus vite :
symfony console d:f:l
Tu devrais toujours avoir les mêmes catégories dans ta base.
Maintenant tu vas enfin pouvoir créer le fichier de fixtures pour insérer des séries dans la base de données.
Utiliser des références existantes dans les fixtures
Pour pouvoir créer des fixtures de Program, nous avons créé au préalable des catégories. Sans cela, nous aurions été dans l'incapacité d'instancier correctement un nouveau Program qui est dépendant d'une catégorie.
Nous allons avoir besoin de 2 nouveaux concepts.
- Indiquer à l'ORM que Program est dépendant de fixtures existantes
- Indiquer à l'ORM que Program est dépendant de fixtures existantes et donc qu'il doit les insérer en base après
Tu peux commencer par créer ProgramFixtures à l'aide de symfony console make:fixtures
Indiquer à l'ORM que Program est dépendant de fixtures existantes
Pour celà, nous allons devoir implémenter l'interface DependentFixtureInterface dans ProgramFixtures. Cette interface nous imposera d'implémenter la méthode getDependencies().
Cette méthode devra retourner un tableau comportant le FQCN de chaque classe de fixtures dont Program dépend.
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class ProgramFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager)
{
}
public function getDependencies()
{
// Tu retournes ici toutes les classes de fixtures dont ProgramFixtures dépend
return [
CategoryFixtures::class,
];
}
}
Sharing Objects between Fixtures
Utiliser les références existantes
La dernière étape consistera à récupérer les objets de type Category mis de côté par Doctrine pour les utiliser dans notre ProgramFixtures.
De la même façon qu'il existait une méthode pour mettre un objet de côté :
$this->addReference($referenceName, $object);
Il existe aussi une méthode pour récupérer cet objet mis de côté :
$this->getReference($referenceName, FQCN);
Ainsi, dans notre application,
$this->getReference('category_Action', Category::class);
serait égale à un objet de type Category ayant pour name "Action"
Tu pourras donc utiliser cette méthode, pour récupérer les objets préalablement créés et les ajouter dans ton program.
Pour expérimenter, crée un seul program dans ProgramFixtures en n'oubliant pas de lui attribuer une catégorie.
Clique pour voir la solution|||php|||Essaye de créer toi même cette fixture avant de regarder la solution !|||0|||Hide
<?php
namespace App\DataFixtures;
use App\Entity\Program;
use App\Entity\Category;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class ProgramFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager)
{
$program = new Program();
$program->setTitle('Walking dead');
$program->setSynopsis('Des zombies envahissent la terre');
$program->setCategory($this->getReference('category_Action', Category::class));
$manager->persist($program);
$manager->flush();
}
public function getDependencies()
{
return [
CategoryFixtures::class,
];
}
}
Vérifie que tout fonctionne en jouant les fixtures
# symfony console doctrine:fixtures:load
# Ou pour aller plus vite :
symfony console d:f:l
Doctrine exécute les fixtures par ordre alphabétique. Dans notre exemple, Category arrivant avant Program, nous aurions pu ne pas implémenter DependantFixtureInterface. Mais on évite de compter sur la chance !
Loading the Fixture Files in Order
💪 Challenge
Alimente ton Wild Séries
Maintenant que les fixtures n'ont plus de secret pour toi, profite de ce challenge pour insérer des fixtures pour toutes les données de ton application, à savoir :
- Des catégories (au moins 5)
- Des programmes (au moins 5 par catégorie)
💡 Tu peux écrire les 25 fixtures de l'entité Program les unes sous les autres ou utiliser un tableau comme tu l'as fait pour les catégories mais avec des index cette fois. Par exemple :
phpconst PROGRAMS = [ [ 'title' => 'Walking Dead', 'synopsis' => 'Des zombies envahissent la terre.', 'category' => 'category_Action', ], [ 'title' => 'Titre 2', 'synopsis' => 'some texte', 'category' => 'category_Action', ], ];Nous verrons dans une prochaine quête comment automatiser et générer du faux contenu en masse.
🧐 Critères de validation
- Lorsque
symfony console doctrine:fixtures:loadest exécuté, il n'y a pas de message d'erreur, - La navigation montre que toutes les données ont bien été insérées
- Le code est disponible sur un repository GitHub, avec une branche correspondant à cette quête.