• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Itération 9 : ajout de commentaires à un article

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Le but de cette itération est de permettre aux utilisateurs authentifiés d'ajouter des commentaires à un article.

Symfony et les formulaires

La saisie de commentaires par les utilisateurs de l'application implique l'ajout d'un formulaire dans la vue qui affiche les détails sur un article. Il serait possible de gérer manuellement la définition de ce formulaire et la récupération des données saisies. Nous allons plutôt en profiter pour découvrir une autre des fonctionnalités offertes par le framework Symfony : la gestion des formulaires.

Grâce au composant Form, Symfony permet de créer un formulaire web à partir d'un objet. Les champs du formulaire sont associés aux propriétés de cet objet. Cette association est bidirectionnelle : le formulaire affiche les valeurs des propriétés de l'objet, et sa soumission (submit) met à jour les propriétés de l'objet. Le composant Form permet encore bien d'autres choses, comme nous allons le voir à présent.

Mise à jour de l'application

Composants Symfony

Commençons par récupérer les composants Symfony nécessaires en les ajoutant dans le fichier de dépendancescomposer.json.

"require": {
    ...
    "symfony/form": "~2.8|3.0.*",
    "symfony/translation": "~2.8|3.0.*",
    "symfony/config": "~2.8|3.0.*"
}
...

 

Le composantform regroupe les services de gestion des formulaires. Le composanttranslation offre des services de traduction nécessaires pour utiliser le composantform. Le composantconfig est également nécessaire au bon fonctionnement deform.

Une fois ce fichier modifié, on utilise Composer pour télécharger ces composants et leurs éventuelles dépendances.

composer update

Partie Modèle

Le formulaire que nous devons créer permettra à un utilisateur connecté de saisir un nouveau commentaire. Ce commentaire sera associé à un article et à un utilisateur existants. Son identifiant sera défini au moment de son insertion dans la base de données. Le seul champ que notre formulaire permettra de saisir sera donc le contenu du commentaire.

Symfony offre plusieurs manières de créer un formulaire. Nous allons employer la technique recommandée par les bonnes pratiques, qui consiste à le définir dans sa propre classe, afin de le rendre réutilisable dans toute l'application. Dans le répertoiresrc/Form/Type (à créer lui aussi), ajoutez un nouveau fichier source nomméCommentType.php. Placez-y le code source suivant.

<?php

namespace MicroCMS\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;

class CommentType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('content', TextareaType::class);
    }

    public function getName()
    {
        return 'comment';
    }
}

Notre classe hérite de la classe Symfony AbstractType et redéfinit sa méthodebuildForm qui, comme son nom l'indique, permet de construire un formulaire. Ici, le formulaire aura une zone de texte associée au contenu du commentaire (champcontent de typetextarea).

Nous devons modifier la classeCommentDAO pour la rendre capable d'insérer des commentaires dans la base de données. Pour cela, une méthodesave  est ajoutée à cette classe.

<?php

namespace MicroCMS\DAO;

use MicroCMS\Domain\Comment;

class CommentDAO extends DAO 
{
    // ...

    /**
     * Saves a comment into the database.
     *
     * @param \MicroCMS\Domain\Comment $comment The comment to save
     */
    public function save(Comment $comment) {
        $commentData = array(
            'art_id' => $comment->getArticle()->getId(),
            'usr_id' => $comment->getAuthor()->getId(),
            'com_content' => $comment->getContent()
            );

        if ($comment->getId()) {
            // The comment has already been saved : update it
            $this->getDb()->update('t_comment', $commentData, array('com_id' => $comment->getId()));
        } else {
            // The comment has never been saved : insert it
            $this->getDb()->insert('t_comment', $commentData);
            // Get the id of the newly created comment and set it on the entity.
            $id = $this->getDb()->lastInsertId();
            $comment->setId($id);
        }
    }

    // ...

 

 

Cette méthode rassemble les valeurs BD dans le tableau$commentData, puis vérifie s'il faut insérer ou mettre à jour le commentaire en se basant sur l'existence d'une valeur pour l'identifiant du commentaire. Ensuite, elle utilise la méthode DBAL appropriée pour effectuer l'opération dans la tablet_comment.

Partie Contrôleur

Nous devons tout d'abord enregistrer les nouveaux fournisseurs de services utilisés dans le fichierapp/app.php.

<?php

// ...

// Register service providers
// ...
$app->register(new Silex\Provider\FormServiceProvider());
$app->register(new Silex\Provider\LocaleServiceProvider());
$app->register(new Silex\Provider\TranslationServiceProvider());

// ...

 

Ensuite, il faut mettre à jour le fichierapp/routes.php  pour créer le formulaire d'ajout d'un commentaire avant de générer la vue qui affiche les détails sur un article. Voici le nouveau contenu de ce fichier.

<?php

use Symfony\Component\HttpFoundation\Request;
use MicroCMS\Domain\Comment;
use MicroCMS\Form\Type\CommentType;

// Home page
$app->get('/', function () use ($app) {
    $articles = $app['dao.article']->findAll();
    return $app['twig']->render('index.html.twig', array('articles' => $articles));
})->bind('home');

// Article details with comments
$app->match('/article/{id}', function ($id, Request $request) use ($app) {
    $article = $app['dao.article']->find($id);
    $commentFormView = null;
    if ($app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_FULLY')) {
        // A user is fully authenticated : he can add comments
        $comment = new Comment();
        $comment->setArticle($article);
        $user = $app['user'];
        $comment->setAuthor($user);
        $commentForm = $app['form.factory']->create(CommentType::class, $comment);
        $commentForm->handleRequest($request);
        if ($commentForm->isSubmitted() && $commentForm->isValid()) {
            $app['dao.comment']->save($comment);
            $app['session']->getFlashBag()->add('success', 'Your comment was successfully added.');
        }
        $commentFormView = $commentForm->createView();
    }
    $comments = $app['dao.comment']->findAllByArticle($id);

    return $app['twig']->render('article.html.twig', array(
        'article' => $article, 
        'comments' => $comments,
        'commentForm' => $commentFormView));
})->bind('article');

// Login form
$app->get('/login', function(Request $request) use ($app) {
    return $app['twig']->render('login.html.twig', array(
        'error'         => $app['security.last_error']($request),
        'last_username' => $app['session']->get('_security.last_username'),
    ));
})->bind('login');

Le contrôleur de la route/article/{id} est modifié : nous avons remplacé$app->get par$app->match afin de gérer à la fois l'accès à cette route via les commandes HTTP GET et POST ($app->get ne gère que la commande GET).

À l'intérieur de ce contrôleur, on récupère l'article (via son identifiant passé dans l'URL) puis on vérifie s'il existe un utilisateur connecté en utilisant le servicesecurity.authorization_checker de Symfony. Si c'est le cas, on récupère l'utilisateur connecté ($app['user']) puis on crée un nouveau commentaire et le formulaire associé à ce commentaire (appel à$app['form.factory']->create). Ensuite, la méthodehandleRequest gère la soumission du formulaire (plus de détails). Si le formulaire a été soumis et que les données reçues sont valides, on fait appel au DAO pour sauvegarder le nouveau commentaire et on crée un message de succès.‌

Dans tous les cas, on ajoute aux données dynamiques envoyées à la vue le formulaire d'ajout d'un commentaire (variable$commentFormView). Si aucun utilisateur n'est connecté, cette variable vautnull.

Partie Vue

Il nous reste à afficher le formulaire créé dans la partie Contrôleur. Pour cela, on modifie le templatearticle.html.twig de la manière suivante.

{% extends "layout.html.twig" %}

{% block title %}{{ article.title }}{% endblock %}

{% block content %}
<p>
    <h2>{{ article.title }}</h2>
    <p>{{ article.content }}</p>

    <h3>Comments</h3>
    {% for comment in comments %}
        <strong>{{ comment.author.username }}</strong> said : {{ comment.content }}<br>
    {% else %}
        No comments yet.
    {% endfor %}

    <h3>Add a comment</h3>
    {% if commentForm %}
        {{ form_start(commentForm) }}
            <div class="form-group">
                {{ form_errors(commentForm.content) }}
                {{ form_widget(commentForm.content, { 'attr':  {
                    'rows': '4',
                    'class': 'form-control',
                    'placeholder': 'Enter your comment'
                }}) }}
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Publish comment" />
            </div>
        {{ form_end(commentForm) }}
        {% for flashMessage in app.session.flashbag.get('success') %}
            <div class="alert alert-success">
                {{ flashMessage }}
            </div>
        {% endfor %}
    {% else %}
        <a href="{{ path('login') }} ">Log in</a> to add comments.
    {% endif %}
</p>
{% endblock %}

 

Dans ce template, on vérifie si le formulairecommentForm existe puis (si c'est le cas) on utilise des fonctions Twig pour générer le code HTML associé à chaque partie du formulaire.

  • form_start génère le début du formulaire (balise HTML<form>).

  • form_widget génère un champ de formulaire.

Pour plus de précisions, consultez la documentation détaillée de ces fonctions.

On associe à chaque champ généré des classes Bootstrap (form-group  etform-control) afin d'améliorer la présentation. Les éventuels messages de succès sont également affichés via Bootstrap.

Résultat obtenu

Lorsqu'un utilisateur connecté clique sur le titre d'un article, la vue qui affiche son détail lui permet à présent d'ajouter un commentaire.

Une fois le commentaire saisi et publié, l'affichage de l'article intègre le nouveau commentaire ainsi qu'un message de succès.

Le code source associé à cette itération est disponible sur une branche du dépôt GitHub

Bilan

Cette itération a fourni l'occasion d'intégrer à notre application la gestion des formulaires. Le composant Symfony associé permet de simplifier grandement ce processus. Ce composant est très puissant et dispose de nombreuses autres fonctionnalités que celles présentées ici.

Exemple de certificat de réussite
Exemple de certificat de réussite