15 - Symfony : Générer un CRUD
## Objectifs
- ✅ Générer un CRUD
- ✅ Comprendre ce qui est généré
- ✅ Modifier le CRUD pour l'adapter à tes besoins
Pré-requis
Avoir terminé la quête
Introduction
User stories 📋
en tant que visiteur, je souhaite récupérer les données d'une série
en tant que visiteur, je souhaite récupérer la liste des séries
en tant que contributeur, je souhaite ajouter une série
In progress 🤸
en tant qu'administrateur, je souhaite ajouter une saison
en tant qu'administrateur, je souhaite éditer une saison
en tant qu'administrateur, je souhaite supprimer une saison
en tant qu'administrateur, je souhaite afficher les détails d'une saison
en tant qu'administrateur, je souhaite ajouter un épisode
en tant qu'administrateur, je souhaite éditer un épisode
en tant qu'administrateur, je souhaite supprimer un épisode
en tant qu'administrateur, je souhaite afficher les détails d'un épisode
Doing 🏗️
Done ✅
en tant qu'administrateur, je souhaite créer une catégorie
en tant que visiteur, je souhaite afficher les séries par catégories
en tant que visiteur, je souhaite visualiser la fiche d'une série
À ce stade du projet, tu dois avoir quelques pages, associées à des routes, qui affichent un peu de texte, des entités qui représentent les piliers de ton site, mais c'est tout. On est encore loin de notre but. Mais attends la fin de cette quête, tu vas faire un pas de géant !
Dans cette quête, nous allons parler des pages pour créer, lire, mettre à jour et supprimer nos entités. Ces quatre actions redondantes sont souvent regroupées sous l'acronyme que tu connais sûrement déjà : CRUD et qui signifie Create Read Update Delete. Ce sont les 4 moments-clés du cycle de vie d'une entité.
Tout ça dans une seule quête ?!?
Oui, mais rassure-toi, Symfony est là pour t'aider.
Sommaire
La génération du CRUD
Tu disposes déjà de nombreuses entités. Il te faut maintenant générer leurs CRUD respectifs, ne perdons pas de temps, c'est parti !
Le Maker Bundle te fournit une commande qui permet de générer tous les fichiers dont tu as besoin en une seule commande : make:crud.
💻 Entre la commande suivante dans le terminal :
symfony console make:crud
La console va te demander de renseigner le nom de l'entité pour laquelle tu souhaites générer l'ensemble du CRUD.
La première entité qui t'intéresse est : Season.
Tu obtiens alors le résultat suivant :

👀 Tu peux constater que Symfony n'a pas chômé. Il a créé 8 fichiers que l'on peut classer en 3 catégories :
- Un contrôleur (SeasonController.php) avec les méthodes
index,new,show,editetdelete, ainsi que leurs routes associées dans les attributs. Note l'importance de l'ordre dans lesquelles ces méthodes sont déclarées (/newavant/{id}). Ce controller est semblable à ceux que tu crées manuellement. Tu as d'ailleurs déjà créé ta propre méthodenew()similaire dansProgramControlleretCategoryControllerlors de la quête précédente. - Une classe de formulaire, src/Form/SeasonType.php, qui permet de générer le formulaire correspondant à ton entité
Season. - Des vues twig (edit, index, new, show, _form et _delete_form) dans le dossier templates/season.
Pourquoi avoir une vue _form et _delete_form?
Si on y pense, le formulaire pour l'ajout et l'édition d'une série est le même. Donc plutôt que de se répéter, on va créer une vue indépendante qui sera appelée dans les vues edit.html.twig et new.html.twig.
Ces vues ne font que manipuler un objet permettant de créer et afficher un formulaire, dans notre cas le formView de SeasonType qui est passé au contexte de la vue par le controller (comme tu l’as vu lors de la quête précédente) pour afficher le formulaire correspondant à l'entité (ici Season).
D'accord, mais les vues _form et _delete_form sont-elles préfixées par un underscore ?
Comme dit plus haut, les vues _form et _delete_form sont des vues partielles, destinées à être incluses dans d'autres vues. Elles ne seront jamais appelées directement dans la méthode render de nos contrôleurs. C’est d’ailleurs la même convention pour le nommage des fichiers SCSS.
On utilise souvent des underscores devant ce type de vue, afin de pouvoir repérer d'un coup d'oeil dans l'arborescence de fichiers, les vues destinées à être importées.
Allons voir maintenant ce qu'a fait Symfony. 💻 Rends-toi sur l'URL suivante : http://localhost:8000/season/. 👀 Sur cette page, tu constates que Symfony a généré tout ce qu'il te faut pour lister tes saisons, ainsi que des liens pour aller en créer de nouvelles ou mettre à jour celles déjà existantes. Teste ces liens !
💻 Rends-toi sur la page de création d'une saison : http://localhost:8000/season/new Que constates-tu ?
La liste déroulante te permettant de choisir la série associée à la saison affiche l'
idduprogram: un peu compliqué à utiliser ce formulaire...
Eh oui, Symfony ne peut pas tout faire. Tu as normalement déjà rencontré ce problème lors du challenge de la quête précédente lorsque tu as voulu afficher le formulaire pour ajouter une série. Tu as peut-être résolu le souci sans trop te poser de questions, alors entrons un peu plus dans le détail du problème.
Que se passe-t-il exactement ? Ici, dans le formulaire d’ajout/édition d’une saison, tu souhaites afficher un champ de type select permettant de lister toutes les séries en base de données, afin d’en relier une à cette saison.
Dans le formulaire SeasonType, le champ program correspond à la propriété $program de ton entité Season. Cette propriété a pour valeur un objet de type Program.
Donc, lorsque Symfony tente de lister les différentes séries dans le select, il affiche par défaut l'id de l'objet de type Program pour chaque <option> du <select>.
Dans cette situation, il faut modifier la configuration du champ program dans la classe App\Form\SeasonType afin d'indiquer au formulaire que c'est la propriété title de l'entité Program qui sera affichée dans le select.
💻 Remplace ['choice_label' => 'id'] par ['choice_label' => 'title'] (comme tu l'as fait pour le champ category du ProgramType lors du challenge de la quête précédente).
Lors d'une quête future tu verras d'autres options plus poussées pour représenter une entité dans un formulaire.
👀 Le résultat devrait ressembler à ça :

Une fois la modification effectuée, tu peux tester les fonctionnalités du CRUD lié à ton entité Season en ajoutant/éditant/supprimant des saisons à/d' une série.
Même si la commande symfony console make:crud génère automatiquement les fichiers pour nous, il faut absolument que tu saches réaliser un crud "à la main" (en utilisant Doctrine et les managers). C’est la raison pour laquelle tu l’as fait toi-même lors de la quête précédente. La commande make:crud est basique et ne te permettra pas de gérer des cas complexes comme la génération de formulaires dynamiques qui s’actualisent en fonction des interactions de l’utilisateur (ex: au clic sur un radio button, affichage de champs supplémentaires, etc.).
Quand on génère un CRUD, le code généré peut correspondre à plusieurs User Stories différentes (une par action du CRUD). On ne tolère habituellement que le code correspondant à sa US en cours. Pour éviter de générer le code via la console et de l'effacer tout de suite après afin de respecter le périmètre de sa US, on peut tolérer la génération du code de tout le CRUD par Symfony. Mais attention, ce code généré n'est pas finalisé (il manque les validations côté serveur, la mise en page, le CSS, etc.). La première US qui a besoin d'un CRUD le génère donc, mais ne modifiera QUE le code touchant à cette US (par exemple, si la US est de faire une page d'ajout, on génère tout le CRUD, donc aussi l'edit et le read) mais dans ce cas on n'y touche pas, et il ne sera modifié que lorsqu'on travaillera ces US. Le but ici est de garder le meilleur compromis possible entre respect du SCRUM et les outils mis en place par le framework pour te faire gagner du temps.
💪 Challenge
Du CRUD ! Du CRUD ! Du CRUD !
Génère les CRUD pour les entity Season et Episode.
Puis enregistre les manipulations suivantes :
- Crée plusieurs saisons (au moins 4),
- Affiche toutes les saisons,
- Modifie plusieurs saisons (au moins 2),
- Efface plusieurs saisons (au moins 2),
- Crée plusieurs épisodes (au moins 4)
- Affiche tous les épisodes,
- Modifie plusieurs épisodes (au moins 2),
- Efface plusieurs épisodes (au moins 2),
Tu peux penser que les méthodes show() du SeasonController et EpisodeController font doublon avec les méthodes showSeason() et showEpisode() créées dans le ProgramController lors de quêtes précédentes et c'est bien légitime.
Cependant, et tu le verras plus tard, les CRUDs nouvellement générés seront exclusivement réservés à l'administration de ton site, et, par conséquent, les pages liées aux CRUDs ne seront pas visibles par un visiteur contrairement aux routes showSeason() et showEpisode().
Critères de validation
- Le CRUD est généré pour l’entité Season.
- L’entité
Seasondispose des actions de lecture, écriture et suppression. - Le CRUD est généré pour l’entité Episode.
- L’entité
Episodedispose des actions de lecture, écriture et suppression. - Les routes sont cohérentes et fonctionnelles.
- Le CRUD agit bien avec la BDD (exemple : insérer une saison depuis
http://localhost:8000/season/new). - Le code est disponible sur un repository GitHub, avec une branche correspondant à cette quête.