Archives Wild Code School
Symfony

09 - Symfony : Les fixtures avancées avec jointures

Quête 12 sur 35

Objectifs

  • ✅ Comprendre le principe des dépendances entres les fixtures
  • ✅ Partager des objets entre fixtures

Pré-requis

Avoir terminé la quête

Quêtes liées
title-book
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
<?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

php
$this->addReference('category_' . $categoryName, $category);
Important

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

bash
# 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.

Bravo

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
<?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,
        ];
    }


}

↗
Doc officielle Symfony Fixtures

Sharing Objects between Fixtures

symfony.com

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é :

php
$this->addReference($referenceName, $object);

Il existe aussi une méthode pour récupérer cet objet mis de côté :

php
$this->getReference($referenceName, FQCN);

Ainsi, dans notre application,

php
$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.

hidden
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

bash
# symfony console doctrine:fixtures:load
# Ou pour aller plus vite :
symfony console d:f:l
Info

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 !

↗
SymfonyCast DependantFixtureInterface
symfonycasts.com
↗
Doc officielle Symfony Fixtures

Loading the Fixture Files in Order

symfony.com

💪 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 :

php
const 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:load est 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.