- Accueil
- Programmation Web S5
- Objectifs de la séance
- Préambule
- Mise en place d'une application
Symfony
6.3 - Gestion des versions avec Git
GitHub Copilot
- Création du projet dans
PhpStorm
- Qualité de code et automatisation
- Conteneurisation des services de base de données
- Les annonces dans l'application
- Catégories d'annonces
- Considérations sur les performances
- Interface utilisateur
- Installation de
Webpack Encore
- Installation de
Sass
- Installation de
Bootstrap
- Utilisation de
Bootstrap
dans l'interface utilisateur - Personnalisation du thème de couleurs de
Bootstrap
- Ajout de couleurs de thème dans
Bootstrap
- Personnalisation d'éléments de mise en forme de
Bootstrap
- Optimisation de
Bootstrap
Bootstrap Icons
- Gestion du mode clair/sombre dans
Bootstrap
- Installation de
- Mise en place de tests
- Amélioration de l'interface et de l'expérience utilisateur
- Sécurité
- Intégration continue
- Commandes de console
- Réalisation d'un système de « likes »
- Introduction d'un flux de travail (« workflow ») pour la gestion des annonces
Objectifs de la séance ¶
- Prendre en main
Symfony
dans sa version 6.3 - Consolider les objectifs du TP de découverte de
Symfony 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
- Développer en respectant les bonnes pratiques de
Symfony
- Mettre en place des outils de qualité de code
- Automatiser l'utilisation des outils de qualité de code
- Conteneuriser certains services avec
Docker
Préambule ¶
L'objectif de ce TP est de consolider vos acquis en développement d'applications Symfony
(découverte de Symfony 5
puis API Platform
), mais également de vous faire découvrir de nouvelles possibilités. Le sujet vous donnera des consignes et des pointeurs vers de la documentation et des ressources, vous mettant ainsi dans une situation de réalisation professionnelle. L'accent sera une nouvelle fois mis sur les bonnes pratiques de Symfony
, la qualité de développement et l'automatisation.
Le fil conducteur sera un site de petites annonces, dont les fonctionnalités évolueront au fil de vos nouveaux apprentissages.
Mise en place d'une application Symfony
6.3
¶
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-for-sale
» 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 de votre projet et ne peut pas fonctionner normalement lorsque ces fichiers sont sur un partage NFS
. Afin d'améliorer les performances de votre 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 votre dépôt distant (en ligne de commande ou avec PhpStorm
)
git commitpuis
git pushfaute de quoi vous perdrez votre travail entre chaque séance !
Pensez également à supprimer votre répertoire de travail /working/votre_login/symfony-for-sale
pour éviter la saturation du disque local :
rm -Rf /working/votre_login/symfony-for-sale
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 votre dépôt local
cd /working/votre_login/symfony-for-sale
git pull
- Effacer votre dépôt local et repartir de zéro
cd /working/votre_login
rm -Rf /working/votre_login/symfony-for-sale
git clone https://iut-info.univ-reims.fr/gitlab/votre_login/symfony-for-sale.git
cd /working/votre_login/symfony-for-sale
- Réinitialiser votre dépôt local selon le dépôt distant
cd /working/votre_login/symfony-for-sale
git fetch
git reset --hard origin/main
Ensuite, dans le répertoire de votre projet, vous devez (ré)installer les composants nécessaires à son fonctionnement :
composer install
Vous devrez également reconfigurer votre accès base de données en redéfinissant le fichier « .env.local
»
Installation / mise à jour de l'exécutable « symfony
» et de Composer
¶
Travail à réaliser
- Vérifiez que l'outil «
symfony
» en ligne de commande (« Symfony CLI ») est installé et à jour en reprenant la procédure d'installation vu l'an passé - Contrôlez la compatibilité du système avec la commande :
symfony check:requirements --verbose
- Vérifiez que «
Composer
» est installé et à jour en reprenant la procédure d'installation vu l'an passé - Vérifiez que
Composer
fonctionne correctement :composer about
- Mettez à jour
Composer
:composer self-update
Création du 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
- 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) - Lancez la création d'un nouveau projet
Symfony
version «6.3.*
» :symfony --version 6.3 --webapp new symfony-for-sale
Vérification du bon fonctionnement de l'application ¶
Si vous avez réalisé toutes les étapes précédentes sans encombre, votre 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
- Placez-vous dans le répertoire de votre application
- Dans le terminal, lancez le serveur Web local avec la commande suivante :
symfony serve
Le serveur Web fonctionnera tant que vous n'aurez pas terminé l'exécution de l'outil ligne de commande «symfony
» avec «CTRL+C
». - Lancez votre navigateur web et saisissez l'URL suivante :
http://127.0.0.1:8000
- Vérifiez que le serveur Web local répond correctement
- 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 votre application Symfony
.
Dépôt local ¶
Vous allez configurer votre dépôt Git
local.
Travail à réaliser
- Assurez-vous d'être dans le répertoire du projet
symfony-for-sale
- Constatez que le dépôt
Git
local a été initialisé par l'outil «symfony
» en ligne de commande (« Symfony CLI »)git log
GitHub Copilot
¶
Une partie du code que vous produisez est prévisible, au moins en partie. C'est pourquoi GitHub
a développé un outil d'assistance à la saisie de code, GitHub Copilot
, qui s'appuie sur l'intelligence artificielle et l'apprentissage automatique pour vous aider à écrire du code. Cet outil est utilisé en entreprise pour augmenter la productivité des développeurs. Il nous semble donc intéressant de vous le présenter, tout en vous sensibilisant à son utilisation éclairée et raisonnée.
Information
Certaines informations sont nécessaires au bon déroulement de votre inscription au « GitHub Student Developer Pack ». Lisez l'intégralité des consignes fournies dans le sujet avant de vous lancer dans la création de votre compte GitHub
et de vous inscrire au « GitHub Student Developer Pack ».
Travail à réaliser
- Si vous n'en possédez pas déjà un, créez un compte sur
GitHub
, de préférence avec votre mail universitaire - Inscrivez-vous au « GitHub Student Developer Pack » : https://education.github.com/pack
- Si votre mail universitaire n'est pas connu de
GitHub
, vous devez le renseigner, car il est nécessaire pour être reconnu comme étudiant - Fournissez une photo de votre carte d'étudiant ou de votre certificat de scolarité Information
Vous devez impérativement fournir une photo de votre carte d'étudiant ou de votre certificat de scolarité. Vous pouvez utiliser votre smartphone pour obtenir un fichier image au format
JPEG
. Les captures d'écran du certificat de scolarité seront rejetées. - Constatez l'état de votre demande qui devrait être approuvée :
- Patientez quelques jours avant de profiter de votre accès à
GitHub Copilot
! - Après 3 ou 4 jours d'attente, vos avantages sont disponibles :
- Accédez à vos paramètres de compte concernant
GitHub Copilot
- Activez
GitHub Copilot
en cliquant sur le bouton « Start free trial » : - Vous devriez voir apparaître un message donnant accès à la version gratuite de
GitHub Copilot
: - Cliquez sur le bouton « Get access to GitHub Copilot »
- Choisissez ensuite vos préférences de
GitHub Copilot
:
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 votre 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
- Dans votre terminal et dans le répertoire du projet, lancez la commande
phpstorm . &
Remarque importanteLa création du projet
PhpStorm
induit la création du répertoire «.idea
» dans le répertoire de votre projetSymfony
. En temps normal, en particulier lors d'un développement collaboratif comme la SAÉ de S3, il est impensable d'inclure le répertoire «.idea
» au dépôtGit
. En effet, chaque modification de la configuration dePhpStorm
faite par l'un des développeurs va engendrer la modification de la configuration de tous les autres développeurs une fois que la modification se retrouvera dans la branche principale.Néanmoins, à cause de la configuration particulière au sein du département informatique qui vous oblige à travailler dans le répertoire local «
/working/votre_login
» sur des ordinateurs différents, et parce que vous êtes l'unique développeur de votre projet, il est légitime d'inclure le répertoire de configuration dePhpStorm
, «.idea
», afin que vous n'ayez pas à reconfigurer votre environnement lorsque vous clonerez votre dépôt en début de séance.
Qualité de code et automatisation ¶
Consignes de codage et de nommage ¶
Le code de l'écosystème Symfony
est intégralement en anglais. Tous les composants que vous allez utiliser possèdent donc des noms anglais. Afin de maintenir une bonne lisibilité de votre code, vous allez respecter les règles de nommage en langue anglaise pour les noms de classes, de propriétés, de méthodes, de variables, de fonctions, de fichiers, … Ceci vaudra également pour les commentaires ainsi que les messages de commit. Les instructions et informations notables consignées dans le fichier « README.md
» pourront être en français. L'interface utilisateur de l'application sera également en français.
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 de votre projet dans un fichier « REAMDE.md
» et le tenir à jour au fil du développement.
Travail à réaliser
- Créez le fichier «
README.md
» à l'aide dePhpStorm
(qui vous propose de l'ajouter à l'indexGit
) - Complétez les informations suivantes :
- un titre de niveau 1 contenant le titre explicite du projet
- 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)
- un titre de niveau 2 « Installation / Configuration » précisant les points essentiels permettant d'installer, de configurer et de lancer le projet
- Validez votre travail dans
Git
Style de code avec PHP CS Fixer
¶
Travail à réaliser
- Installez
PHP CS Fixer
sans oublier l'option «--dev
» - Configurez
PHP CS Fixer
dansPhpStorm
Mise en place de scripts Composer
¶
Les dépendances de votre 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
- Ajoutez un script «
start
» qui lance le serveur web de test («symfony serve
») sans restriction de durée d'exécution - Ajoutez un script «
test:cs
» qui lance la commande de vérification du code parPHP CS Fixer
- Ajoutez un script «
fix:cs
» qui lance la commande de correction du code parPHP CS Fixer
- Ajoutez un script «
test:twig
» qui lance la commande de la consoleSymfony
permettant la vérification des fichiersTwig
contenus dans le répertoire «templates
» - Consultez l'aide de la console
Symfony
pour l'espace de noms «lint
» :php bin/console lint
- Ajoutez un script «
test:yaml
» qui lance la commande de la consoleSymfony
permettant la vérification des fichiersYAML
contenus dans le répertoire «config
» - Documentez vos scripts dans le fichier «
composer.json
» - Documentez vos scripts dans le fichier «
README.md
»
Automatisation des contrôles de qualité de code avec GrumPHP
¶
Travail à réaliser
- Installez
GrumPHP
sans oublier l'option «--dev
» - Configurez
GrumPHP
:- désactivez le «
fixer
» intégré - ajoutez la tâche «
composer
»InformationCherchez l'option de «
composer update
» permettant de mettre à jour uniquement le fichier «composer.lock
», elle vous sera certainement utile. - ajoutez la tâche «
git_blacklist
» et interdisez les expressions «dump(
», «var_dump(
», «print_r(
», «die(
», «exit(
» et «exit;
» - lisez la spécification «
Commits Conventionnels
» - ajoutez la tâche «
git_commit_message
» avec les options suivantes :- le sujet du commit ne commence pas forcément par une majuscule
- les types de commit se limitent à
«
build
», «ci
», «chore
», «docs
», «feat
», «fix
», «perf
», «refactor
», «revert
», «style
» et «test
» - les portées des commits (« scopes ») sont libres
- ajoutez la tâche «
composer_script
» pour déclencher le scriptComposer
«test:yaml
» - ajoutez la tâche «
composer_script
» pour déclencher le scriptComposer
«test:twig
»InformationVous ne pouvez pas ajouter directement deux tâches
GrumPHP
portant le même nom. Vous devez donc ajouter une tâche «composer_script
» pour chaque scriptComposer
que vous souhaitez exécuter selon la méthode définie dans la documentation. - ajoutez la tâche «
phpcsfixer
»InformationN'oubliez pas l'option «
config
» de cette tâche.
Remarque importanteSelon la façon dont votre environnement
Linux
est configuré, et si vous utilisezGit
à traversPhpStorm
, il se peut que vous rencontriez l'erreur suivante lors des tâchesGrumPHP
:The executable for "composer" could not be found.
Ceci est lié aux variables d'environnement accessibles par
PhpStorm
, en particulier «$PATH
», selon que vous le lancez par le menu de votre gestionnaire de fenêtres ou en ligne de commande. Pour résoudre ce problème, référez-vous au point « Exécution deComposer
à traversPhpStorm
» du guide « Installation et configuration dePhpStorm
». - désactivez le «
Installation / configuration des greffons PhpStorm
¶
Vous allez maintenant installer les greffons nécessaires à la gestion de votre projet Symfony
.
Travail à réaliser
- Installez les greffons suivants :
- Activez le support de
Symfony
pour le projet - Configurez le greffon
GitHub Copilot
dont l'icône doit apparaître dans la barre d'état en bas de la fenêtre dePhpStorm
Conteneurisation des services de base de données ¶
Les projets Symfony
générés avec l'outil ligne de commande « symfony
» contiennent un fichier « docker-compose.yml
» et un fichier « docker-compose.override.yml
». Les images utilisées par défaut sont celles de PostgreSQL
dans sa variante alpine
et de MailCatcher
.
Nous allons dans un premier temps nous concentrer sur la base de données pour changer l'image PostgreSQL
utilisée et ajouter une image dérivée de Adminer
permettant la connexion automatique à l'interface.
Travail à réaliser
- Modifiez le fichier «
docker-compose.yml
» pour utiliser l'imagePostgreSQL
classique en remplacement de celle basée suralpine
- Modifiez le fichier «
docker-compose.override.yml
» pour :- exposer le port du service de base de données
- ajouter l'image «
michalhosna/adminer-docker
» en tant que service - configurer les variables d'environnement du service «
adminer
» pour que l'interface soit disponible sur le port «8080
» et que la connexion à la base de données soit automatiqueInformationNe touchez ni à configuration du conteneur
PostgreSQL
, ni au «DATABASE_URL
» par défaut du fichier «.env
». Modifiez uniquement les variables d'environnement du service «adminer
» pour les faire correspondre au reste de la configuration.
Les annonces dans l'application ¶
La base de l'application s'appuie sur les annonces d'objets à vendre.
Information
Une attention très limitée sera portée à l'aspect visuel des annonces. Vous mettrez pour l'instant l'accent sur la structuration HTML
des informations présentées, puis vous améliorerez la présentation de l'application dans une prochaine partie.
Création d'une entité « Advertisement
»
¶
Afin de respecter le codage en langue anglaise, l'entité correspondant à une annonce sera nommée « Advertisement
».
Travail à réaliser
- Utilisez la commande du «
MakerBundle
»Symfony
pour générer l'entité «Advertisement
» avec les propriétés suivantes :- «
title
» de typestring(100)
, non null - «
description
» de typetext
, non null - «
price
» de typeint
, non null - «
createdAt
» de typeDateTimeImmutable
, non null - «
updatedAt
» de typeDateTimeImmutable
- «
location
» de typestring(100)
, non null
- «
- Créez une migration
Automatisation des dates de création et de mise à jour ¶
Un certain nombre de tâches de gestion de données se retrouvent dans de nombreux projets. C'est le cas des champs de date de création ou de mise à jour. Aussi, « StofDoctrineExtensionsBundle
», une extension de Doctrine
, propose un ensemble de fonctionnalités qui peuvent être activées pour automatiser ces tâches ainsi que d'autres dans le même esprit. La mécanique repose sur l'utilisation d'attributs PHP
8 associés aux propriétés des entités.
Travail à réaliser
- Installez l'extension «
StofDoctrineExtensionsBundle
» - Activez l'extension «
Timestampable
» - Utilisez les attributs
PHP
8 pour automatiser les dates de création et de mise à jour :- La date de création doit être automatiquement renseignée lors de la création d'une annonce
- La date de mise à jour doit être automatiquement renseignée lors de la modification des propriétés «
title
», «description
», «price
» ou «location
» d'une annonce
Génération de données factices ¶
Afin de pouvoir tester votre application, vous allez proposer des données factices correspondant aux annonces. Pour cela, vous utiliserez le « DoctrineFixturesBundle
» ainsi que le paquet « Foundry
».
Travail à réaliser
- Installez le «
DoctrineFixturesBundle
» - Installez le paquet «
Foundry
» - Créez un modèle d'annonces avec «
Foundry
» - Créez une classe de données factices «
AdvertisementFixtures
» - Créez 500 annonces aléatoires
Création de la base de données ¶
La création de la base de données en mode développement est une opération classique qui doit être facilement accessible. Vous devez disposer d'un script Composer
.
Travail à réaliser
- Ajoutez un script
Composer
«db
» permettant de :- forcer la suppression de la base de données, si elle existe
- créer la base de données
- appliquer les migrations
- charger les données factices
- Donnez une description de votre script dans le fichier «
composer.json
» - Documentez votre script dans le fichier «
README.md
» - Utilisez le service «
Adminer
» pour vérifier que les données factices ont bien été insérées dans la base de données
Visualisation des annonces ¶
Les annonces étant désormais créées en base de données, il est temps de les afficher. Dans un premier temps, vous proposerez une liste des annonces. Dans un second temps, vous proposerez une page de détail pour chaque annonce.
Travail à réaliser
- Utilisez la commande du «
MakerBundle
»Symfony
pour générer un contrôleur «AdvertisementController
» - Proposez la liste des annonces triées par ordre inverse de création dans l'action «
index()
»- Ajoutez une méthode «
findAllOrderedByDate()
» dans le dépôt «AdvertisementRepository
» - Utilisez la précédente méthode pour obtenir la liste des annonces et la transmettre à la vue qui se chargera de construire une liste
HTML
- Ajoutez une méthode «
- Proposez le détail d'une annonce dans l'action «
show()
»- Ajoutez une validation du paramètre de la route
- Utilisez un convertisseur d'attribut de requête pour obtenir l'annonce à partir de son identifiant
- Transmettez l'annonce à la vue qui se chargera de construire une présentation
HTML
simple des données
- Ajoutez un lien vers la page de détail de chaque annonce dans la liste des annonces
Formulaire d'édition / création d'une annonce ¶
Le même formulaire doit permettre d'effectuer la saisie d'une nouvelle annonce ou l'édition d'une annonce existante.
Travail à réaliser
- Utilisez la commande du «
MakerBundle
»Symfony
pour générer une classe de formulaire «AdvertisementType
» pour l'entité «Advertisement
» - Supprimez les champs de saisie de date de création et de modification qui sont gérés automatiquement
- Précisez les types de champs de saisie restants
- Ajoutez des contraintes de validation sur l'entité «
Advertisement
» :- «
title
» est non vide et contient entre 10 et 100 caractères - «
description
» est non vide et contient entre 20 et 1000 caractères - «
price
» est positif ou nul («≥ 0
» mais pas «null
») - «
location
» est non vide et contient entre 2 et 100 caractères
- «
- A l'aide de l'option «
attr
» des champs de la classe de formulaire, précisez les attributsHTML
améliorant l'ergonomie de la saisie :- «
title
» contient entre 10 et 100 caractères - «
description
» contient entre 20 et 1000 caractères - «
price
» est positif ou nul - «
location
» contient entre 2 et 100 caractères
- «
Utilisation du formulaire d'édition / création d'une annonce ¶
Le formulaire de saisie d'une nouvelle annonce ou d'édition d'une annonce existante étant créé, il convient à présent de l'utiliser.
Travail à réaliser
- Créez un modèle «
advertisement/_form.html.twig
» qui affiche le formulaire de saisie d'une annonce et le bouton de soumission, selon les bonnes pratiques concernant les formulaires - Ajoutez une action «
new()
» dans le contrôleur «AdvertisementController
», qui utilise «advertisement/_form.html.twig
» pour afficher le formulaire de saisie d'une nouvelle annonce - Ajoutez une action «
edit()
» dans le contrôleur «AdvertisementController
», qui utilise «advertisement/_form.html.twig
» pour afficher le formulaire d'édition d'une annonce existante - Rendez les actions fonctionnelles afin qu'elles puissent créer une nouvelle annonce ou enregistrer les modifications apportées à une annonce existante
Catégories d'annonces ¶
Les annonces seront plus faciles à trouver si elles sont rangées par catégorie.
Information
Une attention très limitée sera portée à l'aspect visuel des annonces. Vous mettrez pour l'instant l'accent sur la structuration HTML
des informations présentées, puis vous améliorerez la présentation de l'application dans une prochaine partie.
Création de l'entité « Category
»
¶
Vous allez tout d'abord générer l'entité « Category
».
Travail à réaliser
- Utilisez la commande du «
MakerBundle
»Symfony
pour générer l'entité «Category
» avec les propriétés suivantes :- «
name
» de typestring(50)
, non null
- «
- Vérifiez le code généré
Relations entre les entités « Advertisement
» et « Category
»
¶
L'entité « Advertisement
» doit être liée à l'entité « Category
» afin de pouvoir associer une annonce à une catégorie. Une annonce appartient forcément à une catégorie et une catégorie peut contenir plusieurs annonces.
Travail à réaliser
- Utilisez la commande du «
MakerBundle
»Symfony
pour modifier l'entité «Advertisement
» :- ajoutez une relation «
category
» obligatoire vers l'entité «Category
» - ajoutez la relation inverse «
advertisements
» dans l'entité «Category
»
- ajoutez une relation «
- Créez une migration
Données factices ¶
Afin d'apporter un peu de lisibilité au jeu de données d'essai, vous allez construire la collection de catégories à partir d'un fichier contenant une liste réelle.
Travail à réaliser
- Récupérez le fichier «
category.txt
» et placez-le dans le répertoire «data
» du projet - Générez une classe de « fixtures » pour l'entité «
Category
» - Générez une «
Factory
» pour l'entité «Category
» - Importez les données du fichier dans la base de données en utilisant la «
Factory
» et la classe de « fixtures » - Modifiez la «
Factory
» de l'entité «Advertisement
» pour qu'elle associe chaque nouvelle annonce à une nouvelle catégorie - Vérifiez le bon chargement des données avec le service
Docker
Adminer
Données factices, introduction de « Story
»
¶
Les jeux de données d'essai peuvent devenir complexes à construire et sont alors difficilement réutilisables. Foundry
propose le concept de « Story
» qui permet de définir un ensemble de données cohérentes et réutilisables.
Travail à réaliser
- Lisez le chapitre de la documentation de
Foundry
consacré aux «Stories
» - Générez une «
Story
» pour l'entité «Category
» - Importez les données du fichier «
category.txt
» dans un tableauPHP
- Extrayez la première catégorie de votre import pour créer un «
State
» que vous nommerez «category_without_advertisement
» - Utilisez le reste du tableau de noms de catégories pour construire un «
Pool
» que vous nommerez «categories
» - Modifiez la classe de « fixtures » associée à l'entité «
Category
» afin qu'elle utilise la «Story
» pour générer toutes les catégories - Modifiez la classe de « fixtures » associée à l'entité «
Advertisement
» afin qu'elle utilise la «Story
» pour générer des annonces dont la catégorie sera tirée au hasard dans le «Pool
» «categories
» - Améliorez les performances de la génération du jeu d'essai en utilisant la méthode «
Factory::delayFlush()
» pour toutes les « fixtures »
Liste des annonces par catégorie ¶
Les utilisateurs doivent pouvoir visualiser les annonces par catégorie. Vous allez donc proposer la liste des catégories ainsi que la liste des annonces pour chaque catégorie.
Travail à réaliser
- Utilisez la commande du «
MakerBundle
»Symfony
pour générer un contrôleur «CategoryController
» - Utilisez la route par défaut du contrôleur pour afficher la liste des catégories triées par ordre alphabétique
- Définissez une route «
show
» pour afficher la liste des annonces d'une catégorieInformationPuisque vous avez déjà proposé une vue d'une liste d'annonces, il serait judicieux de mettre le code en commun dans un fragment de « template » qui sera nommé selon les bonnes pratiques. Ce dernier sera inclus ou intégré selon votre choix, et comprendra le titre «
h1
» qui pourra être personnalisé. - Ajoutez un lien sur chaque catégorie de la liste pour afficher les annonces de la catégorie
Formulaire de saisie d'une annonce ¶
L'annonce possède une relation vers la catégorie. Il convient donc de proposer un champ de saisie permettant de sélectionner la catégorie de l'annonce.
Travail à réaliser
- Lisez la documentation de
Symfony
sur les champs de formulaires associés aux entités - Ajoutez un champ de saisie de catégorie dans le formulaire de saisie d'une annonce
- Affichez le nouveau champ de saisie dans la vue
Affichage de la catégorie d'une annonce ¶
L'ergonomie de l'interface utilisateur sera améliorée si chaque annonce affiche la catégorie à laquelle elle est associée, aussi bien dans la vue détaillée de l'annonce que dans les listes d'annonces.
Travail à réaliser
- Ajoutez le nom de la catégorie dans la vue détaillée d'une annonce
- Ajoutez le nom de la catégorie dans la liste des annonces
- Ajoutez un lien sur la catégorie pour afficher les annonces de la catégorie
Considérations sur les performances ¶
L'ORM Doctrine
facilite la tâche du développeur en proposant une interface PHP
pour la gestion des données. Cependant, cette interface a un coût en termes de performance et il est nécessaire d'analyser les requêtes pour voir s'il est possible d'optimiser les performances de l'application. Dans le cas présent, la relation entre les annonces et les catégories implique d'effectuer, sur une collection d'annonces, une nouvelle requête en base de données pour récupérer la catégorie de chacune des annonces.
Catégorie de l'annonce dans la liste des annonces ¶
Vous allez analyser puis optimiser le requêtage des annonces au sein des listes.
Travail à réaliser
- Affichez la liste des annonces dans votre navigateur
- Observez les requêtes effectuées dans la partie
Doctrine
du «Profiler
» accessible par la barre de débogage (« Web Debug Toolbar ») - Expliquez pourquoi une requête est effectuée pour chaque catégorie
- Proposez une solution pour optimiser le requêtage au niveau du «
Repository
»InformationLe nom de la méthode du «
Repository
» doit refléter votre démarche d'optimisation. Vous devez donc le compléter avec un suffixe qui indique les entités supplémentaires sélectionnées. - Vérifiez que votre solution diminue le nombre de requêtes effectuées
Taille de la liste des annonces ¶
Du point de vue des performances, mais également de l'expérience utilisateur, les listes de grande taille doivent être paginées. C'est une problématique courante, dont la solution peut être trouvée dans un « bundle ». Concrètement, d'un point de vue base de données, il s'agit de limiter le nombre de résultats retournés par une requête. Cependant, il est nécessaire de connaître le nombre total de résultats pour pouvoir proposer une pagination. C'est pourquoi, il est nécessaire d'effectuer deux requêtes : une pour récupérer les résultats et une pour récupérer le nombre total de résultats.
Travail à réaliser
- Lisez les explications de la limitation de sélection de résultats dans la documentation « PHP MySQL Limit Data Selections » de
W3Schools
- Parcourez rapidement la documentation de «
KnpPaginatorBundle
» - Installez «
KnpPaginatorBundle
» dans votre projet - Utilisez «
KnpPaginatorBundle
» pour paginer la liste de toutes les annonces - Observez la probable absence de répercussions sur les requêtes effectuées (absence de «
LIMIT
» dans les requêtes)Information«
KnpPaginatorBundle
» permet de paginer de nombreuses formes de collections. Si vous appliquez la pagination à la liste des annonces sous forme de résultat de requête, vous paginez un tableau de toutes les annonces. «KnpPaginatorBundle
» doit avoir accès à la requête pour pouvoir la modifier. C'est pourquoi, il est nécessaire de modifier votre approche en paginant une requête et non une collection issue d'un résultat de requête. - Modifiez le code de la méthode pour qu'elle retourne la requête et non son résultat
- Modifiez le nom de la méthode «
findAllOrderedByDate…()
» du «Repository
» en «queryAllOrderedByDate…()
» pour refléter le changement d'approche - Vérifiez que la pagination fonctionne correctement et que les requêtes sont optimisées (présence de «
LIMIT
») - Procédez de la même manière pour la liste des annonces d'une catégorie
Catégorie dans les détails de l'annonce ¶
La récupération de l'annonce lors de son affichage détaillé peut bénéficier d'une requête optimisée. En effet, la relation entre l'annonce et la catégorie est connue lors de la récupération de l'annonce. Il est donc possible de récupérer la catégorie en même temps que l'annonce, en utilisant une jointure.
Travail à réaliser
- Lisez la documentation « Automatically Fetching Objects (EntityValueResolver) », en particulier le point sur l'utilisation d'une expression avec l'attribut
PHP
«MapEntity
» - Définissez une méthode dans le «
Repository
» pour répondre à la problématique - Associez la méthode du «
Repository
» à l'action «show()
» à l'aide de l'attributPHP
«MapEntity
» - Vérifiez les requêtes effectuées lors de l'affichage détaillé d'une annonce
- Associez la méthode du «
Repository
» à l'action «edit()
» à l'aide de l'attributPHP
«MapEntity
» - Vérifiez les requêtes effectuées lors de l'édition d'une annonce
Interface utilisateur ¶
Le début de votre projet est (volontairement) pauvre en mise en forme. Vous allez maintenant l'améliorer en y incorporant Bootstrap
. La nouveauté par rapport à l'an passé va résider dans une intégration locale de Bootstrap
, afin de ne pas dépendre d'un CDN. Ce sera également l'occasion de découvrir le bundle « Webpack Encore
» qui va faciliter l'intégration de Webpack
dans votre application. Cet outil va vous permettre de gérer les divers « assets » JavaScript
et CSS
de votre projet. Vous aurez également le loisir de découvrir Sass
qui va vous permettre de gérer les feuilles de style de manière plus efficace, structurée et flexible. Vous pourrez notamment personnaliser Bootstrap
en utilisant Sass
.
Installation de Webpack Encore
¶
Vous allez commencer par installer Webpack Encore
.
Travail à réaliser
- Installez le bundle «
Webpack Encore
» - Installez les modules
Node.js
nécessaires - Lancez la construction des « assets »
- Observez l'ensemble des fichiers créés dans le projet
- Complétez la documentation de votre projet
Installation de Sass
¶
Le langage de script Sass
doit être interprété par Webpack
afin de générer les feuilles de style CSS
de votre projet. npm
propose un module Node.js
qui permet d'interpréter Sass
: sass
.
Travail à réaliser
- Configurez
Sass
dans votre projet - Lancez la construction des « assets »
- Complétez la documentation de votre projet
Installation de Bootstrap
¶
L'avantage des CDN est de faciliter la mise en cache des bibliothèques JavaScript
et CSS
par les navigateurs. Cependant, il est préférable de ne pas dépendre d'un CDN pour des raisons de performance et de sécurité. L'intérêt majeur de ne pas utiliser de CDN pour Bootstrap
réside dans les possibilités de personnalisation de la copie locale. Vous allez donc installer « Bootstrap
» localement.
Travail à réaliser
- Installez
Bootstrap
InformationjQuery
n'est pas nécessaire ! - Importez les fichiers
JavaScript
etCSS
deBootstrap
dans votre projet
Utilisation de Bootstrap
dans l'interface utilisateur
¶
Boostrap
propose des composants HTML
et des classes CSS
qui facilitent la mise en forme des contenus. Vous allez donc les utiliser pour améliorer l'interface utilisateur de votre projet.
Travail à réaliser
- Structurez le « template » de base de votre projet en utilisant les classes de «
Bootstrap
» :- Bloquez la largeur maximale du contenu principal
- Ajoutez une barre de navigation en haut de la page
- Donnez du style aux listes d'annonces
- Transformez les étiquettes de catégorie en badges
- Appliquez le thème
Bootstrap
aux formulaires - Utilisez le « template »
Bootstrap
pour la pagination
Personnalisation du thème de couleurs de Bootstrap
¶
Les couleurs et l'aspect de Bootstrap
sont trop classiques et trop reconnaissables. Il est donc nécessaire de personnaliser le thème afin de ne pas avoir un site qui ressemble à tous les autres.
Travail à réaliser
- Choisissez un thème
Boostrap
qui vous convient sur https://huemint.com/bootstrap-plus/ - Appliquez le thème à votre projet Information
Attention à ne pas utiliser directement le code fourni par https://huemint.com/bootstrap-plus/, vous devez respecter les consignes de la documentation de
Bootstrap
pour personnaliser le thème.Mettez en commentaires les couleurs «
accent 1
», «accent 2
» et «accent 3
» qui ne font par partie du thème, mais que nous utiliserons plus tard.
Ajout de couleurs de thème dans Bootstrap
¶
Bootstrap
est conçu autour d'un thème de couleurs symboliques (« primary
», « secondary
», « success
», …) qui sont accessibles à travers de multiples sélecteurs CSS
. Par exemple, la couleur « primary
» se retrouve dans les sélecteurs « .btn-primary
», « .bg-primary
», « .text-primary
», … Il est possible d'ajouter des nouvelles couleurs symboliques afin d'augmenter la palette de couleurs disponibles. Il ne faut toutefois pas en abuser, car chaque couleur symbolique ajoutée augmente la taille et la complexité des feuilles de style générées.
Travail à réaliser
- Lisez la documentation de l'ajout de couleurs de thème
Bootstrap
- Ajoutez une nouvelle couleur symbolique «
accent1
» dans le thème deBootstrap
InformationUtilisez une des trois couleurs supplémentaires générées par https://huemint.com/bootstrap-plus/.
- Utilisez un sélecteur associé à la nouvelle couleur symbolique pour modifier la couleur du texte de l'élément «
navbar-brand
» de la barre de navigation
Personnalisation d'éléments de mise en forme de Bootstrap
¶
Vous utilisez les classes CSS
de Bootstrap
pour mettre en forme votre application. Vous pouvez également les utiliser pour les modifier.
Travail à réaliser
- Ajoutez un sélecteur
CSS
pour modifier les éléments de listes afin d'alterner la couleur de fond des lignesInformationVous pouvez utiliser la variante subtile («
bg-*-subtle
») d'une des couleurs du thème. - Changez la police des badges pour qu'elle soit plus grosse («
1rem
») et pas en caractères gras
Optimisation de Bootstrap
¶
La copie locale de Bootstrap
est trop volumineuse. Vous allez donc optimiser le chargement des fichiers JavaScript
et Sass
en n'incluant que les éléments réellement utilisés.
Travail à réaliser
- Lisez la partie optimisation de la documentation de la personnalisation de
Bootstrap
- Optimisez les imports de fichiers
JavaScript
en n'incluant que les éléments réellement utilisés - Optimisez les imports de fichiers
Sass
en n'incluant que les éléments réellement utilisésInformationIl n'est pas toujours simple de trouver les fichiers nécessaires, mais il est primordial de respecter l'ordre d'inclusion défini dans le fichier «
scss/bootstrap.scss
» deBootstrap
. Partez du contenu de ce fichier et commentez les imports inutiles.
Bootstrap Icons
¶
Les bibliothèques d'icônes sont largement utilisées dans les applications Web. Vous allez intégrer celle de Bootstrap
.
Travail à réaliser
- Lisez la documentation des
Bootstrap Icons
- Installez les
Bootstrap Icons
dans votre projet avecnpm
- Ajoutez une icône
Bootstrap
à la barre de navigation, au niveau de l'élément «navbar-brand
» - Cette icône étant purement décorative, masquez-la aux outils d'accessibilité
Gestion du mode clair/sombre dans Bootstrap
¶
Bootstrap
propose des modes de couleurs depuis la version 5.3. L'utilisation classique est de proposer un mode clair et un mode sombre. La fonctionnalité peut être étendue à tout thème de couleur.
Travail à réaliser
- Lisez la documentation de
Bootstrap
sur les modes de couleurs - Activez le mode sombre dans votre projet et vérifiez que l'affichage est correct
- Récupérez le code
HTML
de la fonctionnalité de basculement du mode clair/sombre du site deBootstrap
(en haut à droite de la page) - Étudiez le code JavaScript de basculement du mode clair/sombre proposé dans la documentation de
Bootstrap
- Insérez le précédent code
Javascript
dans votre projet, dans un fichier «assets/js/color-mode.js
» qui sera importé dans «assets/app.js
» - Modifiez le code
HTML
de la fonctionnalité de basculement du mode clair/sombre du site deBootstrap
pour qu'il fonctionne avec votre projet :- Façon dont les icônes sont incluses Information
Dans son propre site,
Bootstrap
utilise la méthode des sprites pour insérer les icônes. Si vous observez les attributs «href
» des balises «use
», vous pouvez constater que ce sont des liens relatifs au documentHTML
et non des liens désignant le fichierSVG
contenant toutes les icônes. En étudiant le codeHTML
du site deBootstrap
, vous pouvez constater qu'une partie du fichierSVG
est inclus dans le début du documentHTML
et est masqué. Afin de vous épargner l'automatisation de ce processus, vous pouvez faire référence au fichierSVG
complet. Pour cela, vous devez modifier les attributs «href
» des balises «use
» en remplaçant le chemin relatif par un assetTwig
ciblant le fichier «SVG
». Ce dernier n'étant pas disponible dans la sous-arborescence de «public
», vous devez utiliser la méthode «copyFiles()
» deEncore
. - Taille des icônes Information
Les icônes n'ont pas de taille définie dans la structure que vous venez de construire. Aussi, elles vont être affichées en grande taille. Explorez la feuille de style de
Bootstrap
pour trouver le sélecteur qu'ils utilisent pour définir la taille des icônes de la liste déroulante. - Couleur des icônes Information
Inspectez une nouvelle fois la feuille de style de
Bootstrap
pour trouver le sélecteur et la propriété qu'ils utilisent pour définir la couleur des icônes. - Affichage de l'icône du mode actif dans la liste Information
Une nouvelle fois, la réponse se trouve dans l'inspection du site de
Bootstrap
.
- Façon dont les icônes sont incluses
Mise en place de tests ¶
Un projet informatique qui inclut des tests présente de nombreux avantages, directement liés à la détection précoce des problèmes :
- amélioration de la qualité du code
- non régression lors des évolutions
- possibilité de développement itératif par intégration continue et déploiement continu
- facilitation de la collaboration entre développeurs en contenant les effets de bord des modifications de chacun
- fiabilisation des mises à jour des composants (serveur, langage de programmation, « frameworks », « toolkits », …)
Les projets Web demandent un effort particulier sur les tests fonctionnels ou d'acceptation. Symfony s'appuie sur PHPUnit
pour proposer des tests unitaires, d'intégration et fonctionnels. Les tests fonctionnels (« Application Tests ») sont particulièrement adaptés aux projets Web, car ils permettent de tester l'application dans son ensemble, en simulant un navigateur qui va émettre une requête HTTP
vers l'application pour provoquer une réponse qui sera récupérée, analysée et testée.
Sur le même principe, Codeception
propose un module Symfony
. Nous utiliserons Codeception pour la lisibilité apportée par la syntaxe de ses tests.
Installation/configuration de Codeception
¶
Vous allez dans un premier temps installer Codeception
et les modules nécessaires.
Travail à réaliser
- Installez
Codeception
, sans oublier que c'est une dépendance de développementInformationAjoutez l'option «
--no-interaction
» pour éviter d'avoir à répondre à des questions et surtout pour empêcher la génération des suites de tests par défaut. - Installez les modules «
Asserts
», «Symfony
» et «Doctrine2
» deCodeception
- Lisez le guide de démarrage rapide de
Codeception
- Consultez les options d'amorçage (« bootstrap ») de
Codeception
- Amorcez
Codeception
dans votre projet en précisant le namespace «App\Tests
» et en ne générant pas les suites par défautInformationEn ligne de commande, si vous souhaitez passer un paramètre contenant le caractère «
\
», vous devez le doubler puisque le shell utilise ce même caractère «\
» pour échapper les caractères. Ainsi, le namespace «App\Tests
» devient «App\\Tests
» dans les paramètres de la ligne de commande. - Chargez les paramètres de configuration dans la configuration générale de
Codeception
depuis les fichiers «.env
» et «.env.test
» - Configurez l'environnement de test de
Symfony
pour qu'il utilise une base de données «SQLite
» (trouvez le «DATABASE_URL
» adéquat dans le fichier «.env
») - Excluez les sources générées par
Codeception
(«tests/Support/_generated
») de l'analyse de code dePHP CS Fixer
- Créez un script
Composer
nommé «test:codeception
» qui :- nettoie les fichiers générés par
Codeception
- détruit la base de données dans l'environnement de test
- crée la base de données dans l'environnement de test
- crée le schéma de la base de données dans l'environnement de test
- exécute les tests de
Codeception
- nettoie les fichiers générés par
- Créez un script
Composer
nommé «test
» qui exécute, dans un ordre logique, tous les scripts de tests que vous avez créés jusqu'à présent - Décrivez ces scripts dans «
composer.json
» et dans la documentation de votre projet
Suite de tests de « Application
»
¶
Votre première suite de tests regroupera tous les tests fonctionnels de l'application. Vous utiliserez ensuite des espaces de noms pour organiser les diverses catégories de tests.
Travail à réaliser
- Générez une suite de tests «
Application
» - Activez et configurez les modules «
Asserts
», «Symfony
» et «Doctrine2
» pour la suite de tests «Application
»
« Cest » pour la liste des annonces ¶
Vos premières réalisations ont concerné la liste des annonces. Ce sera donc la première fonctionnalité que vous testerez
Travail à réaliser
- Générez un « Cest » «
Advertisement\List
» qui regroupera les tests fonctionnels de la liste des annonces - Effectuez les tests suivants, et corrigez votre code si nécessaire :
- La liste des annonces est correctement affichée si elle est vide
- Une liste de 15 annonces s'affiche correctement, pagination comprise
« Cest » pour le CRUD des annonces ¶
Les annonces peuvent être créées, visualisées, modifiées et effacées (« CRUD »). Ces actions doivent naturellement être présentes et testées.
Travail à réaliser
- Générez un « Cest » «
Advertisement\CRUD
» qui regroupera les tests fonctionnels concernant les annonces - Effectuez les tests suivants, et corrigez ou complétez votre code si nécessaire :
- La création d'une annonce à partir du formulaire de création fonctionne correctement et implique donc la présence des données en base de données
- L'affichage d'une annonce comporte bien ses caractéristiques
- La modification d'une annonce à partir du formulaire d'édition fonctionne correctement et implique donc la mise à jour des données en base de données
- Ajoutez la fonctionnalité de suppression d'une annonce :
- Ajoutez une route et une action pour supprimer une annonce
- Créez un « template » partiel pour le bouton de suppression d'une annonce Information
Le « template » partiel sera inclus dans chaque vue où un bouton de suppression d'une annonce est nécessaire. Il est constitué d'un formulaire
HTML
contenant uniquement un bouton d'envoi. Afin d'éviter les suppressions intempestives, une confirmation réalisée enJavaScript
sera associée à l'événement de soumission du formulaire. - Protégez la suppression de l'annonce des attaques « CSRF » en ajoutant un jeton « CSRF » au formulaire de suppression
- Contrôlez la présence du jeton « CSRF » dans l'action associée à la suppression
- Dans la vue des détails d'une annonce, ajoutez un bouton d'édition ainsi que le formulaire de suppression
- Écrivez le test de la fonctionnalité de suppression d'une annonce
« Smoke testing », test de fumée ¶
L'objectif des tests est de détecter précocement les problèmes de l'application. Le premier niveau de vérification consiste donc à vérifier que les URL de l'application répondent correctement. Chaque URL sera alors contrôlée a minima, en attendant que des tests détaillés soient écrits pour vérifier tous les aspects de la fonctionnalité implémentée. C'est ce que l'on appelle le « smoke testing ». Ces tests devront être exécutés avant tous les autres tests, ce qui va demander une utilisation particulière de Codeception
faisant appel aux groupes.
Travail à réaliser
- Générez un « Cest » «
Availability
» qui regroupera les tests de fumée - Créez un test «
pageIsAvailable
» qui vérifie que l'URL passée en paramètre est disponibleInformationRéfléchissez aux « fixtures » dans ce contexte.
- Créez un «
dataProvider
» qui fournit les URL à tester - Associez le «
dataProvider
» au test «pageIsAvailable
» - Exécutez le test «
pageIsAvailable
» pour toutes les URL connues de l'application - Lisez la documentation de
Codeception
sur les groupes - Créez un groupe «
available
» qui regroupe tous les tests de fumée - Lisez l'auto-documentation de la commande «
run
» de «vendor/bin/codecept
» - Modifiez le script
Composer
«test:codeception
» pour qu'il exécute, dans l'ordre :- les tests de fumée (ceux du groupe «
available
») - les tests de l'application (tous sauf ceux du groupe «
available
»)
- les tests de fumée (ceux du groupe «
Amélioration de l'interface et de l'expérience utilisateur ¶
L'accueil de l'application affiche toujours la page de test de Symfony
dans l'environnement de développement et une erreur HTTP
404 en production. Il faut donc effectuer une redirection vers la liste des annonces. Il manque également une fonctionnalité de rechercher des annonces.
Redirection depuis l'accueil de l'application ¶
Vous allez simplement rediriger le visiteur vers la liste des annonces depuis l'accueil de l'application.
Travail à réaliser
- Générez un nouveau contrôleur «
HomeController
» - Dans l'action «
index
» de ce contrôleur, redirigez le visiteur vers la liste des annonces - Supprimez la vue inutile associée à l'action «
index
» - Testez la fonctionnalité dans «
Application\HomeCest
»
Recherche des annonces par titre ou description ¶
Il est temps d'ajouter une barre de recherche.
Travail à réaliser
- Ajoutez un formulaire comportant champ de recherche dans la barre de navigation
- Définissez la route correspondant à la liste des annonces comme action associée à la recherche
- Utilisez l'icône «
search
» deBootstrap
pour le bouton de recherche (la méthode « Icon Font » est la plus appropriée) - Modifiez la methode de «
AdvertisementRepository
» afin qu'elle :- admette un paramètre correspondant à la chaîne de recherche
- effectue une recherche insensible à la casse sur le titre et la description des annonces Information
Inutile de complexifier la requête si la chaîne de recherche est vide.
- retourne la requête des annonces correspondant à la recherche
- Récupérez la valeur de la chaîne de recherche dans l'action affichant la liste des annonces
- Donnez cette valeur à la méthode de recherche de «
AdvertisementRepository
» - Reportez la valeur de la chaîne de recherche dans le champ de recherche du formulaire
- Ajustez le titre de la page («
title
» et «h1
») en fonction de la présence ou non d'une chaîne de recherche - Testez la fonctionnalité dans «
Application\Advertisement\SearchCest
»
Création d'une extension Twig
pour l'affichage des dates
¶
Ceci est une question complémentaire, qui n'est pas obligatoire. Les détails sont donnés au sein de l'ensemble des questions complémentaires.
Sécurité ¶
Jusqu'ici, l'application donne accès à toutes les fonctionnalités à toute personne y ayant accès. Naturellement, il faut restreindre l'accès à certaines fonctionnalités. Vous allez donc mettre en place un système d'authentification, des restrictions d'accès et du cloisonnement de données.
Authentification ¶
Utilisateur ¶
La première étape de sécurisation de l'application réside dans la création des utilisateurs.
Travail à réaliser
- Générez une entité utilisateur «
User
» avec les propriétés suivantes :- «
email
» de typestring(180)
, unique, not null - «
password
» - «
firstname
» de typestring(100)
, not null - «
lastname
» de typestring(150)
, not null
- «
- Créez, à l'aide d'une «
Story
», des utilisateurs factices dont le mot de passe sera «test
» :- «
admin@example.com
», avec un rôle administrateur - «
admin2@example.com
», avec un rôle administrateur - «
user@example.com
», avec un rôle utilisateur - «
user2@example.com
», avec un rôle utilisateur - 10 utilisateurs aléatoires
InformationAfin d'identifier facilement les utilisateurs non aléatoires dans votre application, définissez leurs nom et prénom dans les données factices.
Pensez à hacher les mots de passe des utilisateurs factices.
- «
- Documentez les informations des utilisateurs factices
Connexion ¶
Les utilisateurs doivent pouvoir se connecter pour s'identifier et se déconnecter.
Travail à réaliser
- Créez un formulaire de connexion en français et vérifiez manuellement son fonctionnement (succès/échec)
- Ajoutez un bouton de connexion et un bouton de déconnexion dans la barre de navigation
- Dans un nouveau « Cest » «
Application\Security\AuthenticationCest
», testez :- qu'un utilisateur peut se connecter
- qu'un utilisateur connecté peut se déconnecter
- qu'un test de connexion avec des identifiants erronés échoue
- Complétez les tests de fumée avec les URL de connexion et de déconnexion
Autorisations ¶
Les utilisateurs maintenant identifiés peuvent être autorisés ou non à accéder à certaines fonctionnalités.
Travail à réaliser
- Affichez ou cachez les boutons de connexion/déconnexion de la barre de navigation en fonction de l'état de connexion de l'utilisateur
- Limitez l'accès à la page de création d'une annonce aux utilisateurs connectés
- Masquez le lien de création d'une annonce dans la barre de navigation aux utilisateurs non connectés
- Modifiez le test de création d'une annonce pour qu'il soit exécuté par un utilisateur connecté
- Ajoutez un test qui vérifie que la création d'une annonce par un utilisateur non connecté échoue
Cloisonnement de données ¶
Les annonces, actuellement anonymes, vont être associées à un utilisateur et les autorisations vont être ajustées en conséquence.
Association d'une annonce à un utilisateur ¶
Pour commencer, chaque annonce doit être associée à un utilisateur.
Travail à réaliser
- Ajoutez une propriété «
owner
» à l'entité «Advertisement
» permettant d'associer un seul utilisateur à chaque annonce - Affectez automatiquement l'utilisateur connecté à la création d'une annonce en utilisant «
Blameable
» de «StofDoctrineExtensionsBundle
» - Modifiez les « fixtures » pour que les 500 annonces soient créées par les 10 utilisateurs aléatoires de la «
Story
» - Ajoutez 20 annonces pour l'utilisateur «
user@example.com
» de la «Story
» - Affichez le prénom de l'utilisateur propriétaire dans les détails de l'annonce sous forme d'un badge
Bootstrap
de couleur «accent1
» - Testez qu'une annonce nouvellement créée est bien associée à l'utilisateur connecté Information
L'utilisation de «
Blameable
» en conjonction avecCodeception
demande la persistance du service «BlameListener
» pour fonctionner correctement. Cet ajustement vous est fourni sous forme d'un «Helper
»Codeception
que vous devez activer dans la suite «Application
». Vous en profiterez pour ajouter le «Helper
» déjà fourni au semestre 3, permettant de réinitialiser l'«EntityManager
» avant chaque test pour éviter les échecs en cascade. Notez que ces deux «Helper
» dépendent du module «Symfony
» deCodeception
.
Annonces d'un utilisateur ¶
Lors de la recherche dans les annonces, il peut être intéressant de consulter les annonces d'un utilisateur, un cas particulier étant les annonces de l'utilisateur connecté. Il faut donc ajouter cette fonctionnalité.
Travail à réaliser
- Créez une action permettant d'afficher les annonces d'un utilisateur dans un contrôleur dédié
- Affichez les annonces de l'utilisateur paginées et triées par date de création décroissante, en réutilisant le fragment de « template » réalisé plus tôt
- Lorsque la liste d'annonces est celle de l'utilisateur connecté, le titre de la page doit être «
Mes annonces
» - Une entrée de menu «
Mes annonces
» doit permettre d'accéder aux annonces de l'utilisateur connecté - Transformez le prénom de l'utilisateur dans les détails d'une annonce en un lien permettant de consulter ses annonces
- Complétez les tests de fumée
Création d'un « Voter
»
¶
Symfony
propose la notion de « Voter
» pour gérer les autorisations. Ce concept permet de centraliser la logique des autorisations plutôt que d'effectuer des tests à divers endroits du code. Vous allez créer un « Voter
» vérifiant les autorisations de modification et de suppression d'une annonce basées sur le contrôle du propriétaire de l'annonce.
Travail à réaliser
- Utilisez le «
MakerBundle
» pour générer un «Voter
» - Adaptez le «
Voter
» pour vérifier les autorisations de modification et de suppression d'une annonce par son propriétaire uniquement - Utilisez le «
Voter
» pour cloisonner les actions de modification et de suppression d'une annonce - Utilisez le «
Voter
» pour afficher les boutons de modification et de suppression d'une annonce uniquement au propriétaire de ladite annonce - Ajustez les tests de modification et de suppression d'une annonce
- Ajoutez des tests permettant de contrôler qu'un utilisateur ne peut ni modifier ni supprimer une annonce qui ne lui appartient pas
Inscription d'un nouvel utilisateur dans l'application ¶
Les visiteurs anonymes doivent pouvoir s'inscrire pour profiter des fonctionnalités de l'application. Il leur sera alors demandé de confirmer leur adresse mail avant de pouvoir utiliser les fonctionnalités nécessitant d'être connecté.
Formulaire d'inscription ¶
Le « MakerBundle
» permet de générer un formulaire d'inscription avec différentes options selon vos réponses aux questions posées. Vous allez donc générer un formulaire d'inscription et l'adapter à vos besoins.
Travail à réaliser
- Utilisez le «
MakerBundle
» pour générer un formulaire d'inscription avec les spécificités suivantes :- Envoyer un mail de confirmation d'inscription
- Inclure l'identifiant de l'utilisateur dans le lien de confirmation contenu dans le mail
- Authentifier l'utilisateur après son inscription
InformationLisez bien le compte-rendu de la commande pour savoir comment finaliser le formulaire d'inscription.
- Supprimez le champ généré « You should agree to our terms. » du formulaire d'inscription
- Traduisez en français le formulaire d'inscription, le modèle de mail et les messages des contraintes
- Ajoutez un lien vers l'inscription dans la page de connexion
- Ajoutez les nom et prénom de l'utilisateur au formulaire d'inscription Information
Respectez les bonnes pratiques en déléguant la responsabilité de présentation des «
labels
» à la vue. - Ajoutez des contraintes de validation (taille maximale, type, non vide…) aux propriétés «
email
», «firstname
» et «lastname
» de l'entité «User
» - Améliorez l'ergonomie de la saisie des champs du formulaire d'inscription en imposant en
HTML
les mêmes contraintes que celles définies dans l'entité «User
»InformationLe mot de passe peut recevoir l'attribut
HTML
«autocomplete="new-password"
» pour indiquer au navigateur qu'il s'agit d'un nouveau mot de passe et qu'il ne doit pas proposer la saisie semi-automatique. - Complétez les tests de fumée
Configuration des services d'envoi et de consultation de mails ¶
Le formulaire d'inscription que vous avez généré doit conduire à l'envoi d'un mail lorsque l'utilisateur valide sa saisie. Ceci va nécessiter la configuration de « Messenger
» et de « Mailer
» ainsi que la prise en main de MailCatcher
pour consulter les mails envoyés durant les essais en phase de développement.
Travail à réaliser
- Exposez les ports de
MailCatcher
dans le «docker-compose.override.yaml
» de l'application - Déportez la définition du mail et du nom de l'émetteur dans un fichier «
.env
» et utilisez les variables d'environnement dans la configuration de «Mailer
»InformationPensez à supprimer le «
from()
» dans le contrôleur d'inscription. - Configurez le transport de mail par
SMTP
sur la boucle locale pour vous connecter àMailCatcher
- Modifiez le routage des mails pour qu'il soit synchrone, uniquement en environnement de développement
- Vérifiez que l'inscription d'un nouvel utilisateur conduit bien à la réception d'un mail dans
MailCatcher
- Utilisez le lien contenu dans le mail de confirmation et vérifiez que l'utilisateur est bien validé (champ «
is_verified
» de la table)
Validation de l'adresse mail du nouvel l'utilisateur ¶
Le mail envoyé à l'utilisateur contient un lien permettant de valider son inscription. Il se peut que l'utilisateur ne reçoive pas le mail ou qu'il le supprime par mégarde. Il faut donc prévoir une fonctionnalité permettant de renvoyer le mail de confirmation.
Tant que l'utilisateur n'a pas validé son adresse mail, il ne doit pas pouvoir utiliser les fonctionnalités nécessitant d'être connecté. Juste après l'inscription, l'utilisateur est automatiquement connecté à l'application. Il est donc identifié et sera systématiquement redirigé vers la page de demande de confirmation de son adresse mail. Ceci permet de le forcer à valider son adresse mail. Dans un cas réel, il serait préférable de laisser l'utilisateur accéder aux parties publiques de l'application tant qu'il n'a pas validé son inscription.
Travail à réaliser
- Créez une action «
validateUserMail()
» dans le contrôleur «Registration
» permettant d'afficher à l'utilisateur connecté la demande de la confirmation de son adresse mail - Définissez le code de ce nouveau contrôleur afin qu'il :
- redirige l'utilisateur connecté vers la page d'accueil si son adresse mail est déjà validée
- construise un formulaire de demande de l'envoi du mail de confirmation de l'adresse mail de l'utilisateur
- redirige simplement l'utilisateur vers la page d'accueil si le formulaire est soumis (vous modifierez ce comportement plus tard)
- effectue le rendu de la vue dans les autres cas
- Créez un «
EventListener
» «ForceValidateMailListener
» qui intercepte toutes les requêtes faites sur votre application et qui redirige vers la page de demande de confirmation de l'adresse mail si l'utilisateur n'a pas validé son adresse mailInformationVérifiez que la requête interceptée est bien la requête principale de l'application et non une sous-requête.
Ne redirigez pas les routes utiles à l'utilisateur dont l'adresse mail n'est pas validée, comme la page de confirmation de l'adresse mail ou la page de déconnexion.
Vous aurez besoin de générer des URL à partir de noms de routes.
- Complétez les tests de fumée
Événement d'inscription d'un nouvel l'utilisateur ¶
La gestion de l'envoi d'un mail de confirmation d'inscription et de validation de l'adresse mail d'un utilisateur sont des fonctionnalités qui peuvent être réutilisées dans d'autres contextes de l'application. Il est donc intéressant de les découpler du contrôleur de gestion des inscriptions. En effet, l'envoi d'un mail de confirmation d'inscription n'est qu'une conséquence souhaitée de l'inscription d'un nouvel utilisateur. Un nouvel utilisateur pourrait être inscrit dans d'autres circonstances et d'autres actions pourraient être déclenchées à cette occasion. Il est donc intéressant de créer un événement « UserRegistered
» qui sera déclenché à l'inscription d'un nouvel utilisateur. Un « EventListener
» personnalisé pourra alors intercepter les événements « UserRegistered
» et envoyer un mail de demande de validation de l'adresse mail de l'utilisateur. Si l'utilisateur demande une nouvelle fois l'envoi du mail de confirmation, un événement « UserConfirmationEmailNotReceived
» sera déclenché. Il sera alors également intercepté par le « EventListener
» qui enverra un nouveau mail de confirmation d'inscription.
Travail à réaliser
- Consultez le support de cours de Floran Brutel et Nicolas Hart sur les événements et les écouteurs
- Créez la classe d'événement «
UserRegistered
» - Créez la classe d'événement «
UserConfirmationEmailNotReceived
» - Créez un «
EventListener
» «EmailVerifierListener
» qui intercepte les événements «UserRegistered
» et «UserConfirmationEmailNotReceived
» pour envoyer un mail de demande de validation de l'adresse mail à l'utilisateurInformationLe code d'envoi du mail sera recopié à l'identique depuis de contrôleur d'inscription.
- Déclenchez un événement «
UserConfirmationEmailNotReceived
» lors de l'appui sur le bouton de demande de renvoi du mail de confirmation - Déclenchez un événement «
UserRegistered
» à la création d'un nouvel utilisateur lors de l'inscription (en remplacement de l'envoi du mail)
Gestion des messages « flash » ¶
Les diverses actions de l'application doivent pouvoir informer l'utilisateur du résultat de l'opération. Il est donc nécessaire de mettre en place un système de messages « flash ». Certains messages sont déjà présents dans le code du contrôleur d'inscription, mais ils ne sont que partiellement fonctionnels. Vous allez donc les compléter et les afficher à l'utilisateur.
Travail à réaliser
- Modifiez le code du contrôleur d'inscription pour qu'il utilise uniquement les catégories de messages « flash » «
success
» et «error
» - Inspirez-vous du code de la vue «
register.html.twig
» pour afficher les messages « flash » «success
» et «error
» dans «base.html.twig
», avec des styles appropriés - Supprimez le code de gestion des messages flash de la vue «
register.html.twig
» - Ajoutez un message « flash » «
success
» lors de la demande d'inscription et de renvoi du mail de confirmation
Sécurisation du mot de passe de l'utilisateur ¶
Le mot de passe choisi par l'utilisateur lors de son inscription n'est pas confirmé par une double saisie. Ceci est une mauvaise pratique que vous devez corriger. De plus, la complexité du mot de passe choisi par l'utilisateur n'est pas évaluée. Vous allez donc ajouter une contrainte de complexité du mot de passe dans le formulaire d'inscription.
Travail à réaliser
- Modifiez le formulaire d'inscription pour qu'il demande la confirmation du mot de passe avec un champ «
RepeatedType
»InformationRespectez les bonnes pratiques en déléguant la responsabilité de présentation des «
labels
» à la vue. - Installez le bundle «
RollerworksPasswordStrength Validator
» - Ajoutez dans le formulaire d'inscription une contrainte de complexité du mot de passe afin qu'il contienne :
- au moins 10 caractères
- au moins une lettre minuscule et une lettre majuscule
- au moins un chiffre
- au moins un caractère spécial
Tests d'inscription ¶
La vérification de l'adresse mail de l'utilisateur et le choix de son mot de passe lors de l'inscription sont des étapes importantes de la sécurisation de votre application. Il est donc nécessaire de tester ces procédures.
Travail à réaliser
- Désactivez «
Mailer
» durant les tests pour éviter de générer des mails («MAILER_DSN=null://null
» dans «.env.test
») - Utilisez les ancres et références de
YAML
pour effectuer la même configuration pour «Mailer
» dans les environnements de développement et de testInformationVous pouvez vous inspirer du fichier «
config/packages/zenstruck_foundry.yaml
» pour la syntaxe. - Créez un «
Cest
» «Registration\RegisterCest
» - Testez les points clés de l'inscription :
- Saisie des données dans le formulaire d'inscription, réception du mail de confirmation et validation de l'adresse mail Information
Pour tester si un mail est envoyé, vous devez désactiver le suivi des redirections comme indiqué dans la documentation.
Vous devez utiliser le lien de vérification de l'adresse mail contenu dans le mail de confirmation. Pour cela, il faut extraire le contenu du mail. Vous pourrez ensuite extraire le lien de vérification de l'adresse mail à l'aide d'une expression régulière correspondant à la balise
HTML
du lien et capturant le contenu de l'attribut «href
». - Refus des données dans le formulaire d'inscription en cas confirmation de mot de passe erronée
- Refus des données dans le formulaire d'inscription en cas de mot de passe incompatible avec les contraintes de complexité
- Redirection systématique sur la page de confirmation de l'adresse mail si l'utilisateur n'a pas validé son adresse mail
- Saisie des données dans le formulaire d'inscription, réception du mail de confirmation et validation de l'adresse mail
Intégration continue ¶
L'intégration continue demande l'automatisation des tests pour détecter au plus tôt les erreurs afin d'éviter les régressions. Vous avez déjà mis en place des outils de qualité de code automatisés sur le poste de travail du développeur avec PHP CS Fixer
et GrumPHP
. Vous disposez également d'une batterie de tests fonctionnels. Il est temps de les automatiser dans le processus d'intégration continue.
Vous allez installer et configurer GitLab Runner
sur une machine virtuelle Ubuntu
dans la ferme OpenNebula
du département informatique. Le « runner » sera ensuite associé à votre dépôt GitLab
pour que les tests soient exécutés automatiquement à chaque « push
».
Configuration du « runner » dans une machine virtuelle ¶
Vous allez tout d'abord déployer une machine virtuelle Ubuntu
dans la ferme OpenNebula
du département informatique. La machine virtuelle Ubuntu
sera ensuite configurée pour pouvoir exécuter les tests de l'application. Elle doit donc disposer de PHP
, de Composer
et de Node.js
. Vous allez ensuite installer et configurer un « GitLab Runner
» pour exécuter les tests à chaque « push
».
Travail à réaliser
- Consultez le support de cours de Floran Brutel et Nicolas Hart sur l'intégration continue
- Suivez le guide de déploiement d'une machine virtuelle
Ubuntu
surOpenNebula
en utilisant le « template » «Ubuntu Minimal 22.04
» - Connectez-vous en
ssh
à la machine virtuelle et vérifiez qu'elle fonctionne correctement - Vérifiez que vous avez bien suivi les consignes en affichant la version du système d'exploitation :
lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy
- Effectuez les actions suivantes permettant de contourner de possibles désagréments ayant été constatés :
- Ajoutez «
localhost.localdomain
» dans «/etc/hosts
» en passant la commande :sed -i "s:^127.0.0.1 localhost$:127.0.0.1 localhost.localdomain localhost:" /etc/hosts
- Mettez à jour les dépôts :
apt update
- Ajoutez un éditeur de texte, «
vim
» ou «nano
» (Ubuntu Minimal
ne contient pas d'éditeur de texte) :apt install nano
- Limitez l'attente de la configuration réseau à 5 secondes en éditant le service «
systemd-networkd-wait-online.service
» avec la commande :systemctl edit --full systemd-networkd-wait-online.service
puis en ajoutant l'option «--timeout=5
» à la fin de la ligne commençant par «ExecStart=
»InformationMettez bien un espace entre la fin de la commande et l'option que vous ajoutez.
- Mettez à jour le système :
apt upgrade
InformationLors de la mise à jour du système, vous serez invité à confirmer la mise à jour du fichier «
/etc/ssh/sshd_config
». Conservez le fichier installé.Lors des installations à vernir, vous serez invité à redémarrer les services. Il n'est pas utile de le faire, vous redémarrez la machine virtuelle à la fin de la configuration.
- Ajoutez «
- Ajoutez le dépôt des versions supportées de
PHP
«ppa:ondrej/php
» - Installez «
php8.1-cli
» avec les extensions «sqlite3
», «curl
», «intl
», «mbstring
», «xml
» et «zip
» - Ajoutez le dépôt officiel de
Node.js
en version 20 - Installez «
nodejs
» - Ajoutez le dépôt officiel de
Gitlab Runner
- Installez «
gitlab-runner
» - Installez
Composer
dans «/usr/local/bin
» - Créez un « runner »
Linux
pour votre dépôtGitLab
avec les « tags » «php8.1
», «composer
», «npm
» et «node.js
» - Enregistrez le « runner » avec la commande proposée et fournissez interactivement les informations nécessaires :
- le jeton d'enregistrement de votre dépôt
GitLab
(déjà renseigné via les options de la commande) - l'URL du serveur
GitLab
(déjà pré-renseigné via les options de la commande) - le nom du « runner » : «
symfony-for-sale
» - l'« executor » du « runner » : «
shell
»
- le jeton d'enregistrement de votre dépôt
- Désactivez les «
shared runners
» de votre dépôtGitLab
- Redémarrez la machine virtuelle et vérifiez que le « runner » est bien actif dans votre dépôt
GitLab
Intégration continue dans le projet ¶
Vous allez pouvoir définir les tâches d'intégration continue pour votre projet. Afin de limiter le temps d'exécution et les ressources OpenNebula
consommées, vous définirez une seule tâche d'intégration continue qui installera les composants nécessaires au projet et exécutera les tests.
Travail à réaliser
- Créez le fichier «
.gitlab-ci.yml
» à la racine du projet - Définissez une tâche «
test
» qui :- nécessite les « tags » «
php8.1
», «composer
», «npm
» et «node.js
» - installe les dépendances du projet Information
Utilisez la commande «
clean-install
» denpm
. - construit les « assets »
- exécute les tests
- conserve les artefacts des échecs des tests de
Codeception
InformationVous pouvez peaufiner la définition des artéfacts de
Codeception
en excluant le fichier «.gitignore
» contenu dans le répertoire concerné.
- nécessite les « tags » «
- Poussez le fichier «
.gitlab-ci.yml
» dans votre dépôtGitLab
- Vérifiez que le « pipepline » d'intégration continue est bien exécuté et se termine avec succès
Commandes de console ¶
Symfony
propose de nombreuses fonctionnalités à travers le script « bin/console
». Ces commandes sont créées à partir du composant « Console
» et peuvent être enrichies par des commandes personnalisées. Vous allez créer une commande personnalisée permettant de supprimer les utilisateurs dont l'adresse mail n'a pas été vérifiée depuis un nombre de jours donné.
Date d'inscription d'un utilisateur ¶
La date d'inscription des utilisateurs n'est pas mémorisée. Vous allez donc ajouter cette information dans l'entité « User
» en faisant une nouvelle fois usage de « Timestampable
».
Travail à réaliser
- Ajoutez une propriété obligatoire «
registeredAt
» à l'entité «User
» - Rendez la nouvelle propriété «
Timestampable
» à la création - Ajustez la «
Factory
» pour que tout utilisateur créé aléatoirement ait une date d'inscription comprise entre 1 jour et 2 mois avant la date du jour - Modifiez la «
Story
» pour ajouter un «Pool
» «unverified users
» de 4 utilisateurs non vérifiés
Ajout de fonctionnalités au « Repository
» des utilisateurs
¶
Maintenant que vous disposez de la date d'inscription des utilisateurs, vous devez pouvoir sélectionner et supprimer des utilisateurs non vérifiés en fonction du nombre de jours écoulés depuis leur inscription. Ces fonctionnalités sont à la charge du « Repository
» des utilisateurs et vous allez les écrire.
Travail à réaliser
- Ajoutez une méthode «
findUnverifiedUsersSince()
» au «Repository
» des utilisateurs permettant de sélectionner les utilisateurs non vérifiés depuis un nombre de jours donné facultatif - Ajoutez une méthode «
deleteUnverifiedUsersSince()
» au «Repository
» des utilisateurs permettant de supprimer les utilisateurs non vérifiés depuis un nombre de jours donné facultatifInformationLes méthodes étant très similaires, factorisez tout le code qui peut l'être.
Création de la commande de suppression des utilisateurs non vérifiés ¶
Vous allez créer une commande personnalisée permettant de supprimer les utilisateurs dont l'adresse mail n'a pas été vérifiée depuis un nombre de jours donné.
Par défaut, la commande affiche tous les utilisateurs non vérifiés. Vous pouvez filtrer les utilisateurs à considérer en précisant le nombre de jours depuis lequel l'utilisateur n'a pas vérifié son adresse mail avec l'option « --days=DAYS
». Une option « --delete
» permet de supprimer les utilisateurs listés, après confirmation. Une dernière option « --force
» permet de supprimer les utilisateurs listés sans confirmation.
Travail à réaliser
- Utilisez le «
MakerBundle
» pour générer une commande personnalisée «app:purge-registration
» - Ajoutez les options «
--days=DAYS
», «--delete
» et «--force
» à la commande - Vérifiez que l'option «
--days=DAYS
» est bien un nombre entier positif, si elle est présente - Réalisez l'affichage sous forme de tableau des utilisateurs non vérifiés (nom, prénom, adresse mail et nombre de jours écoulés) depuis le nombre de jours donné facultatif
- Supprimez, après confirmation, les utilisateurs non vérifiés depuis le nombre de jours donné facultatif si l'option «
--delete
» est présente - Outrepassez la confirmation de suppression si l'option «
--force
» est présente - Affichez le nombre d'utilisateurs supprimés en cas de suppression effective
Tests de la commande de suppression des utilisateurs non vérifiés ¶
Votre commande de suppression des utilisateurs non vérifiés effectue des opérations critiques puisqu'elle supprime des utilisateurs. Il est primordial de la tester.
Travail à réaliser
- Générez un « Cest » «
Command\PurgeRegistration
» - Lisez la documentation de «
runSymfonyConsoleCommand
» - Testez la commande de suppression des utilisateurs non vérifiés avec ou sans les options «
--days=DAYS
», «--delete
» et «--force
» :- Affichage des utilisateurs non vérifiés
- Suppression des utilisateurs non vérifiés (et non suppression des autres utilisateurs)
Réalisation d'un système de « likes » ¶
L'une des forces d'un développeur est d'être capable de transposer une fonctionnalité déjà implémentée dans un nouveau projet. La plus grande force d'un bon développeur est d'être capable d'acquérir de nouvelles compétences en s'appuyant sur celles qu'il possède. Vous allez donc réaliser une fonctionnalité de « likes » en vous appuyant sur les connaissances acquises lors des semestres précédents et dans ce projet. Vous serez peu guidé lorsque la tâche fait appel à des connaissances déjà acquises. Vous serez néanmoins guidé lorsque la tâche fait appel à des connaissances en cours d'acquisition.
Formulation de la demande client ¶
La demande du client est formulée comme une liste de règles de fonctionnement :
- les utilisateurs peuvent « liker » les annonces
- un utilisateur ne peut « liker » une même annonce qu'une seule fois et peut supprimer ce « like » s'il le désire
- les visiteurs voient le nombre de « likes » d'une annonce dans la liste des annonces et sur le détail de l'annonce
- les utilisateurs voient s'ils ont « liké » ou non une annonce particulière en plus du nombre de « likes » dans la liste des annonces et sur le détail de l'annonce
- un utilisateur ne peut pas « liker » ses propres annonces
Le client propose un visuel pour afficher les « likes » :
Adapter le modèle de données ¶
La demande du client doit être traduite en termes de modèle de données. Vous allez donc l'adapter pour prendre en compte les « likes ».
Travail à réaliser
- Réfléchissez à la manière dont vous allez modéliser les « likes »
- Transcrivez ces modifications dans le modèle de données
- Effectuez une migration de la base de données
- Créez de nouvelles « fixtures » pour les « likes » afin que l'utilisateur factice « user@example.com » ainsi que tous les utilisateurs aléatoires aient « liké » entre 50 et 100 annonces aléatoires Information
Les annonces « likées » par un utilisateur doivent être différentes des annonces qu'il a créées.
Construire un composant Twig
¶
Le nombre de « likes » d'une annonce doit être affiché dans la liste des annonces et sur le détail de l'annonce. Vous allez donc construire un composant Twig
permettant d'afficher ces informations en reprenant le visuel proposé par le client.
Travail à réaliser
- Lisez l'introduction des «
Twig Components
» - Installez les «
Twig Components
» avecComposer
- Utilisez la commande du «
MakerBundle
»Symfony
pour générer un composantTwig
«AdvertisementLikes
» - Ajoutez un «
Advertisement
» comme «Props
» du composantInformationDans l'exemple de la documentation, les «
Props
» sont de simples «string
». Vous pouvez naturellement utiliser un «Advertisement
» comme «Props
» de votre composant. - Ajoutez une méthode «
getLikesCount()
» au composant pour récupérer le nombre de « likes » de l'annonceInformationIl suffit de compter le nombre d'utilisateurs ayant « liké » l'annonce, les «
Collection
» de Doctrine implémentent l'interface «Countable
» - Structurez la vue du composant pour qu'elle affiche le nombre de « likes » de l'annonce précédé d'un cœur Information
Dans la vue, vous devez utiliser «
this
» pour accéder au composant et donc à ses propriétés et méthodes. - Ajoutez le composant dans la liste des annonces et sur le détail de l'annonce
- Ajoutez une méthode «
isLikedByUser()
» au composant pour savoir si l'utilisateur a « liké » l'annonce - Modifiez la vue du composant pour qu'elle affiche le nombre de « likes » de l'annonce précédé d'un cœur plein si l'utilisateur a « liké » l'annonce ou d'un cœur si l'utilisateur n'a pas « liké » l'annonce Information
Pensez à étudier le cas où aucun utilisateur n'est connecté.
Vue des annonces préférées de l'utilisateur ¶
L'objectif des « likes » est de mettre en avant une annonce en matérialisant l'intérêt qu'elle suscite, mais ils permettent aussi à un utilisateur de marquer les annonces qu'il préfère. Il est donc logique de lui proposer une vue de ses annonces préférées.
Travail à réaliser
- Créez une nouvelle action «
liked
» dans le contrôleur «AdvertisementController
» - Créez une méthode «
queryLikedByUser…()
» dans le «Repository
» des annonces permettant de récupérer les annonces « likées » par un utilisateur donnéInformationCette méthode doit rester compatible avec une utilisation optimisée de la pagination.
- Construisez la vue associée à l'action
- Ajoutez une entrée « Annonces préférées » dans le menu de l'application
Rendre le composant « Live
»
¶
Symfony UX
propose des « Live Components
» qui peuvent s'actualiser selon les interactions de l'utilisateur. Il est ainsi possible de bénéficier de la souplesse et la puissance d'AJAX
dans l'interface utilisateur sans écrire de JavaScript
.
L'intérêt pour l'application sera de transformer le composant « AdvertisementLikes
» en composant « Live
» afin de pouvoir « liker » une annonce et mettre à jour le nombre de « likes » sans recharger la page.
Travail à réaliser
- Installez les «
Live Components
» avecComposer
InformationComme indiqué dans la documentation, n'oubliez pas d'installer le «
StimulusBundle
» ni les paquetsnpm
nécessaires. - Lisez le chapitre « Making your Component "Live" » de la documentation
- Transformez le composant «
AdvertisementLikes
» en composant «Live
» - Ajoutez une méthode «
toggleLike()
» au composant pour ajouter ou supprimer le « like » de l'annonce pour l'utilisateur connectéInformationPensez à étudier le cas où aucun utilisateur n'est connecté.
- Ajoutez un attribut
PHP
à la méthode «toggleLike()
» pour en faire une «LiveAction
» - Modifiez la vue du composant pour qu'elle appelle la méthode «
toggleLike()
» lors d'un clic sur le cœur contenu dans le composantInformationLe cœur peut être transformé en bouton Bootstrap, uniquement si un utilisateur est connecté, pour faciliter la gestion du clic.
Gestion des droits d'accès ¶
L'un des principes de fonctionnement souhaités demande à ce que l'utilisateur ne puisse pas « liker » ses propres annonces. L'application doit impérativement veiller au respect de cette règle. Vous allez donc compléter le « Voter
» « AdvertisementVoter
» pour gérer ce cas.
Travail à réaliser
- Ajoutez un attribut «
LIKE
» au «AdvertisementVoter
» pour gérer le droit de «liker
» les annonces dont l'utilisateur n'est PAS l'auteur - Utiliser le «
Voter
» pour limiter l'utilisation de la méthode «toggleLike()
» du composant «AdvertisementLikes
» - Utilisez le «
Voter
» pour désactiver le clic sur le cœur dans le composant «AdvertisementLikes
»
Optimisations ¶
Comme précédemment, l'accès à de nouvelles ressources liées à une entité entraine de nouvelles requêtes qu'il convient d'étudier pour déterminer s'il est nécessaire de les optimiser.
Travail à réaliser
- Trouvez ce qui engendre de nouvelles requêtes
- Optimisez les requêtes Information
Lorsque vous faites évoluer le comportement de certaines méthodes, il convient souvent de les renommer pour refléter ces changements. Pensez à la refactorisation de code accessible par le raccourci «
SHIFT+F6
» dePHPStorm
pour gagner en efficacité et en fiabilité. - Déterminez s'il existe dans l'application des requêtes équivalentes qui peuvent être optimisées
- Optimisez les éventuelles requêtes le nécessitant
Introduction d'un flux de travail (« workflow ») pour la gestion des annonces ¶
Les annonces de l'application sont actuellement gérées de manière très classique. Dès qu'une annonce existe, elle est visible par tous les utilisateurs. Le propriétaire d'une annonce peut la modifier ou la supprimer. Vous allez introduire un flux de travail pour la gestion des annonces afin de permettre aux utilisateurs de créer des annonces sans les publier immédiatement, d'archiver des annonces et de les marquer comme terminées. La mise en place d'un état pour les annonces, ainsi que les transitions possibles entre ces états, est une démarche classique dans une application. Ainsi, Symfony
propose un composant « Workflow
» qui permet de gérer ces états et transitions.
Description du flux de travail ¶
La description complète de la mécanique du flux de travail est fournie par le client :
- une annonce nouvellement crée est dans un état « brouillon » : «
draft
» - le propriétaire de l'annonce « brouillon » peut la publier, elle passe alors dans l'état « publiée » : «
published
» - le propriétaire de l'annonce « publiée » peut la marquer comme terminée, elle passe alors définitivement dans l'état « terminée » : «
closed
» - le propriétaire de l'annonce « publiée » peut l'archiver, elle passe alors dans l'état « archivée » : «
archived
» - le propriétaire de l'annonce « brouillon » peut la supprimer, elle est alors supprimée de la base de données
- le propriétaire de l'annonce « archivée » peut la republier, elle passe alors dans l'état « publiée » : «
published
»
L'ensemble des transitions possibles peut être représenté par le diagramme suivant :
Travail à réaliser
- Parcourez la documentation de «
Workflow
» - Installez le composant «
Workflow
» avecComposer
- Configurez le composant «
Workflow
» pour gérer les états et transitions décrits ci-dessus - Modifiez l'entité «
Advertisement
» pour qu'elle mémorise un état - Définissez des constantes pour les états («
STATE_*
») et transitions («TRANSITION_*
») dans l'entité «Advertisement
» - Utilisez les nouvelles constantes dans la configuration
YAML
du composant «Workflow
»
Utilisation du flux de travail ¶
Le flux de travail défini va engendrer des modifications dans l'application. Vous allez donc les réaliser.
Travail à réaliser
- Adaptez les « fixtures » pour que les annonces créées aléatoirement soient dans l'état « publiée »
- Modifiez les annonces associées à l'utilisateur factice « user@example.com » pour qu'elles soient aléatoirement dans tous les états possibles
- Modifiez les requêtes du «
Repository
» des annonces pour qu'elles ne retournent que les annonces dans l'état « publiée » - Modifiez le «
Voter
» «AdvertisementVoter
» pour qu'il ne permette pas de consulter des annonces non publiées, sauf leur auteur et à condition qu'elles ne soient pas terminées - Ajoutez la consultation des annonces dans l'état « brouillon » pour l'utilisateur connecté
- Ajoutez au «
Voter
» «AdvertisementVoter
» la capacité de contrôler qu'une annonce peut être « publiée », « terminée » ou « archivée », uniquement par son auteurInformationLe «
Workflow
» permet de contrôler les transitions possibles. Utilisez cette capacité plutôt que de contrôler vous-même l'état nécessaire à la transition.Pour accéder au service «
Workflow
», vous devez l'injecter dans le «Voter
» en utilisant l'attribut «Target
». - Modifiez le processus de suppression d'une annonce pour contrôler que l'annonce peut bien être supprimée (elle doit être dans l'état « brouillon »)
- Sur le modèle de la suppression, ajoutez la possibilité de :
- publier (ou republier) une annonce
- archiver une annonce
- terminer une annonce
Information - Ajoutez des tests