Affichage et administration des utilisateurs : assets, templates Twig et forms - Tuto Symfony - PHP - Partie 3

Affichage et administration des différents utilisateurs d’une application Symfony
Corentin.jpg
Corentin CHEVRETMis à jour le 7 Déc 2020
tuto symfony php

Maintenant que nous savons créer / peupler notre BDD et récupérer des données d’utilisateurs, nous allons voir comment les afficher et modifier.

Nous verrons dans cette troisième partie la configuration des assets et comment afficher nos utilisateurs à l’aide du moteur de template Twig. Enfin nous découvrirons les Forms qui permettront de modifier les informations utilisateurs.

Configuration des assets sur Symfony

Nous utiliserons le bundle webpack-encore-bundle, qui nous permettra de compiler nos assets en 1 seul fichier CSSFeuilles de style qui permettent de mettre en forme des pages web. et 1 seul fichier JS à travers un serveur Node. Cela fera gagner en performance pour charger tous nos assets (idéal pour les sites importants avec énormément de ressources à utiliser).

Installation

Tout d’abord, il faut ajouter le bundle webpack-encore-bundle :

composer require symfony/webpack-encore-bundle

Ensuite, comme nous utilisons un serveur Node pour compiler les assets, il est nécessaire d’installer Node pour pouvoir utiliser les commandes npm.

Une fois Node installé, nous pouvons installer les packages JS du fichier package.js (les développeurs AngularAngular est un framework de développement JavaScript populaire basé sur TypeScript. / ReactReact est un framework de développement JavaScript populaire. / Vue.jsFramework JavaScript populaire. ne seront pas dépaysés) avec la commande :

npm install

À présent, nous avons accès à la commande encore : elle permet de lancer un serveur Node qui va compiler en direct nos assets à chaque modification (très pratique pendant le développement) :

encore dev-server

Un fichier manifest.json dans le dossier public/build est mis à jour pour indiquer sur quels liens sont accessibles nos assets :

{
  "build/app.css": "http://localhost:8080/build/app.css",
  "build/app.js": "http://localhost:8080/build/app.js",
  "build/runtime.js": "http://localhost:8080/build/runtime.js",
  "build/vendors~app.js": "http://localhost:8080/build/vendors~app.js"
}

Les fichiers app.css et app.js sont disponibles dans le dossier assets. Ce sont ces fichiers qui vont contenir tout le CSS et JS de notre application. On peut directement écrire dedans mais surtout faire des imports de fichiers pour que ce soit plus lisible.

Finalement, nous devons importer les fichiers app.css et app.js dans notre template base.html.twig dans le dossier templates pour que tous les templates "enfants", que nous créerons plus tard pour les utilisateurs, puissent utiliser les assets :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}{% endblock %}</title>
        {% block stylesheets %}
            <!-- Ajout du CSS -->
            {{ encore_entry_link_tags(’app’) }}
        {% endblock %}
    </head>
        <body>
        {% block body %}{% endblock %}
        {% block javascripts %}
            <!-- Ajout du JS -->
            {{ encore_entry_script_tags(’app’) }}
        {% endblock %}
    </body>
</html>

Prise en charge du SASS

Le SASS est presque indispensable. Il va nous permettre d’avoir un code beaucoup plus lisible et surtout utiliser @import pour importer le CSS d’autres packages (comme Bootstrap).

Le fichier webpack.config.js à la racine du projet doit être modifié pour activer le SASS :

...
// enables Sass/SCSS support
.enableSassLoader() // Décommenter cette ligne pour activer le SASS
...

Enfin, il suffit d’installer les packages JS suivants :

npm install sass-loader@^8.0.0 node-sass --save-dev

On peut maintenant renommer le fichier app.css en app.sccs et relance le serveur Node (commande encore dev-server).

Ajout de Bootstrap

Nous allons maintenant ajouter Bootstrap à notre application et donc dans nos assets. Pour cela, il faut d’abord ajouter le package npm Bootstrap :

npm install bootstrap jquery popper.js --save

Ensuite, dans le fichier app.sccs, nous rajoutons le CSS de Bootstrap :

@import "~bootstrap/dist/css/bootstrap.min.css";

Enfin, on importe le JS de Bootstrap dans app.js :

// CSS
import ’../css/app.scss’;

// JS
import ’bootstrap’;

Et voilà ! Nous pouvons maintenant commencer à faire de belles templates Twig.

Template Twig

Nous allons maintenant créer notre première page à l’aide du moteur de template Twig.

Liste des utilisateurs

Création du template Twig

Le nouveau template users.html.twig sera ajouté à un nouveau dossier users dans le dossier templates.

Il affichera la liste de nos utilisateurs :

// template users. sauvegardée dans le dossier templates 
{% extends "base.html.twig" %}

{% block title %}Tableau utilisateurs{% endblock %}
{% block body %}
    <div class="p-5">
        <h2>Tableau utilisateurs</h2>

        <table class="table table-responsive">
            <tr>
                <th>Prénom</th>
                <th>Nom</th>
                <th>Date anniversaire</th>
                <th>Description</th>
            </tr>
            {% for user in users %}
                <tr>
                    <td>{{ user.firstName }}</td>
                    <td>{{ user.lastName }}</td>
                    <td>{{ user.birthday|date(’d/m/Y’) }}</td>
                    <td>{{ user.description }}</td>
                </tr>
            {% endfor %}
        </table>
    </div>
{% endblock %}

On peut voir {% extends "base.html.twig" %} en première ligne du code. Cela va nous permettre de modifier les block renseignés dans base.html.twig.

Ainsi, on peut modifier le block title et le block body de base.html.twig.

Modification du Controller

Le Controller UserController.php doit être modifié pour retourner le template Twig à la place du JSON actuellement :

...
public function getUsers(UserManager $userManager)
{
    $users = $userManager->findAllWithDescription();
    return $this->render(’users/users.html.twig’, [’users’ => $users]);
}
...

On utilise la fonction render pour renseigner le template Twig ainsi que la variable contenant nos utilisateurs accessibles dans la template.

Résultat

La page listant les utilisateurs doit ressembler à cela si tout se passe bien de votre côté (toujours accessible à l’adresse http://localhost:8000/users) : 

page_user.png

Fiche utilisateur

Création du template Twig

Le template user.html.twig sera également ajouté au dossier users dans le dossier templates.

Il affichera la fiche d’un utilisateur :

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

{% block title %}Fiche utilisateur{% endblock %}
{% block body %}
    <div class="p-5">
        <div class="row">
            <div class="col">
                <h2>Fiche utilisateur</h2>
            </div>
            <div class="col-auto">
                <a class="btn btn-primary" href="{{ path(’get-users’) }}"> Retour</a>
            </div>
        </div>

        <p>Prénom : {{ user.firstName }}</p>
        <p>Nom : {{ user.lastName }}</p>
        <p>Né(e) le : {{ user.birthday|date(’d/m/Y’) }}</p>
        <p>Description : {{ user.description }}</p>
    </div>
{% endblock %}

Modification du Controller

Le Controller UserController.php doit également être modifié pour retourner le template Twig :

<?php
...
public function getOneUser(UserManager $userManager, int $id)
{
    $user = $userManager->findOneWithDescription($id);
    return $this->render(’users/user.html.twig’, [’user’ => $user]);
}
...

Résultat

La fiche utilisateur devrait ressembler à cela (http://localhost:8000/users/1) : 

page_users.png

Lier les 2 templates

Modification du template users.html.twig

Nous allons rajouter un bouton à chaque utilisateur pour accéder à sa fiche :

...
<table class="table table-responsive">
    <tr>
        <th>Prénom</th>
        <th>Nom</th>
        <th>Date anniversaire</th>
        <th>Description</th>
        
        <!-- Ajout d’une entête vide -->
        <th></th>
    </tr>
    {% for user in users %}
        <tr>
            <td>{{ user.firstName }}</td>
            <td>{{ user.lastName }}</td>
            <td>{{ user.birthday|date(’d/m/Y’) }}</td>
            <td>{{ user.description }}</td>
            
            <!-- Ajout du bouton pour accéder à la fiche d’un user -->
            <td>
                <a href="{{ path(’get-user’, {id: user.id}) }}" class="btn btn-primary">Voir</a>
            </td>
        </tr>
    {% endfor %}
</table>
...

Résultat

Un nouveau bouton est disponible pour accéder à la fiche utilisateur : 

page_users2.png

Utilisation des Forms Symfony

SymfonyFramework PHP permettant de développer des applications web. nous permet, à travers l’utilisation de Forms, de mettre très facilement en place des formulaires de création / mise à jour.

Nous verrons ici comment modifier un utilisateur à travers un Form que nous créerons.

Installation des Forms

Il nous faudra tout d’abord ajouter le package form :

composer require symfony/form

Création d’un FormType : UserType.php

Un FormType nous permet d’instancier un Form qui pourra être utilisé plusieurs fois par la suite. Cela évite la redondance de code et donc de créer plusieurs fois le même Form.

Le fichier UserType.php est créé dans le dossier Type du dossier Form (à créer si nécessaire) :

<?php
namespace App\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class UserType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options)
   {
      $builder
         ->add(’firstname’, TextType::class, [’label’ => ’Prénom’])
         ->add(’lastname’, TextType::class, [’label’ => ’Nom’])
         ->add(’birthday’, DateType::class, [
            ’label’ => ’Né(e) le’,
            ’attr’ => [’placeholder’ => ’dd/mm/yyyy’],
            ’widget’ => ’single_text’,
            ’format’ => ’dd/MM/yyyy’,
            ’input’ => ’datetime’,
            ’html5’ => false
         ])
         ->add(’save’, SubmitType::class)
         ->getForm();
   }
}

Nous pouvons voir que le Form comporte :

  • firstname : Champ de type Text pour le prénom de l’utilisateur.
  • lastname : Champ de type Text pour le nom de l’utilisateur.
  • birthday : Champ de type Date pour la date d’anniversaire de l’utilisateur.
  • save : Champ de type Submit pour soumettre le formulaire.

Si vous avez besoin d’un autre type de champ (textarea, number, datetime, ... ) ou pour découvrir plus en détails la configuration d’un Form, vous pouvez vous référer à la documentation Symfony.

Création et affichage du Form Symfony

Nous devons maintenant modifier notre UserController.php pour y ajouter le Form que nous venons de créer.

Le formulaire de modification sera visible dans la fiche utilisateur, donc c’est la fonction getOneUser() qui doit être modifiée en conséquence :

<?php
...
public function getOneUser(UserManager $userManager, int $id)
{
    $user = $userManager->findOneWithDescription($id);
    
    // Création de notre Form auquel on passe notre objet User.
    $form = $this->createForm(UserType::class, $user);
    // On rajoute le Form au template de la fiche utilisateur pour pouvoir l’afficher.
    return $this->render(’users/user.html.twig’, [’user’ => $user, ’form’ => $form->createView()]);
}
...

Côté template Twig, la nouvelle variable form passée au template va nous permettre d’afficher le formulaire :

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

{% block title %}Fiche utilisateur{% endblock %}
{% block body %}
    <div class="p-5">
        <div class="row">
            <div class="col">
                <h2>Fiche utilisateur</h2>
            </div>
            <div class="col-auto">
                <a class="btn btn-primary" href="{{ path(’get-users’) }}"> Retour</a>
            </div>
        </div>

        <p>Prénom : {{ user.firstName }}</p>
        <p>Nom : {{ user.lastName }}</p>
        <p>Né(e) le : {{ user.birthday|date(’d/m/Y’) }}</p>
        <p>Description : {{ user.description }}</p>

        {# Ajout du form #}
        <h2>Modifier utilisateur</h2>
        {{ form(form) }}
    </div>
{% endblock %}

Nous obtenons un formulaire pré-rempli avec le nom, prénom, date anniversaire de notre utilisateur dans sa fiche : 

page_user_form_without_style.png

Ajout du thème Bootstrap au formulaire

Il serait assez long de rajouter notre style CSS sur notre formulaire mais pas de panique, il est possible d’ajouter automatiquement un thème Bootstrap à tous les formulaires.

Pour cela, il suffit de modifier le fichier twig.yaml dans le dossier packages :

twig:
    default_path: ’%kernel.project_dir%/templates’
    form_themes: [’bootstrap_4_layout.html.twig’] # Ajout du thème Bootstrap

Le résultat est désormais un peu plus convaincant : 

page_user_form_with_style.png

Modification de notre utilisateur

Si nous essayons de cliquer sur le bouton Enregistrer de notre formulaire, nous pouvons constater que la page se recharge sans prendre en compte les modifications dans le formulaire.

Nous allons ajouter une méthode postUser() dans notre UserController.php qui se chargera de recevoir le formulaire soumis et de sauvegarder l’utilisateur :

<?php
/**
* @Route("/users/{id}", name="post-user", requirements={"id"="\d+"}, methods={"POST"})
*
* @param UserManager $userManager
* @param Request $request
* @param int $id
* @return Response
* @throws Exception
*/
public function postUser(UserManager $userManager, Request $request, int $id)
{
    $user = $userManager->findOneWithDescription($id);
    $form = $this->createForm(UserType::class, $user);
    $form->handleRequest($request);

    // Si le formulaire est soumis et valide
    if ($form->isSubmitted() && $form->isValid()) {
        // On récupère l’utilisateur dans le formulaire
        /** @var User $user */
        $user = $form->getData();

        // On sauvegarde l’utilisateur
        $em = $this->getDoctrine()->getManager();
        $em->persist($user);
        $em->flush();
    }

    // On redirige sur la fiche utilisateur
    return $this->redirectToRoute(’get-user’, [’id’ => $user->getId()]);
}

Pour que le formulaire soit soumis dans cette fonction, il faut modifier son action et sa méthode dans le template :

...
{# Modification de l’action et de la méthode du form #}
<h2>Modifier utilisateur</h2>
{{ form(form, {’action’: path(’post-user’, {id: user.id}), ’method’: ’POST’}) }}
...

Résultat final

Il est maintenant temps de modifier le formulaire d’une fiche utilisateur et de valider les modifications : 

resultat_final.png

La suite d’un projet Symfony

Maintenant que nous maîtrisons les templates Twig et les Forms, la prochaine partie portera sur la mise en place d’une authentification JWT. Nous créerons une page de connexion et verrons la gestion des rôles utilisateur.

À BIENTÔT ♥