Archives Wild Code School
Symfony

19 - Symfony : EntityType

Quête 22 sur 35 · 1 image archivée

Objectifs

  • ✅ Découvrir l'EntityType
  • ✅ Savoir l'implémenter

Pré-requis

​ Avoir terminé la quête

Quêtes liées
title-book
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 que qu'administrateur, je souhaite ajouter des acteurs à une série

Doing 🏗️

mise en place de l'EntityType

Done ✅

création de l'entité Actor

Tu as déjà découvert les formulaires dans Symfony, et quelques-uns des types de champs disponibles (TextType, ChoiceType, etc.). Dans cette quête, tu vas en découvrir un nouveau, l’EntityType.

Sommaire

🤔 EntityType : qu'est-ce que c'est ?

Il arrive souvent que tu aies besoin de charger dans un formulaire, les données d'une autre entité (dans l'exemple ci-dessus, la liste des catégories dans un formulaire d'ajout de série). Symfony embarque cette fonctionnalité nativement, grâce aux EntityType. En réalité, l’EntityType n’est rien d’autre qu’un ChoiceType dans lequel des valeurs par défaut sont déjà remplies, ces valeurs provenant de la BDD et étant chargées via Doctrine.

↗
Documentation officielle

Regarde pour l’instant la partie “Basic Usage”.

symfony.com

🏗 Implémenter un EntityType

Mise en place du formulaire

Tu vas maintenant reprendre le projet Wild Séries. Dans l’entité Program, tu as une propriété $actors qui a été ajoutée lors de la quête précédente. Cette propriété est au pluriel car une série est reliée à plusieurs acteurs. Dans une autre quête, tu as généré le CRUD associé à l’entité Program. Malheureusement pour toi, l’ajout de la relation entre Actor et Program a eu lieu après la génération du CRUD. La classe ProgramType n’est donc plus complète. Mais pas de panique, cette quête est conçue pour la mettre à jour. Dans ProgramType, tu vas donc ajouter un champ ”actors” de type EntityType comme ci-dessous :

php
// add the 2 use
use App\Entity\Actor;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
// here, your form (title, summary…)
$builder->add('actors', EntityType::class, [
    'class' => Actor::class,
    'choice_label' => 'name',
    'multiple' => true,
    'expanded' => false,
]);

Tu remarques que l’EntityType nécessite 2 paramètres obligatoires : class : permet d’indiquer quelle entité est reliée au champ actors. Au niveau de l’entité Program, $actors devra en effet être un objet de type Actor.

Le but de l’EntityType est d’aller récupérer en base de données toutes les données reliées à l'Entity Actor (via Doctrine) et ensuite afficher ces données dans un select (par défaut). Or, l’entité Actor contient deux champs (id et name). Pour savoir lequel de ces deux champs il doit afficher dans le select, Symfony se base sur le choice_label, qui doit donc correspondre au nom d’une des propriétés de l’entité Actor.

Info

Quand tu écris 'choice_label' => 'name' c’est en réalité le getter getName() qui est appelé. Pour afficher quelque chose de plus complexe dans le select (par exemple concaténer les valeurs de plusieurs champs de la BDD), tu peux créer un getter personnalisé, qui se chargera d’effectuer la mise en forme plus complexe, puis l’appeler dans le choice_label. Comme par exemple, mettre 'choice_label' => 'selector' qui renverrait vers la méthode :

php
public function getSelector(): string
{
  return $this->getId() . ' - ' . $this->getName();
}
↗
Définition du choice_label

Tu trouveras un récapitulatif des différentes manières de définir le choice_label : par un string correspondant au nom d’un getter, mais également via une fonction anonyme (callable).

symfony.com

Si tu vas sur ta page d’édition ou de création d’une série, tu peux voir qu’un nouveau champ ”actors” est apparu sous forme de liste déroulante.

Il existe de nombreux paramètres supplémentaires qui sont quant à eux optionnels :

  • expanded et multiple : ces deux paramètres (qui existent également dans le ChoiceType) prennent true ou false. Par défaut, ils sont tous les deux à false et les données de catégories sont affichées sous la forme d’un select. Mais tu pourrais très bien vouloir les afficher sous la forme de boutons radios ou de checkboxes, en fonction de tes besoins. Ce tableau de la documentation officielle résume bien les 4 cas de figures, en fonction des valeurs de expanded et multiple.

  • query_builder : Ici, par défaut, la requête effectuée pour récupérer les informations en base de données est un simple SELECT * FROM category (toutes les catégories sont affichées). Or, parfois, tu aimerais trier tes résultats (ORDER BY), n’en afficher qu’une partie (LIMIT), ou n’en afficher que certaines lignes selon une condition (WHERE). L’option query_builder permet de personnaliser la requête SQL qui sera exécutée pour récupérer les valeurs en BDD. Tu peux regarder la documentation à ce sujet, mais tu verras le fonctionnement des requêtes personnalisées un peu plus tard.

Attends une minute, une série peut être associée à plusieurs acteurs, et un acteur peut être associé à plusieurs séries, une simple liste déroulante classique n’est donc pas la meilleure manière d’afficher ce sélecteur. Tu dois donc rajouter les propriétés expanded et multiple à true pour avoir une interface cohérente avec nos besoins. Rafraîchis ta page, cette fois-ci tu dois voir apparaître des cases à cocher multiples. Il serait aussi possible de configurer expanded à false et multiple à true pour avoir une liste déroulante à choix multiple, mais ce type de champ de formulaire est un peu moins utilisé de nos jours.

Tu peux créer une nouvelle série et cocher à loisir autant d’acteurs que tu le souhaites et cliquer sur “Save” ce qui va enregistrer en base de données ta série et te rediriger sur la page de listing des séries.

Ensuite, retourne sur la page d’édition de la série que tu viens de modifier, que constates-tu ? Ta série est bien saisie, mais pas les acteurs que tu viens de sélectionner. Que s’est il passé ? Tu peux trouver la réponse dans cet article: Saving the Inverse Side of a ManyToMany avec la solution à ton problème dans le chapitre d’après : Form by_reference + Adder and Remover

↗
Saving the Inverse Side of a ManyToMany

Pourquoi le côté “inverse” n'est-il pas sauvegardé ?

symfonycasts.com
↗
Form by_reference + Adder and Remover

La solution à ton problème un peu plus bas dans ta page.

symfonycasts.com

📜 Traitement du formulaire

Côté traitement du formulaire, tu n’as rien à modifier ! Mais comment cela est-il possible ? Reprends un peu le déroulement du traitement de formulaire dans Symfony :

  • Le formulaire est soumis, l’objet Request est récupéré au niveau du contrôleur.

  • La méthode $form->handleRequest($request) hydrate automatiquement l’objet Program avec les données saisies dans le formulaire (et donc contenues dans $request).

  • La méthode setActors() de Program est donc appelée et attend un tableau d’objets Actor. Or le champ actors du formulaire est un EntityType, relié justement à la classe Actor. Symfony arrive donc à faire automatiquement le lien et à hydrater correctement l’objet Program.

👓 Et la vue dans tout ça ?

Côté Twig, là encore, tu n’as absolument rien à faire. Tu avais indiqué que tu souhaitais simplement afficher ton formulaire. Les champs que tu ajoutes du côté de la classe ProgramType se mettent donc automatiquement à jour dans ta vue.

Info

Si tu souhaitais faire des mises en page un peu plus complexes au niveau de ton formulaire, tu serais sans doute amené à ajouter quelques lignes dans ce fichier Twig, mais tu verras cela dans une future quête. Pour un affichage simple, tout se fait automatiquement !

💪 Challenge

Ajoute un champ Actors

En suivant les instructions de la quête, fais en sorte que le champ actors apparaisse sous forme d’une suite de cases à cocher sur le formulaire d’ajout d’une nouvelle série. Il doit afficher les noms des acteurs contenus dans la base.

🧐 Critères de validation

  • Le formulaire d’ajout d’une série affiche un champ acteur (EntityType),
  • Ce champ apparaît sous la forme de cases à cocher.
  • Lorsque l’on ajoute un acteur à une série, celui-ci est bien relié à la série en BDD.
  • Les acteurs s'affichent sur la page de la série.
  • Le code est disponible sur un repository GitHub, avec une branche correspondant à cette quête.