Jérôme Cutrona

Version statique de l'intranet de Jérôme Cutrona - Rejoindre la version dynamique 🔒

Les exemples et corrections sont potentiellement non fonctionnels.

B.U.T. Informatique - IUT de Reims - Université de Reims

Symfony 7.3

Navigation

Objectifs de la séance

  • Créer un projet Symfony avec l'outil « symfony » en ligne de commande (« Symfony CLI »)
  • Prendre en main Symfony dans sa version 5
  • Utiliser le routage
  • Développer des « templates » Twig
  • Écrire des tests fonctionnels
  • Utiliser l'ORM Doctrine
  • Gérer des relations entre entités
  • Générer des données factices (« fixtures ») avec « Foundry »
  • Utiliser le composant Form
  • Utiliser le composant Security
  • Mettre en place un « back-office » avec EasyAdmin

Préambule

L'objectif de ce TP est de vous familiariser avec le développement d'applications Symfony. Le sujet vous accompagne dans la découverte du framework tout en essayant de se conformer aux bonnes pratiques de Symfony.

Remarque importante

De nombreux points du sujet consistent en l'observation de fichiers ou de fonctionnements qui s'appuient sur des conventions liées au framework. Ne les négligez pas ! Le but n'est pas de vous faire suivre bêtement un tutoriel mais de vous amener à comprendre ce que vous faites.

Utilisation du moteur PHP local

Vous allez utiliser le moteur PHP installé localement sur le poste de travail. Vous déclencherez le moteur PHP local, directement ou indirectement de diverses manières :

  • à l'aide de la commande php pour exécuter du code
    php -r "code PHP"
  • à l'aide de la commande php pour exécuter un programme
    php -f un_script_PHP
    ou
    php un_script_PHP
  • comme une commande grâce à l'utilisation du shebang en tête d'un programme PHP
    bin/console cache:clear

    Le programme « console » est fourni dans Symfony, s'utilise comme un script shell, et est écrit en PHP. Sa première ligne est #!/usr/bin/env php

  • comme une commande grâce à l'utilisation du shebang en tête d'un paquet PHP (fichier .phar)
    composer.phar update
  • en mode server local à travers l'utilisation du serveur Web intégré à PHP
    php -S localhost:8000 -t public/

    PHP lance ici un serveur Web local que vous allez interroger avec un navigateur Web.

Documentation

Vous aurez besoin de la documentation de Symfony ainsi que de celle des diverses API :

Mise en place d'une application Symfony

Vous allez créer des applications Symfony de façon conventionnelle, en utilisant l'outil « symfony » en ligne de commande (« Symfony CLI »). Une nouvelle application Symfony nécessite un peu plus de 80 Mo de sources PHP pour fonctionner (environ 10.000 fichiers dans un peu moins de 2.000 répertoires !). Ces données seront rapidement agrémentées de plusieurs dizaines de mégaoctets de cache générés par Symfony.

Vous allez installer Symfony à l'aide de l'outil « symfony » en ligne de commande (« Symfony CLI ») et pour cela, vous allez devoir l'installer. Cet outil utilise Composer dont vous devrez vous assurer du bon fonctionnement.

Quelques considérations liées à la configuration système de l'IUT

Remarque importante

Si vous travaillez sur votre ordinateur personnel, sur Linux ou sur Windows, vous pouvez placer le répertoire « symfony-contacts » du projet où bon vous semble. La partie qui suit concerne uniquement le travail sur les ordinateurs de l'IUT. Cela ne vous empêche pas d'en prendre connaissance.

Votre répertoire d'accueil « $HOME » se trouve sur un emplacement réseau NFS, ce qui vous permet de retrouver vos fichiers quel que soit le PC du département sur lequel vous vous connectez. Symfony utilise le sous-répertoire « var » du projet pour la gestion de son cache, des traces d'exécution et des données de session. Ces tâches génèrent de nombreuses entrées-sorties sur le système de fichiers, particulièrement inadaptées aux systèmes de fichiers en réseau. Il en va de même pour PhpStorm qui surveille les modifications de tous les fichiers du projet et ne peut pas fonctionner normalement lorsque ces fichiers sont sur un partage NFS. Afin d'améliorer les performances de l'application et d'éviter de saturer le serveur de fichiers du département informatique, vous allez travailler dans le répertoire « /working/votre_login » de la machine sur laquelle vous êtes connecté.

En fin de séance

En fin de séance, vous devez impérativement synchroniser le dépôt distant (en ligne de commande ou avec PhpStorm)

git commit
puis
git push
faute de quoi vous perdrez votre travail entre chaque séance !

Pensez également à supprimer votre répertoire de travail /working/votre_login/symfony-contacts pour éviter la saturation du disque local :

rm -Rf /working/votre_login/symfony-contacts

En début de séance

Lorsque vous reprenez le travail la séance suivante, vous avez trois choix possibles, qui dépendent de la façon dont vous avez travaillé :

  • Mettre à jour le dépôt local
    cd /working/votre_login/symfony-contacts
    git pull
  • Effacer le dépôt local et repartir de zéro
    cd /working/votre_login
    rm -Rf /working/votre_login/symfony-contacts
    git clone https://iut-info.univ-reims.fr/gitlab/votre_login/symfony-contacts.git
    cd /working/votre_login/symfony-contacts
  • Réinitialiser le dépôt local selon le dépôt distant
    cd /working/votre_login/symfony-contacts
    git fetch
    git reset --hard origin/main

Ensuite, dans le répertoire du projet, vous devez et (ré)installer les composants nécessaires à son fonctionnement :

composer install

Vous devrez également reconfigurer l'accès base de données en redéfinissant le fichier « .env.local »

Installation de l'exécutable « symfony »

Le développement d'applications Symfony peut être facilité par l'utilisation de l'outil « symfony » en ligne de commande (« Symfony CLI »). Ce dernier peut contrôler que le système comporte tous les prérequis pour le développement d'applications Symfony ou tester la présence de failles de sécurité connues.

Travail à réaliser
  1. Installez l'exécutable « symfony » qui contient le serveur Web local en lançant la commande suivante :
    wget https://get.symfony.com/cli/installer -O - | bash
    --2025-09-08 14:06:03--  https://get.symfony.com/cli/installer
    Résolution de get.symfony.com (get.symfony.com)… 18.164.52.20, 18.164.52.7, 18.164.52.11, ...
    Connexion à get.symfony.com (get.symfony.com)|18.164.52.20|:443… connecté.
    requête HTTP transmise, en attente de la réponse… 200 OK
    Taille : 6100 (6,0K) [binary/octet-stream]
    Enregistre : ‘STDOUT’
    
    -                                 100%[=============================================================>]   5,96K  --.-KB/s    ds 0s      
    
    2025-09-08 14:06:03 (2,49 GB/s) — envoi vers sortie standard [6100/6100]
    
    Symfony CLI installer
    
    Environment check
      [*] cURL is installed
      [*] Tar is installed
      [*] Git is installed
      [*] Your architecture (amd64) is supported
    
    Download
      Downloading https://github.com/symfony-cli/symfony-cli/releases/latest/download/symfony-cli_linux_amd64.tar.gz...
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
      0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
      0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
    100 6151k  100 6151k    0     0  7388k      0 --:--:-- --:--:-- --:--:-- 41.6M
      Uncompress binary...
      Installing the binary into your home directory...
      The binary was saved to: /home/Users/cutron01/.symfony5/bin/symfony
    
    The Symfony CLI was installed successfully!
    
    Use it as a local file:
      /home/Users/cutron01/.symfony5/bin/symfony
    
    Or add the following line to your shell configuration file:
      export PATH="$HOME/.symfony5/bin:$PATH"
    
    Or install it globally on your system:
      mv /home/Users/cutron01/.symfony5/bin/symfony /usr/local/bin/symfony
    
    Then start a new shell and run 'symfony'
    
  2. Modifiez ou créez le fichier « .profile » (à la racine de votre compte) afin qu'il contienne
    export PATH="\$HOME/.symfony5/bin:\$PATH"
  3. Chargez les modifications du « .profile »
    source ~/.profile
    Information

    La configuration du shell Bash se fait à l'aide de fichiers de démarrage. Le fichier « ~/.profile » est exécuté à chaque ouverture de session. Il est donc nécessaire de se (re)connecter pour que les modifications soient prises en compte dans chaque terminal lancé. Pour cette séance, vous pouvez vous contenter de recharger le fichier de configuration avec la commande « source ~/.profile ».

    Si vous souhaitez profiter immédiatement des bénéfices de la modifications du fichier « .profile », vous devez vous déconnecter de la machine et vous reconnecter.

  4. Vérifiez le bon fonctionnement de l'exécutable « symfony »
    symfony self:version
  5. Contrôlez la compatibilité du système avec la commande :
    symfony check:requirements  --verbose
    Symfony Requirements Checker
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    > PHP is using the following php.ini file:
    /etc/php/8.3/cli/php.ini
    
    > Checking Symfony requirements:
    
    [OK] iconv() must be available
    [OK] json_encode() must be available
    [OK] session_start() must be available
    [OK] ctype_alpha() must be available
    [OK] token_get_all() must be available
    [OK] simplexml_import_dom() must be available
    [OK] detect_unicode must be disabled in php.ini
    [OK] xdebug.show_exception_trace must be disabled in php.ini
    [OK] xdebug.scream must be disabled in php.ini
    [OK] PCRE extension must be available
    [OK] string functions should not be overloaded
    [OK] xdebug.max_nesting_level should be above 100 in php.ini
    [OK] PCRE extension should be at least version 8.0 (10.42 installed)
    [OK] PHP-DOM and PHP-XML modules should be installed
    [OK] mb_strlen() should be available
    [OK] utf8_decode() should be available
    [OK] filter_var() should be available
    [OK] posix_isatty() should be available
    [OK] intl extension should be available
    [OK] intl extension should be correctly configured
    [OK] intl ICU version should be at least 4+
    [OK] intl.error_level should be 0 in php.ini
    [OK] a PHP accelerator should be installed
    [OK] short_open_tag should be disabled in php.ini
    [OK] magic_quotes_gpc should be disabled in php.ini
    [OK] register_globals should be disabled in php.ini
    [OK] session.auto_start should be disabled in php.ini
    [OK] xdebug.max_nesting_level should be above 100 in php.ini
    [OK] "memory_limit" should be greater than "post_max_size".
    [OK] "post_max_size" should be greater than "upload_max_filesize".
    [OK] PDO should be installed
    [OK] PDO should have some drivers installed (currently available: mysql, pgsql, sqlite)
    
    
                                                  
     [OK]                                         
     Your system is ready to run Symfony projects 
                                                  
    
    Note  The command console can use a different php.ini file
    ~~~~  than the one used by your web server.
          Please check that both the console and the web server
          are using the same PHP version and configuration.
    
    Information

    Dans un environnement Windows, vous pouvez télécharger une archive zip qui contient « symfony.exe ». Ce programme est l'exécutable de l'outil que vous devez donc placer dans un répertoire de votre système et le rendre accessible en ligne de commande (le répertoire doit figurer dans la variable d'environnement « Path »).

Création d'un projet Symfony

Vous allez pouvoir créer un projet Symfony à l'aide de l'outil « symfony » en ligne de commande (« Symfony CLI »).

Travail à réaliser
  1. Si ce n'est pas déjà fait, installez Composer
    Information

    L'outil « symfony » en ligne de commande (« Symfony CLI ») utilise Composer pour créer le nouveau projet. S'il n'est pas disponible sur le système, une version temporaire sera téléchargée. Il est plus rapide et logique d'avoir votre propre version fonctionnelle qui sera par ailleurs utile par la suite.

  2. Vérifiez que Composer fonctionne correctement :
    composer about
  3. Mettez à jour Composer :
    composer self-update
  4. Vérifiez que vous êtes bien dans le répertoire « /working/votre_login » (ou n'importe quel répertoire de votre choix si vous êtes sur votre ordinateur personnel)
  5. Lancez la création d'un nouveau projet Symfony version « 7.3.* » :
    symfony --version 7.3 --webapp new symfony-contacts

Vérification du bon fonctionnement de l'application

Si vous avez réalisé toutes les étapes précédentes sans encombre, l'application doit fonctionner. Vous allez donc le vérifier. Vous allez utiliser l'environnement de développement de Symfony qui est celui qui est activé par défaut en mode développement.

Travail à réaliser
  1. Placez-vous le répertoire de l'application
  2. Dans le terminal, lancez le serveur Web local avec la commande suivante :
    symfony serve
    Information

    Le serveur Web fonctionnera tant que vous n'aurez pas terminé l'exécution l'outil ligne de commande « symfony » avec « CTRL+C ».

  3. Suivez les instructions données dans la partie « Gestion du certificat du serveur Web de l'API dans le navigateur » du tutoriel « Configuration CORS pour utiliser l'authentification de l'API avec React »
  4. Accédez à l'URL « https://127.0.0.1:8000 » pour obtenir : Test de l'environnement de développement
  5. Constatez l'apparition de la Web Debug Toolbar
  6. Observez les sorties texte du serveur Web local
  7. Naviguez rapidement à travers les outils de la Web Debug Toolbar
  8. Observez les sorties texte du serveur Web local
  9. Terminez l'exécution de l'outil ligne de commande « symfony » avec « CTRL+C »

Gestion des versions avec Git

Afin de fiabiliser votre méthode de développement, vous allez utiliser Git pour gérer le suivi des versions de l'application Symfony.

Dépôt local

Vous allez configurer le dépôt Git local.

Travail à réaliser
  1. Assurez-vous d'être dans le répertoire du projet symfony-contacts
  2. Constatez que le dépôt Git local a été initialisé par l'outil « symfony » en ligne de commande (« Symfony CLI »)
    git log
  3. Excluez du suivi de Git le répertoire « .idea » de PhpStorm
    echo -e "\n/.idea/" >> .gitignore
    git add .gitignore
    git commit -m "Exclusion du répertoire .idea"
Information

Si vous créez le projet avec Composer, vous devez effectuer les actions suivantes :

  1. Initialisez le dépôt Git
    git init
  2. Ajoutez l'ensemble des fichiers à l'index
    git add .
  3. Effectuez la première validation
    git commit -m "Initial commit"
  4. Renommez la branche principale en « main » (une branche vide ne peut pas être renommée, c'est pourquoi ceci est fait après le premier « commit »)
    git branch -m main

Dépôt distant

Passons maintenant à la configuration du dépôt distant.

Travail à réaliser
  1. Créez un nouveau projet « symfony-contacts » sur GitLab (pensez à décocher la case « Initialize repository with a README »)
  2. Associez le dépôt local et le dépôt distant
  3. Poussez la branche locale
Remarque importante

Dans toute la suite du TP, pensez à effectuer des « commit » réguliers (un par question au minimum). Vous pouvez utiliser PhpStorm pour les commandes Git « commit » et « push ». PhpStorm propose une option « Commit and Push… » particulièrement adaptée à votre situation : Configuration de Git

N'oubliez pas d'ajouter les nouveaux fichiers au gestionnaire de versions (Ctrl+Alt+A) avant vos « commit ». Vous pouvez constater que le nom des fichiers s'affiche en vert pour ceux qui ont été ajoutés au suivi par opposition au rouge pour ce qui n'ont pas été ajoutés et gris clair pour ceux qui sont ignorés. Configuration de Git

Création du projet dans PhpStorm

La gestion d'une application Symfony nécessitant de modifier de nombreux fichiers dans une arborescence complexe, vous utiliserez PhpStorm pour l'édition de texte. Des greffons apportent le support de Symfony, Composer, des fichiers YAML, Twig, … Certains sont préinstallés dans la configuration générale.

Vous allez créer un nouveau projet PHP à partir de PhpStorm pour gérer l'application Web.

Remarque importante

PhpStorm est un outil puissant parmi d'autres développés par JetBrains. Leur utilisation dans le cadre professionnel impose de s'acquitter d'une licence annuelle. Cependant, dans la cadre universitaire, vous pouvez disposer d'une licence gratuite pour les étudiants. Ceci vous permet d'utiliser les outils sur votre ordinateur personnel, tant que vous êtes étudiant. L'utilisation de PhpStorm au sein du département ne nécessite pas de démarche particulière puisque nous avons un serveur de licences JetBrains.

Je vous invite néanmoins à demander une licence et à travailler sur votre ordinateur personnel en dehors des séances de TP.

Travail à réaliser
  1. Dans le terminal et dans le répertoire du projet, lancez la commande
    phpstorm . &
    Information

    Cette commande est la façon la plus simple et la plus rapide de créer un nouveau projet PhpStorm dans un répertoire. Il n'est pas utile de la lancer une fois le projet créé puisque vos anciens projets sont proposés à l'ouverture de PhpStorm ou dans son menu « File » puis « Recent Projects ».

  2. Patientez pendant l'indexation des fichiers du projet visible dans la partie droite de la barre d'état Indexatioon du projet
  3. Activez le greffon « Symfony Support » si ce n'était pas déjà fait et que cela vous est proposé Proposition d'auto-configuration du greffon Symfony

Outils de qualité de code (analyse statique de code)

Vous allez mettre en place des outils d'analyse statique de code pour garantir la qualité de l'application. Comme l'année dernière, vous utiliserez PHP CS Fixer pour vérifier et corriger le style de le code PHP. Vous utiliserez un outil équivalent pour le code Twig.

Travail à réaliser
  1. Installez PHP CS Fixer en vous référant au tutoriel Installation et configuration de PhpStorm pour configurer PHP CS Fixer
  2. Rendez-vous dans les préférences de PhpStorm dans « PHP → Quality Tools » et vérifiez que PHP CS Fixer est bien configuré Configuration de PHP CS Fixer dans PhpStorm
  3. Installez Twig CS Fixer, en pensant à exécuter la recette (recipe) :
    composer require --dev vincentlanglet/twig-cs-fixer
    ./composer.json has been updated
    Running composer update vincentlanglet/twig-cs-fixer
    Loading composer repositories with package information
    Updating dependencies
    Nothing to modify in lock file
    Writing lock file
    Installing dependencies from lock file (including require-dev)
    Nothing to install, update or remove
    Generating autoload files
    123 packages you are using are looking for funding.
    Use the `composer fund` command to find out more!
    
    Symfony operations: 1 recipe (dffb4f3dfb06b7c1bbc163a1f4fd34f6)
      -  WARNING  vincentlanglet/twig-cs-fixer (>=3.0): From github.com/symfony/recipes-contrib:main
        The recipe for this package comes from the "contrib" repository, which is open to community contributions.
        Review the recipe at https://github.com/symfony/recipes-contrib/tree/main/vincentlanglet/twig-cs-fixer/3.0
    
        Do you want to execute this recipe?
        [y] Yes
        [n] No
        [a] Yes for all packages, only for the current installation session
        [p] Yes permanently, never ask again for this project
        (defaults to n): y <-- répondre "y" ici
      - Configuring vincentlanglet/twig-cs-fixer (>=3.0): From github.com/symfony/recipes-contrib:main
    Executing script cache:clear [OK]
    Executing script assets:install public [OK]
    Executing script importmap:install [OK]
                  
     What's next? 
                  
    
    Some files have been created and/or updated to configure your new packages.
    Please review, edit and commit them: these files are yours.
    
     vincentlanglet/twig-cs-fixer  instructions:
    
    
     You can create a `.twig-cs-fixer.dist.php` and configure to your needs 
     See https://github.com/VincentLanglet/Twig-CS-Fixer/blob/main/docs/configuration.md 
     For configuration explanation. 
    
    No security vulnerability advisories found.
    Using version ^3.9 for vincentlanglet/twig-cs-fixer
    

Documentation du projet

Tout projet de développement doit fournir les clés pour l'installation, la configuration et le démarrage par un nouveau développeur. Cet effort de documentation peut également s'avérer bénéfique pour le créateur du projet qui peut oublier certains points essentiels de configuration au fil du temps. Ainsi, vous allez rédiger le mode d'emploi du projet dans un fichier « REAMDE.md » et le tenir à jour au fil du développement.

Travail à réaliser
  1. Créez le fichier « README.md » à l'aide de PhpStorm (qui vous propose de l'ajouter à l'index Git)
  2. Complétez les informations suivantes :
    1. un titre de niveau 1 contenant le titre explicite du projet
    2. un titre de niveau 2 « Auteur(s) » vous permettant de préciser votre nom et votre prénom (ainsi que ceux de votre binôme, le cas échéant)
    3. un titre de niveau 2 « Installation / Configuration » précisant les points essentiels permettant d'installer, de configurer et de lancer le projet
  3. Validez votre travail dans Git

Mise en place de scripts Composer

Les dépendances du projet Symfony sont gérées par Composer. Profitons-en pour mettre en place quelques scripts Composer qui faciliteront la gestion quotidienne du projet.

Travail à réaliser
  1. Ajoutez un script « start » qui lance le serveur web de test (« symfony serve ») sans restriction de durée d'exécution
  2. Ajoutez un script « test:phpcs » qui lance la commande de vérification du code par PHP CS Fixer
  3. Ajoutez un script « fix:phpcs » qui lance la commande de correction du code par PHP CS Fixer
  4. Ajoutez un script « test:twigcs » qui lance la commande de vérification du code par Twig CS Fixer
  5. Ajoutez un script « fix:twigcs » qui lance la commande de correction du code par Twig CS Fixer
  6. Ajoutez un script « test » qui lance les scripts Composer « test:phpcs » et « test:twigcs »
  7. Ajoutez un script « fix » qui lance les scripts Composer « fix:phpcs » et « fix:twigcs »
  8. Documentez vos scripts dans le fichier « composer.json »
  9. Documentez vos scripts dans le fichier « README.md »
  10. Validez votre travail dans Git
  11. Relancez le serveur Web local à l'aide du script Composer que vous venez d'écrire

Désactivation de Symfony UX Turbo

Depuis plusieurs versions de Symfony, Symfony UX Turbo est activé par défaut. Ce « bundle », faisant partie de l'initiative Symfony UX, apporte le support de Hotwire Turbo qui amène une expérience utilisateur de type application web monopage (SPA en anglais) sans avoir à écrire de Javascript. Le principal avantage est que les ressources liées (images, fichiers JavaScript, fichiers CSS, …) à la ressource principale (celle affichée dans la barre d'adresse du navigateur) ne sont pas rechargées à chaque changement d'URL. Ceci accélère significativement les temps de chargement et diminue la bande passante nécessaire. Cependant, dans le cadre de l'apprentissage des mécaniques Web, le fonctionnement de Hotwire Turbo transforme les intéractions client/serveur et perturbe votre compréhension du fonctionnement de Symfony. Vous allez donc le désactiver..

Travail à réaliser
  1. Ouvrez le fichier « assets/controllers.json »
  2. Désactivez le contrôleur Stimulus « @symfony/ux-turbo » en passant la valeur de l'attribut « enabled » à « false »:
    {
        "controllers": {
            "@symfony/ux-turbo": {
                "turbo-core": {
                    "enabled": false,
                    "fetch": "eager"
                    …

Le routeur

Dans le framework Symfony, un unique programme « public/index.php » est lancé pour chaque requête HTTP vers l'application et il est dépendant de l'environnement, par défaut « dev » pour développement et « prod » pour production. Le système de routage entre alors en jeu pour permettre de réaliser des tâches différentes en fonction de la requête HTTP soumise à l'application.

Travail à réaliser

Lisez les premiers paragraphes de la documentation sur le routage jusqu'à la fin de « Creating Routes as Attributes » et faites le lien avec la représentation graphique du flux applicatif : Symfony request flow

Les routes actuelles

Les routes disponibles sont potentiellement différentes en fonction de l'environnement de l'application. Il existe, par défaut, des routes accessibles dans les environnements « prod » et « dev » et des routes spécifiques à l'environnement de développement.

Travail à réaliser
  1. Observez les routes disponibles dans l'environnement de production :
    bin/console debug:router --env=prod
  2. Observez la configuration générale du routage en ouvrant le fichier « config/routes.yaml » qui décrit que le routage est défini dans les attributs de vos contrôleurs
  3. Observez les routes disponibles dans l'environnement de développement, qui est celui par défaut dans la configuration :
    bin/console debug:router

    Les routes disponibles dans l'environnement de développement sont actuellement, dans cet ordre :

    • Une route pour les erreurs Twig
    • une route « _wdt » qui correspondent à la « Web Debug Toolbar » Web Debug Toolbar
    • celles commençant par « _profiler » qui sont destinée au « Profiler » (profilage de l'application lors de son exécution)
  4. Observez la configuration du routage « Profiler » en ouvrant le fichier « config/routes/web_profiler.yaml »
  5. Vous constatez que les routes sont définies dans la configuration du « WebProfilerBundle » et uniquement dans l'environnement de développement avec « when@dev » en début de configuration

Liens entre route et contrôleur

Chaque route définie permet de déclencher une action d'un contrôleur (« Controller »). Une action est une méthode publique d'un contrôleur qui est associée à une URI, généralement à l'aide d'un attribut « Route » qui précède la méthode.

Les fichiers des contrôleurs sont localisés dans le répertoire « Controller » et sont nommés « xxxController.php », « xxx » étant le nom du contrôleur. Les contrôleurs font partie de l'espace de nom « App\Controller » ou d'un sous espace de nom de ce dernier. Ils héritent possiblement de « Symfony\Bundle\FrameworkBundle\Controller\AbstractController ».

Travail à réaliser
  1. Complétez vos connaissances en lisant au moins la partie « Creating Routes as Attributes » de la documentation.
  2. Créez un nouveau contrôleur « HelloController » à l'aide du « MakerBundle » :
    bin/console make:controller Hello
    Information

    Le « MakerBundle » peut fonctionner en mode interactif ou à l'aide de paramètres de la ligne de commande. Ici, vous avez fourni le paramètre « Hello » qui correspond au nom du contrôleur que vous souhaitez. Ce dernier sera donc nommé « HelloController » car le « MakerBundle » ajoute automatiquement le suffixe « Controller » que vous n'aviez pas précisé.

  3. Ouvrez le fichier du contrôleur dans PhpStorm
  4. Observez l'ensemble des routes disponibles pour l'application avec la commande
    bin/console debug:router
  5. Observez l'ensemble des routes disponibles pour l'application ainsi que les contrôleurs associés avec la commande
    bin/console debug:router --show-controllers
  6. Faites le lien entre la première route disponible et le code généré par le « MakerBundle »
  7. Observez les détails de la route nommée « app_hello » grâce à la commande
    bin/console debug:router app_hello
  8. Ajoutez l'action et la route associée qui suivent dans le contrôleur :
        #[Route('/hello/world')]
        public function world(): Response
        {
            return new Response('Hello world!');
        }
    
  9. Notez que cette route ne comporte pas de nom dans l'attribut « #[Route( » et faites le lien avec le nom généré automatiquement que vous observez à l'aide de la commande
    bin/console debug:router
  10. Essayez l'URL « http://localhost:8000/hello/world »
  11. Regardez le code source HTML du contenu reçu par le navigateur
  12. Essayez l'URL « http://localhost:8000/hello/guys »
  13. Constatez la réponse reçue par le navigateur et son code HTTP

Route contenant un paramètre

Les routes ne sont pas nécessairement définies à partir d'un URI fixe qui permet de déclencher une action d'un contrôleur. Il est en effet possible de rendre paramétriques des parties de l'URI.

Travail à réaliser
  1. Complétez vos connaissances en lisant au moins la partie « Route Parameters » de la documentation.
  2. Remplacez le texte « world » du chemin « /hello/world » de la route par un paramètre « name »
  3. Adaptez le prototype de l'action « world() » afin qu'elle puisse recevoir la valeur du paramètre « name » de la route
  4. Observez la nouvelle formulation de la route de l'application avec la commande
    bin/console debug:router
  5. Remplacez le mot « world » de la chaîne « Hello world! » par la valeur du paramètre de l'action
    Information

    Ce que vous venez de faire est extrêmement dangereux puisque toute chaîne fournie dans l'URL va se retrouver directement dans la réponse envoyée au navigateur, constituant ainsi une possibilité d'attaque XSS reflétée. Il faudrait échapper la valeur de la variable « $name », comme cela vous a déjà été démontré à plusieurs reprises dans les précédents sujets de TP.

  6. Essayez l'URL « http://localhost:8000/hello/world »
  7. Essayez l'URL « http://localhost:8000/hello/bob »
  8. Constatez la réponse reçue par le navigateur et son code HTTP
  9. Remarquez le lien entre le paramètre « name » du chemin de la route et le paramètre « $name » de l'action

Les vues dans Symfony : Twig

Maintenant que vous avez rendu paramétrique l'action world() du contrôleur HelloController, vous allez lui associer le rendu d'une vue Twig.

Web Debug Toolbar

La « Web Debug Toolbar » n'est activée que si la vue contient la balise de fin de corps d'une page Web </body>.

Travail à réaliser
  1. Saisissez l'URL « http://localhost:8000/hello/world » dans le navigateur
  2. Dans l'action « world() » du « HelloController », demandez le rendu d'un modèle Twig en remplaçant l'instruction
    return new Response('…
    par
    return $this->render('hello/world.html.twig');
  3. Essayez l'URL « http://localhost:8000/hello/world »
  4. Constatez l'erreur signalée par Symfony ainsi que le code réponse HTTP reçu par le navigateur
  5. Créez le fichier « world.html.twig » manuellement en effectuant un clic droit sur le répertoire « templates/hello » dans PhpStorm et en utilisant le menu « New » puis « File »
  6. Essayez l'URL « http://localhost:8000/hello/world »
  7. Constatez la réponse vide reçue par le navigateur
  8. Ajoutez le texte « Hello world! » dans le fichier « templates/hello/world.html.twig »
  9. Essayez l'URL http://localhost:8000/hello/world
  10. Constatez que la « Web Debug Toolbar » n'est pas présente
  11. Regardez le code source HTML du contenu reçu par le navigateur
  12. Faites en sorte que le fichier « templates/hello/world.html.twig » propose une structure HTML correcte dont le titre sera « Hello World! » et qui contiendra le paragraphe « Hello World! »
  13. Essayez l'URL « http://localhost:8000/hello/world »
  14. Notez l'apparition de la « Web Debug Toolbar ».
  15. Cliquez sur un des éléments de la « Web Debug Toolbar » pour accéder au profileur
  16. Naviguez dans les pages du profileur afin d'en découvrir les possibilités

Transmettre des données à la vue

La vue a pour objectif de présenter les données à l'utilisateur. Vous allez donc découvrir comment transmettre des données au modèle Twig et comment les exploiter.

Travail à réaliser
  1. Saisissez l'URL « http://localhost:8000/hello/bob » dans le navigateur
  2. Lisez et observez les exemples de « Rendering Templates » et « Creating Templates »
  3. Passez la valeur du paramètre de l'action à la vue
    Information

    Vous avez remarqué que le paramètre du chemin de la route « {name} » se retrouve sous le même nom « $name » comme paramètre de l'action (et c'est d'ailleurs par rapport au nom que Symfony fait « automagiquement » la correspondance entre les deux). Lorsque vous passez la même valeur à la vue, vous devez choisir le nom sous lequel la donnée sera manipulée dans le modèle Twig. Afin de maintenir une logique globale et faciliter la compréhension du code, il est vivement conseillé de préserver le même nom pour l'utilisation dans le modèle Twig.

  4. Utilisez la valeur dans la vue pour produire « Hello la_valeur_du_paramètre! » dans le titre du document HTML et dans le paragraphe
  5. Vérifiez le bon fonctionnement de cette nouvelle version de la vue dans le navigateur Web
  6. Saisissez l'URL « http://localhost:8000/hello/bob<script> » dans le navigateur (oui, il y a bien « <script> » à la fin de l'URL !)
  7. Observez le résultat dans le navigateur
  8. Observez le code source HTML du résultat dans le navigateur

Héritage et inclusion de « templates » Twig

Vous venez de réaliser une vue à l'aide de « templates » Twig. Cependant, la constitution de plusieurs vues ne devrait pas demander d'écrire une page Web complète pour chacune d'entre elles. Il est possible d'éviter ce genre de répétition en utilisant l'héritage ou l'inclusion de « templates ». Pour y parvenir, il convient de respecter les conventions de nommage et d'emplacement des modèle Twig.

Travail à réaliser
  1. Modifiez la vue « world.html.twig » afin qu'elle hérite de « base.html.twig »
  2. Remplacez la structure HTML du modèle par l'utilisation des blocs définis dans « base.html.twig »
    Information

    Profitez des suggestions de PhpStorm pour retrouver simplement les noms des blocs disponibles hérités du modèle « base.html.twig ».

  3. Accédez à « http://localhost:8000/hello/bob »
  4. Vérifiez le code source du résultat dans le navigateur
  5. Constatez tous les éléments CSS et JavaScript ajoutés au code source final par l'héritage

Prise en main rapide de Twig

Vous allez explorer quelques-unes des possibilités offertes par Twig.

Travail à réaliser
  1. Utilisez une structure algorithmique Twig « for » pour afficher 10 fois le paragraphe de salutation dans le nouveau « template »
  2. Modifiez le texte produit pour y inclure le numéro du tour de boucle de 1 à 10 en fin de ligne (le résultat est donc de la forme « Hello bob! (6) »)
  3. Utilisez la fonction « cycle » de Twig pour afficher alternativement en rouge puis vert (un attribut HTML « style="" » suffira pour cet essai.
  4. Ajoutez un filtre sur le nom afin qu'il apparaisse avec la première lettre en majuscule
  5. Installez le paquet Composer « twig/intl-extra » pour bénéficier des fonctions d'internationalisation de Twig
  6. Formatez le nombre de 1 à 10 pour qu'il soit systématiquement affiché sur deux caractères

De la route à la vue

Vous allez créer une nouvelle route, une nouvelle action dans le contrôleur ainsi qu'un nouveau « template » Twig associé. L'action permettra d'afficher le message de salutation un nombre de fois donné.

Création d'une nouvelle route

Vous allez ajouter une nouvelle route pour découvrir de nouvelles possibilités du routeur de Symfony.

Travail à réaliser
  1. Consultez les règles de bonnes pratiques concernant les contrôleurs
  2. Créer une action vide « manyTimes() » dans le contrôleur « HelloController »
    Information

    En saisissant « pubf » suivi de « TAB » dans une classe, PhpStorm génère automatiquement

        public function ()
        {
            
        }

    Vous êtes alors prêt à saisir le nom de la méthode et un nouvel appui sur TAB fait passer le focus sur la saisie des paramètres de la méthode.

  3. Associez une route de chemin « /hello/name/times » paramétré par « name » et « times » à cette action en ajoutant l'attribut « #[Route(… »
  4. Si vous décidez de nommer la route, utilisez le nommage standard « app_nomducontroleur_nomdelaction » (c'est un exemple !)
  5. Modifiez l'action pour que ses paramètres soient en accord avec ceux du chemin de la route
  6. Consultez les règles de bonnes pratiques concernant le nommage des modèles Twig
  7. Retournez le résultat la méthode « render() » du modèle « hello/many_times.html.twig »
  8. Utilisez les suggestions de PhpStorm (« Alt+Entrée ») pour générer automatiquement ce nouveau modèle : Twig: Create Template
    Remarque importante

    Si la génération automatique du « template » n'est pas proposée par PhpStorm, c'est que vous n'avez pas installé le plugin Symfony : Symfony plugin installed que vous ne l'avez pas activé lorsque cela vous a été proposé : Symfony plugin enabled ou qu'il n'est pas actif pour ce projet : Symfony plugin enabled for this project

  9. Modifiez le code Twig en prenant « world.html.twig » comme base :
    • Remplacez le titre de la page Web par « Hello many times! »
    • Remplacez le paragraphe de salutation par « Hello many times valeur_du_paramètre_name! »
    • Remplacez l'alternance des couleurs par une alternance entre bleu et orange
    • Affichez « times » fois le paragraphe de salutation
  10. Essayez l'URL « http://localhost:8000/hello/bob/5 » et vérifiez le bon fonctionnement

Ajout de conditions sur les paramètres

Le routage de Symfony permet de vérifier que les paramètres répondent à certaines conditions pour pouvoir déclencher une route.

Travail à réaliser
  1. Complétez la route pour que son second paramètre times soit un chiffre en utilisant la validation de paramètres
  2. Essayez l'URL « http://localhost:8000/hello/bob/five » et vérifiez que la validation du paramètre « times » fonctionne (et donc que la route n'est pas acceptée !)
  3. Vérifiez dans l'action du contrôleur que « times » est bien différent de zéro et inférieur ou égal à 10. Fixez sa valeur à 3 dans le cas contraire
  4. Essayez les URL « http://localhost:8000/hello/bob/5 », « http://localhost:8000/hello/bob/0 » ainsi que « http://localhost:8000/hello/bob/42 » et vérifiez la cohérence du résultat produit
  5. Rendez le paramètre « times » optionnel qui vaudra par défaut « 3 ».
  6. Utilisez la « Web Debug Toolbar » pour visualiser quelle est la route déclenchée par l'URL « http://localhost:8000/hello/bob »
  7. Faîtes en sorte que ce soit la route « app_hello_manytimes » qui soit déclenchée par l'URL « http://localhost:8000/hello/bob » (ceci doit mettre en évidence la façon dont les routes sont étudiées par Symfony)

Redirection dans le contrôleur

Les contrôles que vous venez d'effectuer conduisent à une forme d'incohérence de l'application. En effet, si vous demandez l'URL « /hello/bob/42 », les conditions ajoutées dans le contrôleur vont limiter l'affichage à 3 messages alors que l'URL contient toujours « 42 ». Il serait souhaitable dans ce cas que le « 42 » de l'URL soit remplacé par « 3 ». En raisonnant du côté serveur, il faut donc effectuer une première réponse à la requête de « /hello/bob/42 » qui demande une redirection vers « /hello/bob/3 » afin que le navigateur effectue une nouvelle demande de ressource, correcte cette fois.

Travail à réaliser
  1. Observez l'incohérence entre l'« URL » « /hello/bob/42 » demandée et les 3 messages affichés dans le navigateur
  2. Lisez le chapitre concernant les redirections
  3. Effectuez une redirection dans l'action « manyTimes() » en demandant seulement « 3 » affichages lorsque le paramètre « times » est hors des bornes fixées précédemment
    Information

    Si vous tapez les guillemets du premier paramètre de la méthode « redirectToRoute() », PhpStorm doit vous proposer la liste de routes disponibles. Suggestion de routes dans redirectToRoute(

  4. Vérifiez le fonctionnement en observant la redirection de « /hello/bob/42 » dans la barre de développement de le navigateur (pensez à cocher « Preserve log » pour pouvoir visualiser la réponse de redirection)

De la vue à la route

Symfony et son modèle de routeur prévoient de ne jamais écrire manuellement des URL vers les ressources de l'application. Les URL doivent être produites automatiquement en Twig en se basant sur le nom de la route correspondant à l'URL souhaitée.

Travail à réaliser
  1. Faites le ménage dans l'action « index() » qui avait été générée par le « MakerBundle » dans le contrôleur « HelloController » pour ne préserver que le rendu de la vue
  2. Faites également le ménage dans le modèle associé « hello/index.html.twig » en supprimant le contenu de tous les blocs hormis le titre
  3. Consultez les règles de production de liens vers des ressources de l'application
  4. Dans une liste à puces, créez un lien relatif qui permet de produire le résultat de « 5 » « Hello » à « Joe »
    Information

    PhpStorm peut vous proposer les routes existantes dans les fonctions Twig « path() » ou « url() », profitez-en.

  5. Dans la liste à puces, ajoutez un lien absolu qui permet de produire le résultat de « 8 » « Hello » à « Bob »
  6. Vérifiez le bon fonctionnement de vos liens
  7. Vérifiez que vos deux liens sont bien respectivement relatif et absolu en observant le code HTML reçu par le navigateur

Introduction aux tests fonctionnels

Vous avez été sensibilisés aux tests pendant le « TP Développement d'une application Web de consultation et modification de morceaux de musique ». Vous avez certainement remarqué le répertoire « tests » dans l'arborescence de Symfony. Il contiendra les tests unitaires, d'intégration ou fonctionnels associés à vos classes.

Symfony est nativement prévu pour fonctionner avec PHPUnit grâce au « PHPUnit Bridge ». Pour des raisons de simplicité d'écriture et de facilité de compréhension, nous utiliserons plutôt Codeception qui possède un module pour Symfony.

Installation et configuration de Codeception

Travail à réaliser
  1. Installez Codeception et ses modules « asserts » et « symfony » à l'aide de Composer :
    composer require --dev --no-interaction codeception/codeception codeception/module-asserts codeception/module-symfony
    Information

    L'option « --no-interaction » permet d'éviter toute interaction lors de l'installation. Dans ce cas particulier, il ne vous sera donc pas demandé si vous souhaitez appliquer les recettes Flex de Codeception. Si toutefois la question vous est tout de même posée, nous ne souhaitons pas les appliquer car cela crée de nombreux répertoires et fichiers dans « tests » et nous n'en avons pas l'utilité.

  2. Initialisez Codeception pour le projet :
    php vendor/bin/codecept bootstrap --namespace=App\\Tests --empty
  3. Chargez les paramètres de configuration de Codeception selon l'environnement de Symfony en complétant le fichier « codeception.yml » :
    params:
        - .env
        - .env.test
    
    

Tests de l'action « manyTimes() » du contrôleur « HelloController »

Travail à réaliser
  1. Créez une nouvelle suite de tests que nous dédirons aux contrôleurs :
    php vendor/bin/codecept generate:suite Controller
  2. Mettez au propre le source PHP généré :
    composer fix:phpcs
    Information

    Les scripts Composer peuvent être lancés en omettant une partie de leur nom, tant qu'il n'y a pas d'ambiguïté. Ici, « composer fix:p » est équivalent à « composer fix:phpcs ».

  3. Créez un « Cest » (« Codecept » + « Test ») dédié à l'action « manyTimes() » du « HelloController » :
    php vendor/bin/codecept generate:cest Controller Hello\\ManyTimes
    Information

    Si vous êtes sur Windows et que vous utilisez le terminal cmd ou PowerShell, le caractère « \ » n'a pas le même sens qu'en environnement Linux ou MacOS. Il n'est donc nécessaire de le doubler dans la ligne de commande.

  4. Mettez au propre le source PHP généré :
    composer fix:phpcs
  5. Activez les modules « Symfony » et « Asserts » de la suite « Controller » en remplaçant la clé « modules » dans le fichier « tests/Controller.suite.yml » :
    modules:
        # enable helpers as array
        enabled:
            - Symfony:
                  app_path: 'src'
                  environment: 'test'
            - Asserts:
    
  6. Lancez la construction des classes « Actor » de Codeception pour prendre en compte les nouveaux modules :
    php vendor/bin/codecept build
  7. Testez le style du code PHP :
    composer test:phpcs
    Information

    Les fichiers PHP dont le style n'est pas conforme sont générés par Codeception et exclus du dépôt Git. Il est donc nécessaire de modifier la configuration de PHP CS Fixer pour qu'il n'essaie pas de les corriger.

  8. Modifiez la configuration de PHP CS Fixer dans le fichier « .php-cs-fixer.dist.php » pour exclure le répertoire « tests/Support/_generated »
  9. Testez de nouveau le style du code PHP pour vérifier que le répertoire est bien exclu de l'analyse :
  10. Remplacez le fichier des tests du contrôleur par l'ensemble de tests « ManyTimesCest.php » (télécharger)
    Information

    Ces tests fournis sont assez détaillés pour que vous les utilisiez comme base d'exemple.

  11. Lancez les tests à l'aide de la commande
    php vendor/bin/codecept run
  12. Vérifiez que le code passe les tests

Ajout de scripts Composer pour lancer les tests

Travail à réaliser
  • Ouvrez le fichier « composer.json »
  • Ajoutez un script « test:codeception » qui
  • Complétez le script « test » pour qu'il lance le précédent script à la suite de ceux déjà présents
  • Décrivez ces scripts Composer dans « composer.json » et dans la documentation du projet

Configuration de l'accès base de données de l'application

Vous avez utilisé l'outil « symfony » en ligne de commande pour créer le projet d'application Symfony. Des valeurs par défaut ont été affectés à divers paramètres de configuration dans le fichier « .env » situé à la racine du projet.

Remarque importante

Le fichier « .env » sera inclus dans le dépôt Git. Il est donc vital qu'il ne contienne pas vos mots de passe ! Il servira uniquement de base à la configuration en mentionnant les paramètres à définir. La configuration effective de l'application locale se fera dans le fichier « .env.local ». Ce dernier est par défaut exclu du gestionnaire de versions et doit le rester.

Travail à réaliser
  1. Dans le fichier « .env », observez les exemples de configuration de la base de données à travers les valeurs de la variable « DATABASE_URL »
    Information

    Les lignes commençant par « # » sont des commentaires et ne sont pas prises en compte dans la configuration. Elles servent ici à donner des exemples de configuration.

  2. Afin de faciliter le travail de correction de votre production, modifiez la ligne en commentaire de la variable « DATABASE_URL » dans le fichier « .env » pour qu'elle corresponde à une base de données MariaDB version 10.2.25
    # DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
    DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
    
    devient
    DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.2.25-MariaDB&charset=utf8mb4"
    # DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
  3. Copiez le fichier « .env » en « .env.local » à partir de PhpStorm et ouvrez-le
  4. Donnez les valeurs adéquates à la variable DATABASE_URL afin de vous connecter sur le serveur dont le nom DNS est « mysql » accessible avec l'utilisateur « web » dont le mot de passe est « web » (ou selon vos paramètres si vous êtes sur votre ordinateur personnel) pour accéder à la base de données MySQL (MariaDB 10.2.25) nommée « cutron01_contact_demo »
    Information

    Retrouvez les parties constitutives d'une URL dans le sujet de TP sur le proptocole HTTP que vous avez réalisé en première année.

    Si vous souhaitez travailler sur votre ordinateur personnel, vous pouvez télécharger le script de création de la base de données (Clic droit puis « Enregistrer sous… »).

  5. Vérifiez l'accès à la base de données :
    bin/console doctrine:query:sql "SELECT * FROM contact WHERE id=4"

    Vous devriez obtenir une ligne de résultat :

     ---- ----------- ---------- ------------------------------ 
      id   firstname   lastname   email                         
     ---- ----------- ---------- ------------------------------ 
      4    Christine   Michaud    christine.michaud@raynaud.fr  
     ---- ----------- ---------- ------------------------------ 
    

Consultation des contacts

Le modèle de données étant à présent configuré, il est temps de l'utiliser. Pour cela, vous allez construire une nouvelle fonctionnalité de listage de l'ensemble des contacts de la base de données.

Modèle de données

Symfony intègre Doctrine pour effectuer la persistance et l'accès aux données dans une base de données. L'interaction entre l'application et la base de données se fera à travers des objets PHP appelés des entités qui constituent la logique métier de l'application ainsi que les relations entre les entités. Par convention, les définitions de ces classes seront localisées dans le répertoire src/Entity.

Afin que ces classes puissent interagir avec le SGBD, il convient de définir les liens entre les objets PHP et la base de données. Cette opération est qualifiée de « mapping » qui est décrit sous forme d'attributs PHP dans la définition de la classe. Le « mapping » peut être réalisé manuellement ou de façon interactive à l'aide du « MakerBundle ».

Vous avez configuré l'application pour accéder à la base de données « cutron01_contact_demo » : La table contact de la base de données

Information

La démarche habituelle pour un projet Symfony est de créer les entités et leurs relations en fonction des besoins révélés par la phase d'analyse, puis de créer la base de données à l'aide de Doctrine, pour ensuite insérer des données factices qui permettent d'obtenir une application de démonstration pour le développement. Nous dérogeons temporairement à cette règle pour des raisons de progression pédagogique en vous fournissant une base de données qui contient déjà des données générées par nos soins.

Travail à réaliser
  1. Lisez le paragraphe « Creating an Entity Class »
  2. Utilisez le « MakerBundle » pour générer l'entité « Contact » conformément à la table MySQL :
    bin/console make:entity Contact
    en donnant les propriétés suivantes :
    • « firstname » de type « string » de taille « 30 » non « nullable »
    • « lastname » de type « string » de taille « 40 » non « nullable »
    • « email » de type « string » de taille « 100 » non « nullable »
  3. Actualisez la liste des fichiers du répertoire « Entity » par un clic droit sur la racine du projet puis « 🗘 Reload from disk »
  4. Observez le fichier généré dans le répertoire « src/Entity »
  5. Consultez la classe générée et expliquez les divers attributs PHP.
  6. Observez le fichier généré dans le répertoire « src/Repository »

Liste des contacts

Travail à réaliser
  1. Créez un nouveau contrôleur « ContactController » à l'aide du « MakerBundle »
  2. Lisez le chapitre « Récupérer des objets dans la base de données » de la documentation de Symfony
  3. Supprimez tous les éléments inutiles de l'action et de la vue ainsi que les paramètres passés à la vue
  4. En paramètre de l'action « index() » générée par défaut, demandez le service « ContactRepository »
  5. Dans l'action, utilisez la méthode « findBy() » de la classe « EntityRepository » afin de récupérer l'ensemble des contacts de la base de données (critère de sélection vide) par ordre alphabétique (tri ascendant sur le nom puis le prénom)
  6. Transmettez l'ensemble des contacts à la vue Twig
  7. Donnez un titre au contenu Web produit et proposez un titre de niveau 1 représentatif
  8. Dans la vue, effectuez le parcours de l'ensemble des contacts pour produire une liste à puces présentant chaque contact sous la forme « nom, prénom »
  9. Vérifiez que la liste s'affiche correctement

Tests fonctionnels

Afin de poursuivre les tests fonctionnels, vous allez mettre en place des contrôles sur le résultat de la liste des contacts.

Information

La démarche des tests liés à la consultation de la base de données est ici incomplète (voire incorrecte) puisque nous nous appuyons sur la base de données de développement. Ceci vous permet néanmoins de prévoir les tests et la démarche sera rectifiée par la suite.

Travail à réaliser
  1. Copiez le fichier d'environnement de test « .env.test » en « .env.test.local »
  2. Définissez la variable contenant le chemin d'accès à la base de données comme dans l'environnement de développement
  3. Ajoutez ce nouveau fichier à la liste des paramètres de configuration de Codeceptiona> dans le fichier de configuration de Codeception « codeception.yml »
  4. Mettez en commentaire la propriété « dbname_suffix » de « when@test.doctrine.dbal » du fichier « config/packages/doctrine.yaml » pour éviter d'ajouter « _test » à la fin du nom de la base de données de test
  5. Générez une classe de « Cest » pour l'action « index() » du « ContactController » :
    php vendor/bin/codecept generate:cest Controller Contact\\Index
  6. Supprimez les méthodes de la classe générée (« _before() » n'est pas utile et « tryToTest() » est un exemple)
  7. Sur le modèle des tests présentés en début de TP, écrivez une méthode de test « contactListContainsRightNumberOfContacts() » permettant de contrôler que la ressource « /contact » donne une réponse HTTP 200 et que le corps de la réponse vérifie que :
    • le titre de la page Web contient « Liste des contacts »
    • un titre de niveau 1 contenant « Liste des contacts » est présent
    • une liste à puce contient 195 éléments
    Information

    Profitez des suggestions de PhpStorm au fil de la saisie du code pour découvrir les méthodes à utiliser.

Remarque importante

Codeception enregistre dans le répertoire « tests/_output » le corps de la réponse HTTP des ressources impliquées dans des tests échoués. Consultez ces contenus, ceci facilite grandement la recherche des erreurs !

Détails d'un contact, version naïve

Vous allez à présent rechercher un contact pour afficher le détail de ses données. Cette recherche va s'effectuer de façon naïve à partir de l'identifiant du contact. Ceci permet de comprendre la mécanique et d'arriver en douceur au « ParamConverter » dans la partie suivante.

Travail à réaliser
  1. Dans le contrôleur « ContactController », créez une action « show(int $contactId) » qui reçoit en paramètre un identifiant de contact
  2. Associez une route de chemin « /contact/{contactId} » à la nouvelle action
  3. Appliquez les conditions requises à « contactId »
  4. Dans la nouvelle action, demandez le rendu de la vue Twig « contact/show.html.twig »
  5. Générez le fichier Twig à l'aide de PhpStorm
  6. Vérifiez la bonne interaction de ces trois éléments
  7. En paramètre de l'action « show() », demandez le service « ContactRepository »
  8. Dans l'action, récupérez le contact concerné et transmettez-le à la vue
  9. Si le contact n'existe pas, levez une « NotFoundHttpException » dont le texte doit être explicite
  10. Présentez le nom et le prénom du contact dans le titre du document HTML et dans un titre de niveau 1
  11. Présentez toutes les informations du contact (hormis l'identifiant) dans une liste de définitions
  12. Vérifiez que la route produit un résultat conforme
  13. Vérifiez que la route produit une réponse « 404 » pour un identifiant de contact qui n'existe pas
    Information

    Vous ajouterez des tests pour cette action dès que vous aurez des générateurs de données fictives.

Détails d'un contact, utilisation d'un « EntityValueResolver »

Vous allez à présent rechercher un contact en utilisant un « EntityValueResolver » comme préconisé dans les bonnes pratiques. Cette démarche permet de simplifier le code.

Travail à réaliser
  1. Dans le contrôleur « ContactController », modifiez le chemin de la route « /contact/{contactId} » pour que le nom du paramètre corresponde au nom de l'identifiant de l'entité « Contact »
  2. Modifiez les paramètres de l'action « show() » pour :
    • Remplacer l'identifiant de contact par un « Contact »
    • Supprimer le service « ContactRepository » qui sera inutile
  3. Maintenez les conditions requises sur le paramètre du chemin de la route
  4. Supprimez le code maintenant inutile de l'action, en particulier le test
  5. Vérifiez que la route produit toujours un résultat conforme
  6. Vérifiez que la route produit une réponse « 404 » pour un identifiant de contact qui n'existe pas

Des routes pour produire des URL

Vous venez de construire une liste de contacts et les détails d'un contact. Il convient à présent de rendre accessible les détails d'un contact par un clic sur son nom dans la liste des contacts. Vous n'écrirez pas d'URL mais utiliserez les fonctionnalités Twig permettant de les produire à votre place à partir du nom des routes.

Travail à réaliser
  1. Si nécessaire, relisez le chapitre « Linking to Pages » de la documentation
  2. Modifiez la vue « contact/index.html.twig » afin qu'elle propose à présent des liens vers les détails du contact sur chaque nom de contact
  3. Vérifiez que les liens sont correctement produits et fonctionnels
  4. Améliorez le précédent test fonctionnel pour qu'il vérifie que la liste à puces contient 195 liens
  5. Écrivez un nouveau test permettant de cliquer sur le premier lien de la liste des contacts et de vérifier que la route obtenue est la bonne (sans tenir compte du paramètre de route)

Mise en place de votre propre base de données, retour aux bonnes pratiques

Dans la partie précédente, vous avez consulté une base de données existante. La démarche habituelle lors de la création d'un projet Symfony est de construire de nouvelles entités liées entre elles par des relations, de gérer des versions des entités et de la base de données et de remplir la base de données avec des données, factices ou non, permettant de faire fonctionner le projet complet directement après clonage. Vous allez donc à présent suivre cette démarche et apprendre à construire des données factices générées aléatoirement à partir de « Faker ».

Création de la base de données

Avant de pouvoir créer la base de données, vous allez devoir modifier la configuration pour accéder à votre propre base de données MySQL.

Travail à réaliser
  1. Ouvrez le fichier de la configuration locale du projet
  2. Modifiez la configuration base de données pour :
    • Utiliser votre compte MySQL en lieu et place de l'utilisateur « web »
    • Modifiez la base de données utilisée en « votre_login_contact »
    • Mettez la valeur du paramètre « serverVersion » en accord avec le serveur MySQL du département, à savoir « mariadb-10.2.25 »
      Information

      La valeur de « serverVersion » doit impérativement être correcte pour que les migrations fonctionnent. En effet, MySQL et MariaDB n'ont pas la même façon d'accéder aux méta-informations de la base de données.

  3. Lancez la création de la base de données :
    bin/console doctrine:database:create
  4. Sur phpMyAdmin, vérifiez que la base a bien été créée

Création d'une migration de données

Rappelons que vous avez créé une entité « Contact ». Cette entité n'est plus persistante, maintenant que la base de données de démonstration a été débranchée. Vous allez donc reprendre le cours normal de la création du projet en effectuant avec Doctrine la synchronisation entre les entités et la base de données pour que la structure de la base de données soit équivalente à celle de l'ensemble des entités.

Puisque vos entités peuvent évoluer au fil des fonctionnalités développées, il est normal que la base de données évolue de la même façon. Cependant, contrairement à la base de données de développement qui peut être détruite sans danger, la base de données de production doit pouvoir être modifiée sans perte ni corruption de données. C'est l'objectif des migrations qui vont contenir les requêtes permettant de faire évoluer la base de données.

Travail à réaliser
  1. Lancez la construction de la première migration
    bin/console make:migration
  2. Observez le contenu de la migration générée dans le répertoire « migration »

Création du schéma de la base de données

Les migrations contiennent l'ensemble des requêtes SQL permettant d'appliquer et de supprimer la mise à jour de la base de données à un instant donné de l'évolution du projet. Doctrine maintient l'état des migrations appliquées sur la base de données dans une table « doctrine_migration_versions ». Ainsi, la comparaison de l'ensemble des fichiers contenus dans le répertoire « migrations » et du contenu de la table « doctrine_migration_versions » permet de connaître les migrations à appliquer pour que la structure de la base de données soit à jour.

Travail à réaliser
  1. Lancez l'exécution des migrations
    bin/console doctrine:migrations:migrate --no-interaction
  2. Sur phpMyAdmin, vérifiez la présence, la structure et le contenu de la table « doctrine_migration_versions »
  3. Vérifiez la présence, la structure et le contenu de la table « contact »
  4. Vérifiez que l'affichage de la liste des contacts fonctionne toujours, mais ne contient aucun contact

Générateur de données factices

Pour faciliter la démarche de remplissage de la base de données de développement, vous utiliserez les bundles « DoctrineFixturesBundle » et « ZenstruckFoundryBundle ». Le premier permet de gérer la création de données factices (« fixtures ») avec Doctrine. Le second propose de faciliter le processus de création d'une entité en définissant les valeurs par défaut des propriétés d'une nouvelle instance, souvent générées aléatoirement avec « Faker ». Par ailleurs, les méthodes « create*() » des « Factory » génèrent de nouvelles instances mais les font aussi persister automatiquement en base de données.

Travail à réaliser
  1. Utilisez Composer pour demander le bundle « orm-fixtures » pour le développement (ne pas oublier l'option « --dev » !)
  2. Observez les nouveaux fichiers à l'aide de l'onglet « Commit » de PhpStorm
  3. Effectuez un « commit » avec ces fichiers
  4. Utilisez Composer pour demander le bundle « zenstruck/foundry » pour le développement
  5. Observez les nouveaux fichiers à l'aide de l'onglet « Commit » de PhpStorm
  6. Effectuez un « commit » avec ces fichiers
  7. Parcourez la documentation du « DoctrineFixturesBundle »
  8. Lancez la création d'un générateur de données pour les contacts :
    bin/console make:fixtures ContactFixtures
  9. Observez le contenu du fichier généré et supprimez le corps de la méthode « load() » qui sera complété dans quelques instants
    Information

    Le code d'exemple qui est proposé lors de la génération du fichier s'applique lorsque l'on utilise directement Doctrine. Puisque nous utilisons « Foundry » pour nous faciliter la tâche, il est hors de propos.

  10. Effectuez un « commit » avec ce fichier
  11. Lisez le chapitre « Generate » et de la documentation de « Foundry »
  12. Lancez la création d'une nouvelle forge de données :
    bin/console make:factory
  13. Observez le fichier généré
  14. Effectuez un « commit » avec ce fichier
  15. Modifiez la méthode « defaults() » pour que :
  16. Puisque certains noms de famille et certains prénoms composés contiennent des espaces incompatibles avec la structure d'une adresse email, il est plus sûr de remplacer tout caractère non alphabétique par un tiret
  17. Vous devez effectuer des traitements identiques sur le nom et sur le prénom de l'utilisateur en vue de construire son mail, proposez une méthode protégée « normalizeName » qui effectue ces traitements et qui sera utilisée par « defaults() »
  18. Votre méthode construit un « Transliterator » à chaque appel, ce qui est inutile et inefficace : construisez le « Transliterator » dans le constructeur de la classe, stockez-le dans une propriété d'instance et utilisez-le dans « normalizeName() »
  19. Effectuez un « commit » avec ce fichier
  20. Lisez les exemples du paragraphe « Using your Factory » de la documentation de « Foundry »
  21. Modifiez le générateur de données de « Contact » pour qu'il crée 150 « Contact » en utilisant la forge précédemment construite
    Information

    Vous avez certainement envie de générer les données factices mais il va falloir attendre un peu !

Génération de la base de données et des données factices

A ce stade, vous pourriez générer les données factices en base de données. Malheureusement, si vous avez commis des erreurs dans votre code et tentez de générer un nouveau jeu de données corrigé, elles vont se cumuler avec les anciennes. Pour palier ce problème, vous allez créer un script Composer qui reprend toutes les étapes précédentes pour générer de façon fiable une nouvelle base de données contenant les données factices.

Travail à réaliser
  1. Créez un script Composer « db » qui exécute les étapes suivantes :
    • Destruction forcée de la base de données
      bin/console doctrine:database:drop --force --if-exists
    • Création de la base de données
      bin/console doctrine:database:create
    • Application des migrations successives sans questions interactives
      bin/console doctrine:migrations:migrate --no-interaction
    • Génération des données factices sans questions interactives
      bin/console doctrine:fixtures:load --no-interaction
  2. Documentez ce script dans le fichier « composer.json »
  3. Documentez ce script dans le fichier « README.md »
  4. Puisque cela n'a pas été fait auparavant, documentez la configuration de la base de données dans « README.md »
  5. Lancez le script Composer « db »
  6. Observez le contenu de la table « contact » dans phpMyAdmin
  7. Réalisez le même type d'observation en utilisant la console, par exemple avec :
    bin/console doctrine:query:sql "SELECT * FROM contact LIMIT 5"
    Information

    Il est essentiel de vérifier la pertinence de toutes les données générées. Il faut vérifier toutes les lignes et toutes les colonnes pour avoir une vision globale de la cohérence de ce qui est produit, aléatoirement ou pas.

  8. En vous inspirant de la documentation de « Faker » dans « Foundry », modifiez la configuration de « Faker » qui qu'il génère des textes en français
  9. Réinitialisez la base de données et contrôlez les données produites qui doivent ressembler à :
    bin/console doctrine:query:sql "SELECT * FROM contact LIMIT 5"
     ---- ----------- ----------- ------------------------------ 
      id   firstname   lastname    email                         
     ---- ----------- ----------- ------------------------------ 
      1    Édith       Gregoire    edith.gregoire@perez.com      
      2    Adélaïde    Gauthier    adelaide.gauthier@dupre.fr    
      3    Maurice     Boulanger   maurice.boulanger@allard.net  
      4    Louis       Caron       louis.caron@marty.org         
      5    Paulette    Besnard     paulette.besnard@rey.org      
     ---- ----------- ----------- ------------------------------ 
    
  10. Vérifiez l'affichage de ces nouvelles données dans l'application

Tests fonctionnels basés sur des données factices

Les tests fonctionnels dépendant de données ont précédemment été réalisés sur une version de démonstration de la base de données de développement. Ce principe est problématique puisqu'il nécessite un serveur de base de données MySQL contenant des données et une connaissance du jeu de données. Habituellement, des données factices sont générées à la volée pour chaque test sur un moteur SQLite qui ne nécessite pas d'infrastructure particulière.

Vous allez donc utiliser « Foundry » pour générer des données factices lors des tests. Il faut installer le module « Doctrine » de Codeception pour pouvoir tester le contenu dans la base de données.

Travail à réaliser
  1. Ajoutez au projet la dépendance de développement au module « codeception/module-doctrine »
    composer require --dev codeception/module-doctrine
  2. Activez le module « Doctrine » dans la configuration de la suite des tests « Controller » (fichier « tests/Controller.suite.yml »)
  3. Activez l'option « cleanup » pour que chaque test s'exécute dans une transaction, empêchant ainsi les effets de bords
  4. Ajoutez le fichier source de cet utilitaire (« Helper ») au projet en le plaçant dans le répertoire « tests/Support/Helper »
  5. Activez le « Helper » qui dépend du module « Symfony » en ajoutant les lignes suivantes à la liste des modules activés dans le fichier « tests/Controller.suite.yml » :
        - \App\Tests\Support\Helper\EntityManagerReset:
            depends: Symfony
    Information

    Ce « Helper » permet de réinitialiser l'EntityManager entre chaque test pour éviter les effets de bords.

  6. Générez les classes « Actor » de Codeception avec le nouveau module activé :
    php vendor/bin/codecept build
  7. Configurez l'accès à une base de données SQLite de test dans « .env.test » en prenant tel quel le modèle proposé dans « .env »
    Information

    Il est classique de configurer une base de données SQLite pour les tests directement dans le fichier « .env.test ».

  8. Supprimez le fichier « .env.test.local »
    rm .env.test.local
  9. Supprimez la référence à « .env.test.local » dans « codeception.yml »
  10. Modifiez le script Composer « test:codeception » pour qu'il initialise la base de données de test avant de lancer les tests :
    • Nettoyage du répertoire « _output » et du code généré par Codeception
      php vendor/bin/codecept clean
    • Destruction silencieuse forcée de la base de données
      bin/console doctrine:database:drop --force --quiet --env=test
    • Création silencieuse de la base de données
      bin/console doctrine:database:create --quiet --env=test
    • Création silencieuse du schéma de la base de données
      bin/console doctrine:schema:create --quiet --env=test
    • Exécution des tests Codeception
      php vendor/bin/codecept run
  11. Documentez ce script dans le fichier « composer.json »
  12. Documentez ce script dans le fichier « README.md »
  13. Lancez le script Composer « test:codeception » et constatez qu'il produit des erreurs
  14. Mettez à jour le test de la liste des contacts en le débutant par la création de 5 « Contact » avec « ContactFactory »
  15. Ajoutez un test de clic sur le premier contact de la liste :
    • À l'aide de « ContactFactory », créez un « Contact » « Joe Aaaaaaaaaaaaaaa »
    • Toujours à l'aide de « ContactFactory », créez 5 « Contact »
    • Cliquez sur le lien « Aaaaaaaaaaaaaaa, Joe »
    • Vérifiez que la réponse est un succès
    • Vérifiez que vous êtes sur la route « app_contact_show » avec les bonnes valeurs de paramètres
  16. Ajoutez un test qui contrôle que les contacts sont correctement triés :
    • Avec « ContactFactory », créez une séquence d'insertion de 5 « Contact » dont deux ont le même nom de famille
      Information

      Pour que le test soit pertinent, utilisez des contacts dont les noms et prénoms sont fixés et insérés dans un ordre différent de l'ordre alphabétique attendu.

    • Utilisez la méthode « grabMultiple() » du module « WebDriver » de Codeception pour récupérer la liste des contacts
    • Comparez l'ordre attendu et l'ordre constaté
  17. Vérifiez que le code passe tous les tests