Les formulaires

Les formulaires sont une partie importante des applications Web.

Ils permettent à nos utilisateurs d’interagir avec notre site.

Nous allons ici créer des commentaires pour nos articles.

Pour cela, un utilisateur va devoir Donner son nom, son email et bien sûr son commentaire.

Commençons par le HTML

Nous allons pour l’instant afficher nos commentaires en simple HTML, dans sur la page d’un article.

Intégrez le code HTMl ci-dessous dans la page d’un article.

<hr>

<div class="container">
    <div class="row">
        <h3 class="col-lg-8 col-md-10 mx-auto">2 Comments</h3>
    </div>
    
    <!-- Comments Form -->
    <div class="col-lg-8 col-md-10 mx-auto">
        <div class="card my-4">
            <h5 class="card-header">Leave a Comment:</h5>
            <div class="card-body">
                <form>
                    <div class="form-group">
                        <label for="name">Name</label>
                        <input id="name" class="form-control form-control-sm" type="text">
                    </div>
                    <div class="form-group">
                        <label for="email">Email</label>
                        <input id="email" class="form-control form-control-sm" type="email">
                    </div>
                    <div class="form-group">
                        <label for="comment">Comment</label>
                        <textarea id="comment" class="form-control form-control-sm" rows="3"></textarea>
                    </div>
                    <button type="submit" class="btn btn-secondary">Submit</button>
                </form>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="media mb-4 mt-4 col-lg-8 col-md-10 mx-auto">
            <div class="media-body">
                <h5 class="mt-0">John Doe <small>2020-03-19</small></h5>
                <blockquote>Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.</blockquote>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="media mb-4 mt-4 col-lg-8 col-md-10 mx-auto">
            <div class="media-body">
                <h5 class="mt-0">Foo Bar <small>2020-04-19</small></h5>
                <blockquote>Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.</blockquote>
            </div>
        </div>
    </div>
</div>

Avec ça, vous devriez avoir une section commentaires avec un formulaire et deux commentaires.

Rien de bien compliqué pour l’instant…

L’entité Comment

Créez une simple entité Comment grâce à make:entity avec les champs suivant

Puis faite en sorte que la table comment soit créée en DB

Encore une fois, c’est du déjà vu.

Les relations

Ces commentaires vont être liés à un article.

On va parler de relation entre un article et un commentaire.

En SQL, cela correspond à une clé étrangère, où chaque ligne de la table comment va contenir l’id de l’article auquel il est lié.

Avec Doctrine, le commentaire va avoir une propriété article qui va contenir l’objet Article associé.

Nous allons générer ça avec la commande make:entity. Cette commande, permet non seulement de créer une nouvelle entité, mais également d’en ajouter en cours de route ! Pour cela, exécutez la commande et comme nom d’entité, entrez à nouveau Comment.

Ajoutez la propriété article de type relation et lié à l’entité Article.

La commande va vous proposer 4 types de relation qui sont ManyToOne, OneToMany, ManyToMany et OneToOne. Cette commande explique assez clairement le comportement de chaque type.

Choisissez le type attendu ici puis répondez no à la première question et yes à la deuxième puis appuyez sur Entrée jusqu’à sortir de la commande.

Observez attentivement l’entité Comment mais également l’entité Article.

Vous remarquerez que nous avons maintenant une propriété $article dans Comment et $comments dans Article avec des getters, setters mais aussi des méthodes addComment et removeComment dans Article.

Créez des fixtures pour les commentaires

Exécutez la commande make:fixtures pour créer une classe CommentFixtures

Générez des fixtures pour les commentaires et les lier à un article grâce à la documentation sur les références dans les fixtures.

Affichons ces commentaires

Dans le template, affichez les commentaires dans le code HTML ajouté précédemment.

Pour rappel, chaque Article possède une propriété comments qui contient tous les commentaires liés à cet article.

Afficher le nombre de commentaires là où il est actuellement écrit 2 Comments.

Regarder les requêtes effectuées par Doctrine dans le profiler.

Et maintenant, les formulaires

On commence par les dépendances composer require form validator security-csrf

En Symfony, les formulaires sont également gérés par des classes PHP.

Utilisez la commande make:form et répondez Comment aux deux questions.

La classe CommentType a été générée dans src/Form.

Ouvrez cette classe et observez son contenu.

Supprimez de cette classe ->add('createdAt') et ->add('article') car ces champs ne sont pas éditables par l’utilisateur.

Modifiez la configuration twig pour utiliser le thème Bootstrap 4 pour les formulaires.

Par défaut, Symfony détecte automatiquement le type de champ <input> à utiliser en HTML à partir de la configuration.

Ici il va générer un champ type="text" pour name et email et un <textarea> pour comment.

Voyons ça dans twig !

Il faut tout d’abord créer le formulaire dans la méthode show du controlleur.

$commentForm = $this->createForm(CommentType::class);

Sans oublier le use pour CommentType

Et le passer à Twig en ajoutant dans le tableau de paramètres de la méthode render

[
    ...
    'commentForm' => $commentForm->createView()
]

Vous avez maintenant une variable commentForm dans le template qui contient la représentation Objet de votre formulaire HTML.

Par exemple, les balises <form> et </form> sont respectivement remplacées dans twig par {{ form_start(commentForm) }} et {{ form_end(commentForm) }}.

Et chaque champ du formulaire (name, email et comment) est accessible comme une propriété.

Et pour afficher les champs du formulaire, vous pouvez utiliser {{ form_row(commentForm.email) }}.

Affichez ainsi tous vos champs sans oublier de retirer les champs HTML.

Actualisez la page, vous devriez voir votre formulaire, remplissez-le et soumettez le formulaire !

Rien ne se passe, c’est bien normal.

Observez le HTML généré grâce à la console de votre navigateur.

Création de nos nouveaux commentaires

Ajoutez le code suivant dans votre méthode show, entre le createForm et le return.

// le formulaire prend la requête et va récupérer à lintérieur les champs
// remplis par le formulaire HTML
$commentForm->handleRequest($request);

// Si le formulaire a été soumis et est valide
if ($commentForm->isSubmitted() && $commentForm->isValid()) {
    // on récupère l'objet Comment créé par le formulaire
    /** @var Comment $comment */
    $comment = $commentForm->getData();
    
    // on associe le commentaire à l'article et on défini la date de création
    $comment
        ->setArticle($article)
        ->setCreatedAt(new \DateTime())
    ;

    // on recupère le l'EntityManager de Doctrine qui va nous servir à sauvegarder notre commentaire en base de données
    $manager = $this->getDoctrine()->getManager();

    // le persist dit a Doctrine de conidérer cet Objet comme un objet à sauvegarder en base, l'objet est donc maintenant 
    // géré par Doctrine
    $manager->persist($comment);
    // le flush dit à Doctrine d'exécuter les requêtes SQL permettant de créer/modifier les objets sur lesquels
    // on appelé ->persist()
    $manager->flush();
    
    // redirige vers la page actuelle (la redirection permet d'éviter qu'en actualisant la page, cela soumette
    // à nouveau le formulaire
    return $this->redirectToRoute('show', ['id' => $article->getId()]);
}

Lisez attentivement les commentaires afin de comprendre ce morceau de code.

Il faut également injecter la Request dans la méthode (cf TP routing).

Retournez sur votre page et remplissez à nouveau votre formulaire, vous devriez voir votre commentaire apparaître !

Essayez d’en ajouter un nouveau mais en mettant un adresse email invalide comme test par exemple.

Ca marche ! Pas terrible….

Pou remédier à ça, remplacez ->add('email') par ->add('email', EmailType::class).

Essayez à nouveau, le formulaire est maintenant de Type Email et attend donc une adresse email valide.

Mais cette validation est faite en HTML, pas terrible en terme de sécurité.

Avec la console navigateur, modifiez le type de l’<input> par text (Clic Droit sur l’input puis Inspecter).

Essayez de soumettre à nouveau, ça devrait marcher…

C’est là qu’intervient, la validation !

Symfony possède un mechanisme de validation très puissant, qui s’intègre parfaitement avec les formulaires !

Dans votre entité Comment, modifiez votre code comme ceci.

/**
 * @ORM\Column(type="string", length=255)
 * 
 * @Assert\Email()
 */
private $email;

Et ajoutez l’import use Symfony\Component\Validator\Constraints as Assert;

Recommencez le test, il y a encore la validation HTML, modifiez à nouveau le champ grâce à la console navigateur pour le mettre en type text.

Réitérez l’expérience, cette fois-ci le formulaire est soumis à Symfony, mais une erreur générée par Symfony apparaît.

Cette fois-ci, aucun moyen de le contourner !

Pour tester la validation backend dans de meilleures condition, remplacer le form_start dans twig par {{ form_start(commentForm, {attr: {'novalidate': 'novalidate'}}) }}.

Cela va avoir pour effet de désactiver la validation HTML et laisser faire Symfony.

A partir de la liste de toutes les contraintes existantes, ajouter de la validation sur ce formulaire, pour vous assurer de recevoir la données dans le format souhaité (taille minimale, maximale, non vide, etc).