Cours - Symfony - Chapitre 04 - Récupération des données d'un formulaire et envoi d'emails

SOMMAIRE



Introduction


Dans ce chapitre, nous allons récupérer les données de notre formulaire de contact et allons les envoyer à l'administrateur du site.


Le profiler


Symfony propose d’installer le «profiler », un outil très pratique, qui permet de comprendre ce qu’il se passe sur votre site à différents niveaux :

  • routes (URL) disponibles,

  • requêtes HTTP,

  • requêtes SQL exécutées,

  • contrôleur appelées,

  • les fichiers TWIG utilisés,

  • etc.

Il permet également de savoir si vous êtes connecté et le temps d’exécution de votre programme.


Installation du package et découverte du profiler


composer require --dev symfony/profiler-pack



Nous voyons une nouvelle barre s’afficher en bas de la page. (Sauf si vous êtes en https, pensez bien à supprimer le « s »)








Nous avons le « status » de la page. Ici 200 car la page existe.

Le nom de la route est « index » et le contrôleur qui a répondu est « index » de la classe « BaseController ».





Nous pouvons consulter les données passées en paramètre dans la requête HTTP.





Nous voyons, sur l’image suivante, toutes les routes du site. Y compris les routes du « profiler ».







Voici un aperçu des informations concernant le rendu de la vue TWIG.






Récupérer les données de notre formulaire « Contact »


Remplissez le formulaire de contact et appuyez sur « envoyer »




Cliquez sur la barre du bas au niveau de « contact » et voyez le résultat du « profiler » qui doit ressembler à ceci :





Commentaires :


  • Nous remarquons que les données du formulaire sont récupérées dans les paramètres « POST » . C’est assez logique puisque les données proviennent d’un formulaire et que nous ne souhaitons pas voir apparaitre nos données dans l’URL.

  • Nous retrouvons nos données avec le nom de chaque composant que nous avions défini dans le formulaire « ContactType ».


Dans le contrôleur, nous allons maintenant mettre en place la réception des données si le formulaire a été soumis.


Dans « src/Controller/BaseController.php » :


Installation du composant « Request »

Le composant « Request » va contenir des informations sur la requête « HTTP » qui a été réalisée pour se retrouver sur le contrôleur « contact ».


Dans les « use » du haut du fichier, ajoutez l’appel à « Request » :


namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Form\ContactType;
use Symfony\Component\HttpFoundation\Request;


Dans les paramètres de notre fonction «contact », nous allons ajouter le paramètre « Request $request » qui nous permettra de recevoir toutes les données concernant la requête « HTTP ».


 #[Route('/contact', name: 'contact')]
    public function contact(Request $request): Response
    {
        $form = $this->createForm(ContactType::class);

        return $this->render('base/contact.html.twig', [
            'form' => $form->createView()
        ]);
    }


Test permettant de vérifier si le formulaire a été envoyé


 #[Route('/contact', name: 'contact')]
    public function contact(Request $request): Response
    {
        $form = $this->createForm(ContactType::class);

        if($request->isMethod('POST')){
            $form->handleRequest($request);
            if ($form->isSubmitted()&&$form->isValid()){
               
            }
        }

        return $this->render('base/contact.html.twig', [
            'form' => $form->createView()
        ]);
    }


Commentaires :


if($request->isMethod('POST')){ //regarde si la requête est de type POST (envoi de formulaire)

$form->handleRequest($request); // associe les données du formulaire avec les données de la requête.

if ($form->isSubmitted()&&$form->isValid()){ // vérifie si c’est bien notre formulaire qui a été envoyé. Nous verrons dans un autre chapitre comment créer des contraintes.


Pour l’instant, nous n’avons aucune indication sur le site pour être informés que le formulaire a bien été envoyé.

Mise en place des messages « Flash »


Lorsque nous allons réaliser des actions pour l’utilisateur, nous souhaitons afficher un message pour l’informer que l’opération s’est bien déroulée ou au contraire qu’elle a échoué. Symfony propose un système très pratique qui permet d’envoyer au système, un ou plusieurs messages qui s’afficheront sur la prochaine page qui sera chargée.


Envoyer un message à partir d’un contrôleur



#[Route('/contact', name: 'contact')]
    public function contact(Request $request): Response
    {
        $form = $this->createForm(ContactType::class);

        if($request->isMethod('POST')){
            $form->handleRequest($request);
            if ($form->isSubmitted()&&$form->isValid()){
                $this->addFlash('notice','Message envoyé');
            }
        }

        return $this->render('base/contact.html.twig', [
            'form' => $form->createView()
        ]);
    }


Commentaire :


Nous envoyons le message « Message envoyé» dans la liste des messages « flash », plus précisément dans la liste ‘notice’.

Définir un emplacement dans TWIG


Afin d’afficher les messages, nous allons définir un emplacement dans le template de base du site.

Donc dans « src/templates/base.html.twig » :


<!doctype html>
<html lang="fr">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
   {% block stylesheets %}
    <!-- Bootstrap CSS -->
    <link href="https://bootswatch.com/5/lumen/bootstrap.min.css" rel="stylesheet">
   {% endblock %}
    <title>{% block title %}Share - {% endblock %}</title>
  </head>
  <body>
   

<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
  <div class="container-fluid">
    <a class="navbar-brand " href="{{path('index')}}">Share</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarColor01">
      <ul class="navbar-nav me-auto">
        <li class="nav-item">
          <a class="nav-link" href="{{path('index')}}">Accueil        
          </a>
        </li>
         <li class="nav-item">
          <a class="nav-link" href="{{path('contact')}}">Contact        
          </a>
        </li>
         <li class="nav-item">
          <a class="nav-link" href="{{path('apropos')}}">À propos        
          </a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="{{path('mentions')}}">Mentions légales        
          </a>
        </li>
       </ul>
    </div>
 </div>
</nav>

 {% for message in app.flashes('notice') %}
     <h2 class="alert alert-warning text-center mt-4 mb-4" role="alert">
      {{ message }}
      </h2>
    {% endfor %}

    {% block body %}{% endblock %} 
   
    {% block javascripts %}
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
    {% endblock %}
  </body>
</html>


Commentaires :


  • {% for message in app.flashes('notice') %} // permet de parcourir l’ensemble des messages « flash » que nous aurons envoyés à partir d’un contrôleur. ‘notice’ signifie que nous souhaitons uniquement afficher les messages « notice » (notification) mais qu’il est tout à fait possible d’envoyer d’autres types de messages comme des alertes ou autres. Le premier message sera stocké dans la variable message, puis le 2ème message remplacera le premier lorsque la boucle recommencera, etc.

  • <h2 class="alert alert-warning text-center mt-4 mb-4" role="alert"> // Il s’agit d’utiliser un titre « h2 » avec des classes de « Bootstrap » pour donner un peu de style à nos messages.

  • {{ message }} // permet d’afficher la variable « message » entre les balises « h2 ».



Vous pouvez maintenant tester votre formulaire en le remplissant et en appuyant sur le bouton « envoyer ».





Le message s’affiche bien. En revanche, nous voyons que notre formulaire est encore renseigné avec nos données. Nous allons ajouter une instruction dans notre contrôleur pour éviter cela.


#[Route('/contact', name: 'contact')]
    public function contact(Request $request): Response
    {
        $form = $this->createForm(ContactType::class);

        if($request->isMethod('POST')){
            $form->handleRequest($request);
            if ($form->isSubmitted()&&$form->isValid()){
                $this->addFlash('notice','Message envoyé');
                return $this->redirectToRoute('contact');
            }
        }

        return $this->render('base/contact.html.twig', [
            'form' => $form->createView()
        ]);
    }



Commentaire :


L’instruction « redirectToRoute » demande à « Symfony » de rediriger le formulaire sur une route de votre site. Ici, il s’agit de la route pour se rendre sur la page « contact ».




Envoyer les données du formulaire à l’administrateur du site par email


Installation de « Postfix » sur votre serveur  

Afin d’envoyer un email, nous devons installer sur notre machine, « Postfix ». Il s’agit d’un serveur permettant d’envoyer et de recevoir des emails.


Dans le terminal, en "root », tapez la commande suivante :


apt install postfix


Mettez-vous en utilisateur normal en adaptant le numéro de votre login


su login4400


et dans votre projet 


cd share


Installation du module Mailer

Symfony propose un module permettant de construire et d’envoyer facilement des emails.


composer require symfony/mailer


Dans le fichier .env situé à la racine, vous trouverez ces lignes :


###> symfony/mailer ###
# MAILER_DSN=smtp://localhost
###< symfony/mailer ###


Mettez la valeur «smtp://localhost?verify_peer=0 » à la variable d’environnement « MAILER_DSN ».


###> symfony/mailer ###
MAILER_DSN=smtp://localhost?verify_peer=0
###< symfony/mailer ###


Commentaire :


verify_peer=0 // par défaut, la vérification TLS est activée, pour notre site en développement, nous le désactivons. Pour des raisons de sécurité, activez-le en production (à voir dans un prochain chapitre)..

Importation des composants 

En haut du fichier « src/Controller/BaseController.php » :


<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Form\ContactType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;


Envoyer un email au format texte


 #[Route('/contact', name: 'contact')]
    public function contact(Request $request, MailerInterface $mailer): Response
    {
        $form = $this->createForm(ContactType::class);

        if($request->isMethod('POST')){
            $form->handleRequest($request);
            if ($form->isSubmitted()&&$form->isValid()){   
                $email = (new Email())
                ->from($form->get('email')->getData())
                ->to('reply@nuage-pedagogique.fr')
                ->subject($form->get('sujet')->getData())
                ->text($form->get('message')->getData());
              
                $mailer->send($email);
               
                $this->addFlash('notice','Message envoyé');
                return $this->redirectToRoute('contact');
            }
        }

        return $this->render('base/contact.html.twig', [
            'form' => $form->createView()
        ]);
    }


Commentaires :


public function contact(Request $request, MailerInterface $mailer): Response // un nouveau paramètre est passé à la fonction « contact ». Il permet d’utiliser la méthode d’envoi d’emails.

$email = (new Email()) // Nous instancions une variable email

->from($form->get('email')->getData()) // Nous récupérons la valeur « email » envoyée par le formulaire pour la donner à la méthode « from » de l’email. Il s’agit de l’email de la personne qui souhaite nous contacter.

->to('reply@nuage-pedagogique.fr') // Nous mettons l’email de la personne qui le recevra, il s’agit généralement de l’administrateur du site.

->subject($form->get('sujet')->getData()) // Nous récupérons le sujet du message saisi dans le formulaire de contact et nous le mettons dans le sujet de l’email.

->text($form->get('message')->getData()); // Nous récupérons le message saisi dans le formulaire de contact afin de l’envoyer dans l’email.

$mailer->send($email); // la variable « mailer » reçoit l’email que nous avons préparé pour l’envoyer.



Vous pouvez maintenant tester l’envoi d’email en remplissant et en envoyant le formulaire de contact.


Envoyer un email au format HTML


Il est possible d’envoyer un email au format HTML avec de la couleur et une belle mise en forme.


Nous allons créer un fichier TWIG afin de définir la structure de notre email.


Dans le répertoire « templates », créez le répertoire « emails ». À l’intérieur, créez le fichier « email.html.twig ».


Dans templates/emails/email.html.twig, mettez le code suivant :


<h1>Vous avez un nouveau contact</h1>
<br />Nom: {{nom}}
<br />Sujet: {{sujet}}
<br />Message:
<br />{{message | nl2br }}


Commentaires :


  • Les balises « html » <br> et <h1> permettent de structurer votre email.

  • La fonction nl2br permet de créer des retours à la ligne en html pour que le message respecte la forme saisie dans le formulaire de contact.


Mettre en forme votre email 


Installez dans votre projet, la librairie nécessaire en tapant la commande suivante :


composer require twig/extra-bundle twig/cssinliner-extra


Et modifiez votre fichier « email.html.twig » comme ceci :



{% apply inline_css %}
    <style>
        {# here, define your CSS styles as usual #}
        h1 {
            color: #ff851b;
        }
    </style>

<h1>Vous avez un nouveau contact</h1>

<br />Nom: {{nom}}
<br />Sujet: {{sujet}}
<br />Message:
<br />{{message | nl2br }}

{% endapply %}


Commentaire :


Vous pouvez maintenant ajouter du « css » dans la partie « style » afin de personnaliser votre affichage.


Modification du contrôleur « src/Controller/BaseController.php ».


Ajoutez le nouveau composant :


use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Form\ContactType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email; // cette ligne devient inutile
use Symfony\Bridge\Twig\Mime\TemplatedEmail;


Puis modifier l’envoi d’emails dans le contrôleur :


#[Route('/contact', name: 'contact')]
    public function contact(Request $request, MailerInterface $mailer): Response
    {
        $form = $this->createForm(ContactType::class);

        if($request->isMethod('POST')){
            $form->handleRequest($request);
            if ($form->isSubmitted()&&$form->isValid()){   
                $email = (new TemplatedEmail())
                ->from($form->get('email')->getData())
                ->to('reply@nuage-pedagogique.fr')
                ->subject($form->get('sujet')->getData())
                ->htmlTemplate('emails/email.html.twig')
                ->context([
                    'nom'=> $form->get('nom')->getData(),
                    'sujet'=> $form->get('sujet')->getData(),
                    'message'=> $form->get('message')->getData()
                ]);
              
                $mailer->send($email);
                $this->addFlash('notice','Message envoyé');
                return $this->redirectToRoute('contact');
            }
        }



Commentaires :


$email = (new TemplatedEmail()) // Nous instancions un « TemplatedEmail » à la place d’un « Email » dans le chapitre précédent.

->htmlTemplate('emails/email.html.twig') // Appel du template que nous avons créé

->context([ // cette méthode va passer nos variables à notre template «  email.html.twig ».

'nom'=> $form->get('nom')->getData(), // nous passons le nom de la personne saisi dans le formulaire

'sujet'=> $form->get('sujet')->getData(), // nous passons le sujet de la même façon

'message'=> $form->get('message')->getData() // enfin, nous passons le message




Voici l’email reçu au format HTML



Voir le Chapitre 5