PRÉSENTATION DU COURS

Aller plus loin avec les formulaires

Comprendre les options et aller plus loin avec les formulaires

Aller plus loin avec les fomulaires de Symfony

Avant toute chose, nous avons un problème, notre formulaire est dégeulasse.

Pour palier à ça, on peut aller dans le fichier config/packages/twig.yaml et ajouter la dernière ligne :

twig:
    paths: ['%kernel.project_dir%/templates']
    debug: '%kernel.debug%'
    strict_variables: '%kernel.debug%'
    form_themes:
        - bootstrap_4_layout.html.twig

Et là, c'est de suite plus agréable à l'oeil.

C'est un thème directement intégré à Symfony pour avoir un formulaire bootstrap rapidement (si vous avez installé bootstrap)

Pour en savoir plus pour les thèmes de formulaires, je vous laisse aller voir dans la (documentation symfony correspondante)[https://symfony.com/doc/current/form/form_themes.html] (Nous ne le verrons pas dans ce cours)

Type de champs

Comme nous avons pu le voir dans notre formulaire, les types sont actuellement devinés par symfony, ce qui n'est pas une situation idéale, car il peut être amené à faire des erreurs (Partez du principe que Symfony est con comme ses iep quand il sagit de réfléchir comme un humain).

Les type de champs vont se transformer en différents éléments html :

  • Input text
  • Input checkbox
  • Input number
  • Select
  • Multi select
  • Textarea
  • Et bien d'autres encore...

Pour faire ça il rendez vous dans un des fichiers dans le dossier form.

Pour l'instant ça ressemble à ça : (attention classe d'exemple fictive de mon coté pour l'exemple)

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('rating')
            ->add('jelly')
        ;
    }

Hé bien figurez vous que add de builder peut prendre jusqu'à trois arguments :

  • Le nom du champ
  • Le type de champ
  • Les options du champ

Tous les types de champ se retrouvent dans le namespace suivant : Form\Extensions, donc pour ceux qui ont phpstorm c'est cool on a toutes les options par l'autocomplete !

Par contre pour les autres, vous avez choisi d'être déviant vous vous débrouillerez donc seul avec la documentation 😏 (je sais que c'est vous qui êtes du genre à recommencer le projet à chaque exercice, me dites pas le contraire)

Vous pouvez retrouver tous les types de formulaire dans la documentation

Donc par exemple, si on définissait les champs comme ceci :

  • Name est un input text
  • Rating est un select avec des options
  • Jelly est un texte long servant à décrire votre sentiment de jalousie par rapport aux gens qui ont classe même en dansant sur du Ricky Martin

Ça nous donnerait donc ça :

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('rating', ChoiceType::class, [ // on ajoute un argument pour faire parvenir les choix, sinon le select sera vide
                'choices'  => [
                    'awful' => 0,
                    'eatable at best' => 1,
                    'i did not threw up' => 2,
                    'Decent dog food' => 3,
                    'Yes' => 4,
                    'If you do not finish your plate i will eat it too' => 5,
                ],
            ])
            ->add('jelly', TextareaType::class)
        ;
    }

Modifiez vos champs avec ce que vous voulez, et affichez votre formulaire, tout devrait être dans le bon format !

Par contre attention, si le format n'est pas compatible avec le champ défini dans votre entité, vous aurez une erreur.

Débugger son formulaire

Quel formidable opportunité pour parler du debugger 😏

Symfony a une partie formulaire dans son debugger, pour vous permettre de voir tout ce qu'il y a pour chaque champ du formulaire affiché, ainsi que ses options etc...

Tout ça se passe dans la barre du profiler au niveau du petit icon clipboard ou la section form si vous êtes déjà dans le profiler

Autres options

Vous pouvez définir un grand nombre de choses dans les options de champ, en fonction du type de celui ci.

Vous allez retrouver tout ce qui est possible dans la documentation des types, eppluchez la donc avec soin !

Pour vous résumer, dans la pluspart des champs, vous pouvez ajouter les choeses suivantes :

  • Label
  • Classes css
  • désactiver le champ
  • Faire en sorte que ce champ soit requis

Faites bien le tour de chaque type de champ que vous utilisez, ça vous sera bien utile !

Récupérer des éléments depuis une autre entité et les afficher dans un select

Comme nous avons pu le voir avant, certaines entités peuvent avoir des relations, il est donc normal de pouvoir le refléter dans les formulaires.

C'est pour cela qu'existe le type EntityType::class qui va vous permettre de lister dans une liste déroulantes les éléments de la relation (essentiellement un findAll sur cette entité, et le resultat se retrouve dans un select)

Dans ce type, plusieurs options sont importantes :

  • class : va correspondre à l'entité de l'autre coté de la relation
  • choice_label : Propriété de l'entité cible à afficher ou fonction pour gére l'affichage
  • placeholder : Valeur par défaut quandle champ est null

En soit, cela va se former de cette manière là :

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('rating', ChoiceType::class, [ // on ajoute un argument pour faire parvenir les choix, sinon le select sera vide
                'choices'  => [
                    'awful' => 0,
                    'eatable at best' => 1,
                    'i did not threw up' => 2,
                    'Decent dog food' => 3,
                    'Yes' => 4,
                    'If you do not finish your plate i will eat it too' => 5,
                ],
            ])
            ->add('jelly', TextareaType::class)
            ->add('author', EntityType::class, [
                'class' => User::class,
                'choice_label' => function(User $user) {
                    return sprintf('(%d) %s', $user->getId(), $user->getEmail());
                },
                'placeholder' => 'Choose an author'
            ])
        ;
    }

ou comme ça avec une simple propriété

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('rating', ChoiceType::class, [ // on ajoute un argument pour faire parvenir les choix, sinon le select sera vide
                'choices'  => [
                    'awful' => 0,
                    'eatable at best' => 1,
                    'i did not threw up' => 2,
                    'Decent dog food' => 3,
                    'Yes' => 4,
                    'If you do not finish your plate i will eat it too' => 5,
                ],
            ])
            ->add('jelly', TextareaType::class)
            ->add('author', EntityType::class, [
                'class' => User::class,
                'choice_label' => 'email',
                'placeholder' => 'Choose an author'
            ])
        ;
    }

Inbrique un formulaire dans un autre

Dans certains cas, il peut être intéressant d'avoir un formulaire en contenant un autre, dans ce cas là, rien de plus simple, utilisez simplement la classe de votre FormType !

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('rating', ChoiceType::class, [ // on ajoute un argument pour faire parvenir les choix, sinon le select sera vide
                'choices'  => [
                    'awful' => 0,
                    'eatable at best' => 1,
                    'i did not threw up' => 2,
                    'Decent dog food' => 3,
                    'Yes' => 4,
                    'If you do not finish your plate i will eat it too' => 5,
                ],
            ])
            ->add('jelly')
            ->add('author', EntityType::class, [
                'class' => User::class,
                'choice_label' => 'email',
                'placeholder' => 'Choose an author'
            ])
            ->add('user', UserType::class) // ici on utilise une autre partie de notre formlaire
        ;
    }

Désormais votre formulaire contiendra aussi ce formulaire dans une partie "user", les données seront renvoyées en même temps que l'autre formulaire.

Utiliser des queries pour filtrer les résultats

Dans un premier temps, nous allons devoir récupérer le repository pour pouvoir faire de queries (Pas obligé de passer par les entités !)

Comme pour toutes les autres choses, en réalité les formulaires sont des...services, vous allez donc pouvoir accéder à toutes les autres services de Symfony depuis votre classe de formulaire !

Comme nous l'avons vu plutôt, nous ne pouvons pas faire comme dans les controller et demander des dépendences à chaque méthode, nous sommes cantonné à faire ça dans la fonction construct.

Nous allons donc récupérer seulement les utilisateurs étant le rôle auteur :

 private $userRepository;

public function __construct(UserRepository $userRepository)
{
    $this->userRepository = $userRepository;
}

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', TextType::class)
            ->add('rating', ChoiceType::class, [ // on ajoute un argument pour faire parvenir les choix, sinon le select sera vide
                'choices'  => [
                    'awful' => 0,
                    'eatable at best' => 1,
                    'i did not threw up' => 2,
                    'Decent dog food' => 3,
                    'Yes' => 4,
                    'If you do not finish your plate i will eat it too' => 5,
                ],
            ])
            ->add('jelly')
            ->add('author', EntityType::class, [
                'class' => User::class,
                'choice_label' => 'email',
                'placeholder' => 'Choose an author'
                'choices' => $this->userRepository->findAllAuthors(), // on vient définir la query qui renvoie tous les choix possibles
            ])
        ;
    }

De cette façon, seulement les résultat de cette query sera affichée à l'utilisateur dans la liste déroulante !

Par contre, vous êtes obligé d'utiliser le repository lié à la classe que vous utilisez dans ce champ ( ex : On utiluse UserRepository pour l'entité User, sinon ça ne marche pas)

Conclusion

Vous en savez désormais un peu mieux sur les formulaire,et notament comment récupérer des informations directement depuis les Entités.

Vous allez désormais pouvoir vous exercer dans le superbe exercice qui suit 😏

Envie de discuter du contenu ?

logo twitter @GarnierKristen