Dossier de projet - Chrysostome Lanoire
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Dossier de projet Titre de concepteur et développeur d’applications par Chrysostome LANOIRE Abstract In this project, I worked with the technology Symfony to create a com- mercial website focused on hand-made jewelry named Biju - les bijoux de Juliette after the name of my client. Titre RNCP de niveau 6 Concepteur et développeur d’applications Avril 2021
Remerciements La réalisation de ce projet a été possible grâce au concours de plusieurs personnes à qui je voudrais témoigner toute ma gratitude. Je voudrais tout d’abord adresser toute ma reconnaissance à toute l’équipe de l’INSTIC, pour leur travail et leur encadrement. Je tiens à remercier en particulier Faouzi Tchenar, mon professeur principal, pour les bases qu’il m’a transmises tout au long de ma formation. Je souhaite aussi remercier l’équipe médicale qui m’a suivi pendant toute la durée de ce projet, sans laquelle je n’en serait certainement pas arrivé à bout. Je désire également remercier toutes les personnes qui m’ont aidé par le biais d’Internet, et spécialement Eddy Richard pour sa disponibilité, ses conseils et sa bienveillance. Je tiens à remercier spécialement Juliette pour son accompagnement au quoti- dien, qui fut essentiel au maintient de ma motivation pendant toute la durée du projet. J’en profite pour remercier tous ceux qui m’ont soutenu, rassuré et motivé aux moments où j’avais le plus de mal à avancer : mes parents en particulier, mais mes amis, malgré le confinement. Un grand merci enfin à tous mes relecteurs, déjà cités plus haut pour la plupart. 2
Table des matières 1 Travail préliminaire 8 1.1 Expression du besoin et formulation du cahier des charges . . . . . . 8 1.1.1 Besoin du client . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Côté utilisateur . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Côté administrateur . . . . . . . . . . . . . . . . . . . . . . . 9 Autres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.1.2 Mise en place du cahier des charges . . . . . . . . . . . . . . . 9 1.2 Environnement humain et technique . . . . . . . . . . . . . . . . . . 10 1.2.1 Environnement humain . . . . . . . . . . . . . . . . . . . . . 10 1.2.2 Planification et gestion du temps . . . . . . . . . . . . . . . . 10 1.2.3 Environnement technique . . . . . . . . . . . . . . . . . . . . 11 Plateformes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Choix de l’IDE . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.3 Spécifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.3.1 Spécifications fonctionnelles . . . . . . . . . . . . . . . . . . . 12 État des lieux . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Wireframe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.3.2 Spécifications techniques . . . . . . . . . . . . . . . . . . . . . 16 La programmation orientée objet . . . . . . . . . . . . . . . . 16 L’architecture MVC . . . . . . . . . . . . . . . . . . . . . . . 17 Symfony . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Gestion des dépendances . . . . . . . . . . . . . . . . . . . . . 18 Twig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.3.3 Sécurité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2 Réalisation du projet 20 2.1 Premiers pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.1.1 Créations préliminaires . . . . . . . . . . . . . . . . . . . . . . 20 La base de données . . . . . . . . . . . . . . . . . . . . . . . . 20 Le projet GitLab . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.1.2 Création du projet Symfony . . . . . . . . . . . . . . . . . . . 21 2.1.3 Installation des premiers composants . . . . . . . . . . . . . . 22 2.1.4 Thème Bootstrap et grandes lignes du front . . . . . . . . . . 22 Le thème ”Bootstrap Agency” . . . . . . . . . . . . . . . . . . 22 La navbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3
2.2 Le CRUD (Create, Read, Update and Delete) des bijoux . . . . . . . 24 2.2.1 L’ORM de Doctrine . . . . . . . . . . . . . . . . . . . . . . . 24 2.2.2 Création de l’entité Bijou . . . . . . . . . . . . . . . . . . . . 24 Création . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Persistence en base de données . . . . . . . . . . . . . . . . . 24 2.2.3 Génération du CRUD avec Doctrine . . . . . . . . . . . . . . 25 La data fixture pour obtenir des données de travail . . . . . . 26 Accéder aux bijoux . . . . . . . . . . . . . . . . . . . . . . . . 26 Slugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.2.4 Ajout des images par relation . . . . . . . . . . . . . . . . . . 27 Création de l’entité Image . . . . . . . . . . . . . . . . . . . . 27 Création du service d’upload d’image . . . . . . . . . . . . . . 28 2.2.5 Ajout d’une fonctionnalité : supprimer les images . . . . . . . 31 2.2.6 Refonte des vues générées . . . . . . . . . . . . . . . . . . . . 32 Mise en forme avec Bootstrap des vues edit et new . . . . . . 32 Refonte totale de la vue show . . . . . . . . . . . . . . . . . . 33 Refonte totale de la vue index . . . . . . . . . . . . . . . . . . 34 2.3 Gestion des utilisateurs . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.3.1 Création de l’entité User . . . . . . . . . . . . . . . . . . . . . 36 2.3.2 Génération du formulaire de login avec Symfony . . . . . . . . 36 Redirections . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.3.3 Gestion des inscriptions . . . . . . . . . . . . . . . . . . . . . 37 Mise en place du formulaire d’inscription . . . . . . . . . . . . 37 Mailer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.3.4 Mise en place des règles de permissions . . . . . . . . . . . . . 41 Accès aux pages . . . . . . . . . . . . . . . . . . . . . . . . . 41 Éléments contextuels . . . . . . . . . . . . . . . . . . . . . . . 41 2.3.5 Le login-throttling . . . . . . . . . . . . . . . . . . . . . . . . 42 2.3.6 L’option se souvenir de moi et le mot de passe oublié . . . . . 42 2.4 Formulaires de contact . . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.4.1 Création de l’entité Contact . . . . . . . . . . . . . . . . . . . 43 2.4.2 Validation du formulaire avec contraintes . . . . . . . . . . . . 43 2.4.3 Captcha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.4.4 Envoi du mail . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.5 Panier et commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 2.5.1 Gestion du panier . . . . . . . . . . . . . . . . . . . . . . . . 45 Ajouter des bijoux au panier . . . . . . . . . . . . . . . . . . . 45 Supprimer des bijoux du panier, vider le panier . . . . . . . . 47 2.5.2 Gestion des commandes . . . . . . . . . . . . . . . . . . . . . 47 Saisie des informations . . . . . . . . . . . . . . . . . . . . . . 48 Validation des informations . . . . . . . . . . . . . . . . . . . 48 Paiement (Stripe) . . . . . . . . . . . . . . . . . . . . . . . . . 48 Confirmation . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 2.5.3 Gestion des commandes : côté administrateur . . . . . . . . . 50 2.6 Mise en production . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 2.7 Pour la suite... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 2.8 Jeu d’essai du comportement lié à une fonctionnalité . . . . . . . . . 52 2.9 Veille sur les questions de sécurité . . . . . . . . . . . . . . . . . . . . 56 4
Compétences couvertes par ce projet Voici la liste des compétences que j’ai mises en oeuvre pendant de mon projet. • Concevoir et développer des composants d’interface utilisateur en intégrant les recommandations de sécurité → Maquetter une application → Développer une interface utilisateur de type desktop → Développer des composants d’accès aux données → Développer la partie front-end d’une interface utilisateur web → Développer la partie back-end d’une interface utilisateur web • Concevoir et développer la persistance des données en intégrant les recomman- dations de sécurité → Concevoir une base de données → Mettre en place une base de données → Développer des composants dans le langage d’une base de données • Concevoir et développer une application multicouche répartie en intégrant les recommandations de sécurité → Collaborer à la gestion d’un projet informatique et à l’organisation de l’environnement de développement → Concevoir une application → Développer des composants métier → Construire une application organisée en couches → Développer une application mobile → Préparer et exécuter les plans de tests d’une application → Préparer et exécuter le déploiement d’une application → Maquetter une application. 6
Introduction The project I am presenting in this report is called Biju, and is available at the address biju.blue. In spite of having worked alone, this is a real project, for a real client : I worked for a young woman who creates jewelry in her free time, and who is called Juliette, thus giving the name of the project : Biju, les bijoux de Juliette. I have worked with a technology that I have never studied at school : the PHP framework Symfony. This has considerably increased the difficulty of the project, since even though I have started learning Symfony by myself in November, I still had to learn many things to be able to complete it. The main goals of this website is to allow her to show her work, by uploading her creations, and to allow users to buy them. I tried to fetch inspiration from the giants in the domain of online shopping, such as Amazon, for things like the design of the basket, or the ”command tunnel” (the steps to complete in order to place an order). I fully intend to keep maintaining this website for my client in the future. That’s why all along this project, I have paid particular attention to the details : documen- ting my code, factorizing it whenever possible by creating services and interfaces, never inserting inline CSS (using classes instead), and all the other good practices I know. 7
Chapitre 1 Travail préliminaire 1.1 Expression du besoin et formulation du cahier des charges 1.1.1 Besoin du client Le client de ce projet est une personne qui fabrique des bijoux dans son temps libre. L’objectif de ce projet est de lui fournir un site web sur lequel elle pourra montrer son travail et éventuellement vendre ses bijoux. Voici un peu plus de détails sur son besoin. Par souci de clarté, je désignerai dans la suite le client ”d’artisan”, pour ne pas le confondre avec ses propres clients, les utilisateurs web. Côté utilisateur Acceuil Un utilisateur web doit tout d’abord être accueilli, puis introduit au tra- vail de l’artisan. Il doit donc se le voir présenter, avec une photographie, et une sélection de son travail, c’est à dire quelques bijoux. Par ailleurs, l’artisan souhaite que l’utilisateur ait le moyen de le contacter dès la première page. Index Il faudra ensuite que l’utilisateur puisse consulter l’ensemble des bijoux, avec leur nom et leur prix. Pages individuelles Par l’intermédiaire de cette (ou ces) page(s), on devra pou- voir accéder à d’avantage d’informations à propos des bijoux. Si l’utilisateur est intéressé par un bijou, il devra pouvoir aisément accéder à l’ensemble des photogra- phies du bijou, ainsi qu’à sa description. Contact Il devra alors se voir proposer à nouveau de contacter l’artisan, mais cette fois dans le cas où il aurait des questions sur le bijou en particulier. Panier Ensuite, l’utilisateur devra pouvoir ajouter le bijou qu’il consulte à son panier. Éventuellement, si le bijou n’est pas unique, l’utilisateur pourra en ajouter plusieurs à son panier. 8
Commande L’utilisateur pourra ensuite passer commande en validant son panier, et dans la foulée effectuer le paiement de sa commande. Pour cela, il devra être authentifié, ce qui nous mène à d’autres besoins : Authentification L’utilisateur, s’il possède déjà un compte sur le site, doit pou- voir s’authentifier. Il faudra qu’il puisse le faire à tout moment, mais que lorsqu’il tente de réaliser une action qui nécessite d’être authentifié, il soit redirigé pour le faire. Inscription Si l’utilisateur ne possède pas de compte, il faudra qu’il puisse s’en créer un. Il devra renseigner une adresse email et un mot de passe, puis par souci de sécurité un email devra lui être envoyé pour valider son compte. Côté administrateur Gestion des bijoux L’artisan devra pouvoir consulter les bijoux qu’il a créé. Il devra de plus pouvoir en créer de nouveaux et modifier ceux déjà présents (par exemple ajouter des photographies ou modifier la description). Contact L’artisan devra pouvoir voir les messages qui lui ont été envoyés par l’intermédiaire du site, et y répondre. Commandes Les commandes devront être notifiées à l’artisan, et leur détail devra lui être disponible. Il devra par ailleurs pouvoir notifier automatiquement l’utilisa- teur de l’avancement de sa commande (préparation, en cours de livraison). Autres Unité graphique Il faudra aussi que l’application web présente un univers gra- phique cohérent, marqué en particulier d’un logo et de quelques éléments présents sur toutes les pages. 1.1.2 Mise en place du cahier des charges Grâce à l’expression du besoin du client citée précédemment, j’ai pu mettre en place un cahier des charges, que j’ai ensuite fait valider par l’artisan. Page d’accueil La page d’accueil devra comporter : • une barre de navigation, arborant le logo et le nom du site, et permettant d’accéder à l’ensemble des bijoux, au formulaire de contact, au panier, et à la connexion/déconnexion. • un message de bienvenue • une sélection de bijoux • un lien vers l’index des bijoux • une présentation de l’artisan • le formulaire de contact 9
Index On aura de plus une page index de tous les bijoux, sur laquelle seront affichés une photographie, le nom et le prix de chaque bijou. On mettra en place un système de pagination pour ne pas avoir à trop faire défiler la page. Show La page show contiendra le détail de chaque bijou, avec toutes ses photo- graphies, sa description complète, et un formulaire de contact dont l’objet aura été prérempli pour annoncer le fait qu’il s’agit d’une prise de contact à propos d’un bijou. Contact Le module de contact devra permettre d’envoyer un email à l’artisan. Celui-ci pourra ensuite se servir des informations transmises par le formulaire (objet et adresse email) pour répondre par mail. Panier Mise en place d’un panier standard, stocké dans les variables de session Commande Commande stockée en base de données, envoyée par email à l’artisan, et consultable sur l’interface administrateur, depuis lequel on pourra envoyer les mails automatiques de suivi de la commande. Authentification Mise en place d’une page de login et d’une page d’inscription. Pour pouvoir s’authentifier comme un utilisateur, il faudra au préalable que celui-ci ait été validé. Pour ce faire, la page d’inscription enverra un email contenant un lien unique de vérification (limité dans le temps). 1.2 Environnement humain et technique 1.2.1 Environnement humain J’ai effectué tout mon projet depuis chez moi, à cause du contexte sanitaire. Ce projet n’a pas été effectué dans le cadre d’un stage, et je ne dépendais d’aucune entreprise. Pendant mon projet, j’ai principalement intéragi avec mon client (l’artisan), pour faire valider mon travail et pour recueillir ses suggestions ; et avec divers internautes, par le biais notamment de forums et de la plateforme Reddit, pour me documenter et trouver des solutions aux éventuels problèmes que j’ai rencontré. 1.2.2 Planification et gestion du temps Étant données les conditions particulières dans lesquelles j’ai travaillé, j’ai dû m’organsier seul, et cela s’est ressenti directement sur ma planification. J’ai utlisé l’outil en ligne Trello pour séparer aussi bien que possible les tâches, avec les trois colonnes usuelles (To Do, Doing, Done), et un code couleur pour démarquer l’urgent du moins pressé et le facultatif de l’obligatoire. Étant donné que mon projet ne s’inscrivait pas dans le cadre d’un travail en entreprise ni d’un projet avec l’école, j’ai du le commencer sur mon temps libre. J’ai ensuite organisé mon travail en fonction des fonctionnalités du projet : je commence à en concevoir une, et lorsque je suis bloqué j’effectue des recherches sur Internet et 10
si possible je me fais aider par d’autres développeurs ; et, en attendant que je trouve le moyen de me débloquer, je commence (sur une autre branche, cf section 1.2.3 sur Git) à programmer une nouvelle fonctionnalité. J’ai pu travailler comme ça sur 2, 3 voire 4 fonctionnalités simultanément. L’avancement du projet était principalement marqué par mes merges Git sur la branche principale, et c’est en me basant sur ceux-ci que je mesurais mon avance- ment. 1.2.3 Environnement technique Plateformes J’ai travaillé sur plusieurs systèmes d’exploitation. J’ai commencé le projet sur Windows (10) et Ubuntu (20.04). Je l’ai terminé sous Kali Linux. Et le serveur utilisé pour la production est sous Ubuntu 16.04. J’ai donc eu l’occasion d’expérimenter avec les différents outils sous Windows comme sur Linux. Git Afin de développer sereinement mon application, j’ai choisi d’utiliser Git (version 2.29), l’un des outil de versionning les plus utilisés dans le monde du développement web. Ce dernier présente de nombreux avantages qui m’ont été utiles tout au long de mon projet : • la possibilité de revenir en arrière dans le cas où les dernières modifications ne sont pas satisfaisante • la possibilité de développer plusieurs couches différentes de mon application en parallèle (ne pas être obligé de finir chaque fonctionnalité avant de passer à la suivante), à l’aide des branches. J’avais en particulier deux types de branches : la branche dev, contenant la dernière version fonctionnelle du code, utilisée aussi pour la production, et les branches de toutes les fonctionnalités en cours de développement • un dernier avantage, que je n’ai pas eu l’occasion d’expérimenter dans mon projet : la possibilité de faire valider mon code par un autre développeur (à l’aide notamment de merge requests, où la mise à jour de la branche principale est soumise à la relecture d’un autre développeur, et à sa validation). Pour pouvoir utiliser Git comme moyen de télécharger les dernières modifications ap- portées à mon projet sur mon serveur (pour la production), j’ai utilisé la plateforme en ligne GitLab, sur laquelle j’ai créé un projet privé. Choix de l’IDE J’ai choisi l’IDE PhpStorm, pour les deux raisons suivantes : d’une part c’est un IDE qui m’a été recommandé par des développeurs senior pour travailler sur du Symfony ; et, d’autre part, l’INSTIC me procure une licence gratuitement. Parmi les fonctionnalités proposées par PhpStorm, on peut notamment citer : autocompletion, génération automatique de ”PhpDoc” (commentaires de documentation du code), chargement automatique de dépendances, terminal intégré, plugins pour Symfony, gestion graphique de Git. 11
1.3 Spécifications 1.3.1 Spécifications fonctionnelles État des lieux Dans un premier temps, afin de visualiser et de mieux comprendre l’expression du besoin de l’artisan, nous avons réalisé deux diagrammes de cas d’utilisation. Voici le premier, qui concerne la partie utilisateur (front-end). Figure 1.1 : Diagramme de cas d’utilisation pour l’utilisateur On voit sur ce diagramme que les utilisateurs font appel à la base de données pour afficher les bijoux, se connecter et s’inscrire ; il font de plus appel au client SMTP (cf section 2.3.3) pour envoyer des mails automatiquement lors de certaines actions, comme compléter le formulaire de contact ou s’inscrire (email de confirma- tion de l’adresse email) ou encore passer commande (deux mails : notification de passage de commande à l’utilisateur et à l’administrateur). Voici le second diagramme, celui cette fois de la partie administrateur (back-end). 12
Figure 1.2 : Diagramme de cas d’utilisation pour l’administrateur Fort de ces informations et du cahier des charges, j’ai pu élaborer une arbores- cence du squelette du site. Les pages sont représentées en ignorant les permissions nécessaires pour y parvenir. Figure 1.3 : Arborescence du site Analyse J’ai pu tirer de la partie précédente les informations nécessaires à la constitution d’un diagramme de classes (pour les classes ”entités” uniquement, car avec Symfony beaucoup de fichiers définissent des classes). Le voici : 13
Figure 1.4 : Diagramme de classes des entités du mon projet En complément, voici le diagramme de classes des services implémentés tout au long de mon projet : Figure 1.5 : Diagramme de classes des services du projet 14
Wireframe Pour la partie graphique, j’ai réalisé un wireframe décrivant pour mon client les grandes lignes de la disposition de la page d’accueil (que celui-ci a validé). Le voici : Figure 1.6 : Wireframe de la page d’accueil du projet Comme décrit dans la partie 2.1.4, j’ai utilisé pour le graphisme du site un template Bootstrap (le template ”Agency”). Bootstrap est un projet regroupant un ensemble d’outils (HTML, CSS, SCSS, JavaScript) pour développer des applications 15
web responsive. Pour la maquette, j’ai donc simplement présenté au client le site juste après avoir mis en place le thème et retiré les parties dont je ne me servirai pas pour le site (services, about et partenaires). 1.3.2 Spécifications techniques La programmation orientée objet La programmation orientée objet, que j’ai utilisé tout au long de mon projet, est un paradigme de programmation consistant à regrouper certaines informations liées entre elles conceptuellement dans des ”objets”. Ces derniers étendent en quelque sorte la notion de variable : là où une variable est définie par un type et une valeur, un objet est défini par des attributs (qui eux-mêmes sont soit des variables soit d’autres objets), et par des méthodes, qui peuvent par exemple être des fonctions, et qui n’ont de sens qu’en lien avec l’objet dont elles découlent. Prenons un exemple tiré de mon projet (j’ai volontairement enlevé une partie des commentaires et certaines méthodes afin de simplifier pour illustrer de manière minimale la programmation orientée objet) : 1 class Image 2 { 3 /** 4 * @ORM\ Column (type =" integer ") 5 */ 6 private $id; 7 8 /** 9 * @ORM\ Column (type =" string ", length =255) 10 */ 11 private $name; 12 13 /** 14 * @ORM\ ManyToMany ( 15 * targetEntity = Bijou :: class 16 * ) 17 */ 18 private $ bijous ; 19 20 public function __construct () 21 { 22 $this -> bijous = new ArrayCollection (); 23 } 24 25 public function getId (): ?int 26 { 27 return $this ->id; 28 } 29 30 public function getName (): ? string 31 { 32 return $this ->name; 33 } 34 35 public function setName ( string $name): self 36 { 37 $this ->name = $name; 16
38 39 return $this; 40 } L’entité Image est ici implémentée par une classe (d’objet). Elle possède trois attributs : $id, $name et $bijou. Les deux premiers sont des variables (de type ”integer” et ”string”), et le troisième est un autre objet (de classe ”bijou”). Le contructeur __construct est une méthode particulière à la programmation orientée objet, qui permet d’éventuellement initialiser les attributs de l’objet lors de sa création. Enfin, les ”getters” et ”setters” getId(), getName() et setName() sont tous trois des méthodes de classe (permettant d’invoquer l’attribut auquel ils sont associés : pour obtenir la valeur de l’attribut $name d’un objet de la classe Image, le code est : $objet->getName()). L’architecture MVC L’architecture ”Modèle-Vue-Controlleur”, dite MVC, fait partie des briques de base sur lesquelles j’ai construit mon projet. Elle consiste en une factorisation du code bien particulière, reposant sur trois composants principaux : le controlleur, qui contient le code qui doit être exécuté ; la vue, qui contient le code de la partie visible du projet (HTML, Twig dans ce projet) ; et enfin le modèle, qui gère les intéractions avec la base de données. On a en résumé le schéma suivant : Figure 1.7 : Schéma récapitulatif du modèle MVC Cepandant, tout du long de ce projet, je ferai appel à des fichiers n’entrant dans aucune catégorie (services, interfaces...). Nous ferons aussi appel de façon implicite (cf paragraphe 1.3.2 sur Symfony) à un quatrième élément parfois ajouté au modèle MVC : le routeur. Symfony J’ai décidé pour ce projet de faire appel à un framework de PHP : Symfony. C’est l’un des deux frameworks majeurs du développement web PHP d’aujourd’hui (avec 17
Laravel). Les intérêts d’un tel framework sont multiples : la structure en couches est inté- grée, la sécurité est un des piliers de Symfony, les bonnes pratiques sont largement favorisées, l’organisation en services est naturelle, de nombreux bundles sont dispo- nibles et immédiatement utilisables... On peut de plus analyser finement les opérations se déroulant sur l’application, grâce notamment à la ”debug bar” dans l’environnement de développement (qui permet par exemple d’avoir le détail sur les éventuels codes d’erreur HTTP, sur les mails envoyés, l’utilisateur connecté, les logs...). J’ai utilisé la version la plus récente disponible (Symfony 5). J’ai commencé le projet avec la version 5.1, et je suis monté par la suite à la version 5.2, en raison d’une fonctionnalité de sécurité intéressante de cette version (cf partie 2.9 sur le login-throttling). Gestion des dépendances Composer Le gestionnaire de dépendances que j’ai utilisé est bien connu des développeurs PHP : composer. À l’instar de npm par exemple, composer permet d’installer et de mettre à jour des dépendances, à l’échelle d’un projet (ce qui le différencie d’un gestionnaire de paquet, comme apt pour Debian Linux et ses dérivés, qui eux installent leurs paquets à l’échelle du système). Quelques exemples de dépendances que j’ai installées avec composer tout au long du projet : Webpack encore (cf partie suivante), un composant pour ”slugifier” des titres en URL, un mailer de Symfony supportant le SMTP... J’ai utilisé la version 1.10 de composer. Yarn, Webpack Encore Là où pour installer et gérer les dépendances PHP, j’ai utilisé composer, pour les dépendances JavaScript et CSS, j’ai utilisé Yarn et Webpack Encore. Yarn est une surcouche de npm, le gestionnaire de dépendances Node JS, présentant quelques différences avec ce dernier, notamment une gestion améliorée du cache. Webpack Encore est un bundler : il permet de synthétiser et de minifier tous les assets JS, SCSS, CSS, images... du projet, diminuant ainsi au maximum le nombre et la longueur des fichiers à lire par l’application. Twig Twig est le moteur de templates que j’ai utilisé tout au long de mon projet. Un moteur de templates est un outil permettant de simplifier au maximum la partie traitement associée aux vues (cf 1.3.2 sur le modèle MVC), afin de séparer au maximum la partie interface graphique de la partie traiement. Twig est en général le moteur de templates privilégié quand on travaille avec Symfony. Le but d’un moteur de template est d’intégrer les éléments logiques et les éléments de traitement simple nécéssaires aux templates (boucles, appel de variables, filtres...). Voici un exemple très simple de l’intérêt de Twig : on peut considérer le code PHP et HTML suivant, permettant d’afficher le contenu échappé d’un attribut $name d’un objet de la classe Bijou : 18
Le voici en Twig : {{ bijou .name|e }} On voit bien par cet exemple l’intérêt d’un moteur de templates optimisé. J’ai utilisé Twig 3.0, HTML 5 et CSS 3. MySQL MySQL est le système de gestion de bases de données (SGBD) que j’ai utilisé pour ce projet. J’ai principalement fait ce choix car c’est le SGBD avec lequel j’ai le plus d’expérience. Pour pouvoir travailler sur les différentes plateformes citée au 1.2.3, j’ai choisi d’héberger ma base de données sur mon serveur. Pour controller le contenu de ma base, j’ai utilisé l’interface en ligne PhpMyAd- min (version 5.0). J’ai utilisé la version 5.7 de MySQL. Pour la sécurité de ma base de données (étant donné qu’elle est accessible di- rectement via Internet), j’ai bien sécurisé le compte root (avec un mot de passe aléatoire de 24 caractères de toutes les sortes, accessible par mon gestionnaire de mots de passe), et j’ai créé un utilisateur spécialement pour la base de données du projet, qui a tous les droits sur cette base mais sur aucune autre. Ainsi, mes bases de données ne seraient pas exposées dans le cas d’une attaque ou d’une erreur exposant mes identifiants (présents en dur dans mon projet Symfony). De plus, pour limiter au maximum le risque d’une telle attaque, le fichier .env, que je commit avec Git, ne contient pas mes identifiants de base de données, ni mes identifiants SMTP permettants d’envoyer les mails : ces derniers sont dans un fichier .env.local, qui prime sur le .env, et qui est cité dans mon .gitignore (il n’est pas commité, et par conséquent une faille de sécurité sur GitLab ne les exposerait pas). 1.3.3 Sécurité Je reviens sur toutes les mesures mises en œuvre pour la sécurité dans la partie 2.9. Voici néanmoins quelques éléments essentiels que nous pouvons citer dans cette partie : → La partie administrateur et la partie paiement sont protégées par l’authentifi- cation (l’administrateur doit de plus bénéficier d’un rôle spécifique) → Dans les formulaires du site accessibles aux utilisateurs, les champs sont vérifiés (adresse email valide, code postal ne contenant que des chiffres...) et, quand elles sont affichées, les variables dont la valeur a été définie par l’utilisateur sont échappées par le moteur de templates. 19
Chapitre 2 Réalisation du projet 2.1 Premiers pas 2.1.1 Créations préliminaires La base de données J’ai créé la base de donnée biju de mon projet à partir de l’interface graphique en ligne phpMyAdmin. Je m’y suis connecté comme l’utilisateur root (administrateur), puis j’ai créé la base avec l’encodage utf8_general_ci. Je me suis ensuite connecté (via SSH) à mon server, et j’ai lancé l’invité de commande de MySQL, à nouveau en temps que root. J’ai ensuite créé l’utilisateur (appelons le alice). Pour cela j’ai utilisé la commande suivante : CREATE USER 'alice '@'%' IDENTIFIED BY 'password '; Il est évident que l’utilisateur réel que j’ai créé a un nom et un mot de passe plus sécurisés. J’ai ensuite accordé à alice tous les privilèges sur la base de données avec la commande suivante : GRANT ALL PRIVILEGES ON biju .* TO 'alice '@'%' IDENTIFIED BY 'password '; Le projet GitLab J’ai créé sur GitLab (j’avais déjà un compte auparavant) un projet qui me servira de remote pendant tout mon travail. J’avais ce besoin pour la raison suivante : comme je ne travaillais pas toujours sur la même machine, c’était un moyen de synchroniser mes postes. De ce point de vue c’était plus une sécurité, car en réalité j’utilise un autre outil pour les synchroniser (Syncthing, avec lequel je crée un backup en temps réel de mes documents sur mon serveur, qui synchronise à son tour les autres machines). Je pouvais grace à cela avoir l’esprit tranquille, car s’il y avait eu un problème dans la synchronisation je pouvais toujours effectuer un git pull pour avoir la dernière version de mon travail. 20
2.1.2 Création du projet Symfony J’ai commencé par installer composer, en suivant la documentation en ligne. J’ai ensuite créé mon projet Symfony à l’aide de la commande : cd chemin /du/ dossier / parent / composer create - project symfony /website - skeleton biju Cette commande permet de créer toute la structure (le ”squelette”) de l’applica- tion Symfony. En voici les pricipaux éléments : • Le dossier bin contient les éxécutables, comme le script PHP console (appelé par la commande php bin/console {...}) • Le dossier config contient tous les fichiers de configuration des bundles (par défaut, il contient par exemple services.yaml, packages /security.yaml ou encore packages/twig.yaml. • Le dossier migration : j’y reviendrai quand nous parleront de Doctrine • le dossier node_modules : j’y reviendrai quand nous parlerons de Webpack Encore et de Yarn • Le dossier public : c’est le dossier qui contient le fichier index.php, qui va dicter le compor- tement de l’appication, en interprétant no- tamment les routes. Il contiendra aussi les assets (en version compilée) du projet, et en production le fichier .htaccess nécessaire au fonctionnement d’Apache. • Le dossier src contiendra les classes PHP, que ce soient les contrôleurs, les services, les inter- faces, les entités... C’est celui qui contiendra la majorité de mon travail. • Le dossier templates contiendra les vues (cf 1.3.2 sur l’architecture MVC), ainsi que les templates d’email (en MJML, cf la partie 2.3.3) • Le dossier var contiendra notamment les fichiers de log et le cache de Symfony • Le dossier vendor contiendra toutes les dépendances PHP du projet • Enfin, parmis les fichiers à la racine du projet, on peut citer notamment le fichier .env et le fichier .env.local, qui contiendront les informations de connexion à la base de données et au mailer ; le fichier .gitignore, qui régira quels fichiers ne seront pas inclus dans Git ; le fichier composer.json, qui contien- dra les versions de tous les packages installés pour le projet, par composer ; et enfin le fichier package.json, équivalent du composer.json mais pour Yarn. 21
2.1.3 Installation des premiers composants Sur chaque système, j’ai installé yarn. La méthode diffère un peu en fonction de l’OS : en effet, sur une des machines Linux l’installation par le gestionnaire de dépendances NodeJS npm n’a pas fonctionné, et j’ai donc installé yarn par le gestionnaire de paquets de la distribution (apt). J’ai ensuite installé Webpack Encore, dans le projet cette fois, avec composer. Pour ce faire, j’ai éxécuté les commandes suivantes : composer require symfony /webpack -encore - bundle yarn install Pour finir, j’ai rajouté quelques lignes à la configuration par défaut de Webpack Encore, dans le fichier webpack.config.js : 1 . enableSassLoader () 2 3 . copyFiles ([ 4 { from: './ assets /images ', to: 'images /[ path ][ name ].[ hash:8 ].[ ext]' }, 5 { from: './ assets /fonts ', to: 'images /[ path ][ name ].[ hash:8 ].[ ext]' } 6 ]) La ligne 1 permet d’activer le support du SCSS, dont je me servirai pour le style de mon projet ; les lignes 3 à 6 spécifient comment copier les assets dans le fichier public. En particulier, pour optimiser la gestion du cache, les fichiers images et polices comporteront un hash dans leur nom, qui sera regénéré à chaque fois que je lancerai la commande yarn dev (ou en production, yarn build). 2.1.4 Thème Bootstrap et grandes lignes du front J’ai choisi d’utiliser Bootstrap pour ce site pour les mêmes raisons que celles qui le rendent si populaire : il est d’abord extrèmement bien documenté ; il est aussi très simple d’utilisation, d’autant que je m’en suis déjà servi ; et enfin, peut-être le plus important : il permet d’obtenir une application responsive. Le thème ”Bootstrap Agency” J’ai sélectionné pour le design de la page d’accueil de mon projet un thème Bootstrap gratuit trouvé sur Start Bootstrap 1 : le thème ”Agency” 2 . Celui-ci est composé d’une page unique, séparée en plusieurs parties : accueil, services, portfolio, about, team, contact. Parmis celles-ci, j’ai choisi de ne garder que : l’accueil ; le portfolio, qui contiendra les six derniers bijoux créés par l’artisant sous forme d’image-cards Bootstrap ; la partie team, et enfin la partie contact. Pour la partie portfolio, le thème propose d’utiliser des modales Bootstrap pour aller plus loin et visualiser plus d’informations que l’image-card. J’ai choisi de faire autrement et de rediriger plutôt vers la page du bijou. 1. https ://startbootstrap.com/templates 2. Template prévisualisable en ligne, à https ://startbootstrap.com/previews/agency 22
La navbar Création du logo J’ai commencé par créer un logo très simple, le nom du site, ”BiJu”, dans une police cursive un peu stylisée, et coloré dans l’esprit du thème du site : en doré. Voilà le résultat : Figure 2.1 : Premier logo pour le site Ce logo apparait dans la barre de navigation (présente sur toutes les pages), ainsi que dans tous les mails envoyés par l’application. Le fond est transparent pour pouvoir s’adapter à tous les contextes (par exemple, il est affiché par dessus une image sur la page d’accueil, et sur un fond clair uni sur l’index des bijoux). Positionnement de la navbar Le thème Agency propose une barre de naviga- tion fixe sur l’écran (qui descend lorsqu’on fait défiler la page vers le bas). L’artisan souhaitait plutôt qu’elle soit fixe sur la page (qu’elle soit masquée quand on fait dé- filer vers le bas). Pour réaliser cela, j’ai joué sur les propriétés de positionnement de CSS. J’ai englobé toute la page dans une div de classe wrapper, à laquelle j’ai attribué le style position: relative et j’ai ensuite attribué à la navbar la classe Bootstrap position-absolute, qui lui donne le style position: absolute. Avec ces deux éléments, j’ai bien obtenu une navbar fixe par rapport à la page, et pas à l’écran. Pour trouver comment obtenir ce résultat, j’ai commencé par rechercher sur Internet (en anglais), et ne trouvant pas ce que je cherchais, je me suis tourné vers le forum Stack Overflow. J’y ai posé ma question en anglais, et j’y ai obtenu une réponse dans les jours qui ont suivi, également en anglais. Le fil en question peut être consulté ici 3 . 3. https ://stackoverflow.com/questions/66049066/stack-navbar-and-the-next-section 23
2.2 Le CRUD (Create, Read, Update and Delete) des bijoux 2.2.1 L’ORM de Doctrine Doctrine est un projet visant à implémenter en PHP des composants faisant le lien entre des objets et des éléments de base de données. On peut lire sur le site web l’introduction suivante : ”The Doctrine Project is the home to several PHP libraries primarily focused on database storage and object mapping. The core projects are the Object Relational Mapper (ORM) and the Database Abstraction Layer (DBAL) it is built upon.” Je vais principalement utiliser dans ce projet l’ORM. Il me permettra d’intéragir avec la base de données (je n’aurai besoin d’écrire aucune requête SQL, bien que de les comprendre pourra être utile pour vérifier mon travail) ; il permettra de plus de faire le lien objet-table de base de données quand ça sera nécessaire. 2.2.2 Création de l’entité Bijou Création Pour créer une entité avec Doctrine, j’ai utilisé le script console de Symfony. Les entités sont les classes que je persisterai en base de données (sauf, comme nous le verrons, l’entité Contact). Pour ce faire, je lance dans un terminal ouvert à la racine du projet la commande : php bin/ console make: entity Bijou Je suis alors le cheminement imposé par la console, au cours duquel je crée les diffé- rents attributs de ma classe Bijou, en spécifiant leur type, ainsi que les informations nécessaires à leur persistence en base de données (taille par exemple, pour les types string, ou encore si la valeur peut être nulle en base de données). Pour la classe Bijou, j’ai créé les champs suivants : name, price, description, created_at. Doctrine crée automatiquement un champ id, de type entier, qui aura le rôle de clé primaire en base de données. Par ailleurs, j’ajouterai plus tard un champ images. J’ai mis en annexe A la classe générée à la fin du processus. Persistence en base de données La prochaine étape est de créer une migration. Pour cela, j’utilise la commande php bin/ console make: migration Cette commande crée un fichier de migration dans le dossier migrations. Celui- ci contient les requêtes SQL qui vont être exécutées lors de la prochaine étape. Un fichier de migration contient deux fonctions, up et down, (qui correspondent respectivement à la migration et à l’annulation de celle-ci) qui contiennent elles- même les requêtes. En voici un exemple : 1 public function up( Schema $ schema ) : void 2 { 24
3 $this -> addSql ('CREATE TABLE bijou (id INT AUTO_INCREMENT NOT NULL , name VARCHAR (255) NOT NULL , price INT NOT NULL , description LONGTEXT NOT NULL , created_at DATETIME NOT NULL , images LONGTEXT NOT NULL COMMENT \'(DC2Type:array ) \', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4 _unicode_ci ` ENGINE = InnoDB '); 4 } 5 6 public function down( Schema $ schema ) : void 7 { 8 $this -> addSql ('DROP TABLE bijou '); 9 } Une fois que j’ai vérifié que la migration contenait bien tout ce que je voulais, j’exécute la dernière commande, pour migrer en base de données les modifications : php bin/ console doctrine : migrations : migrate Avec cette commande, la classe est maintenant accompagnée d’une table en base de données, dans laquelle on pourra persister les objets créés, pour pouvoir par la suite y faire appel. 2.2.3 Génération du CRUD avec Doctrine Un CRUD (Create, Read, Update and Delete) est une structure d’application côté back-end permettant de gérer les instances d’une entité persistées en base de données. Dans notre cas, il s’agit de pouvoir créer, appeler (pour afficher), modifier et supprimer des bijoux en base de données, en passant uniquement par le back-office. Il est bien sûr possible de créer un CRUD manuellement, mais Symfony propose, grâce notamment à Doctrine, d’automatiser la création de la structure. Ainsi, pour le créer, j’ai simplement eu (une fois l’entité Bijou créée) à exécuter la commande suivante : php bin/ console make:crud Cette commande fait appel au bundle MakerBundle, qui permet de générer au- tomatiquement le code associé à certaines fonctionnalités, comme ici le CRUD. Elle crée dans notre cas un certain nombre de choses : • un contrôleur src/Controller/BijouController.php : ce contrôleur contiendra toute les routes associées au CRUD, ainsi que toute la logique des différents composants. Il contiendra en particulier les fonctions index, new, show, edit et delete. • les vues index, show, new, edit, _delete_form et _form créées dans le dossier templates/bijou et au format .html.twig. • et le fichier src/Form/BijouType.php, qui contient les informations nécessaires à la création des formulaires du CRUD. Le CRUD est donc maintenant créé. Cependant, il reste quelques détails à régler. Dans un premier temps, voyons comment générer des bijoux factices pour pouvoir travailler sans perdre de temps à créer véritablement des bijoux ; nous verrons ensuite la création de slugs pour embellir les URL ; enfin, nous verrons la gestion des images. 25
La data fixture pour obtenir des données de travail Le but des fixtures est de générer de ”fausses” données avec lesquelles on peut travailler. Il est possible de gérérer des fixtures avec Doctrine. Pour ce faire, on commence par installer le bundle : composer require --dev orm - fixtures J’ai choisi d’utiliser en plus un autre bundle, qui permet de générer des données aléatoires de tous les types, utile pour donner des valeurs à tous les attributs des bijoux : fzaninotto/faker. Voici la fixture que j’ai utilisé pour me donner une base de travail pour mon projet : 1 public function load( ObjectManager $ manager ) 2 { 3 $ faker = Factory :: create ('fr_FR '); 4 for ($i = 0; $i < 100; $i++) { 5 $bijou = new Bijou (); 6 $bijou 7 ->setName ($faker -> words (3, true)) 8 -> setDescription ($faker -> sentences (3, true)) 9 ->setPrice ($faker -> numberBetween (1, 20)) 10 $manager -> persist ($ bijou ); 11 } 12 $manager -> flush (); 13 } On voit par exemple que je génère 100 bijoux, et que le nom généré pour les bijoux sera composé de trois mots aléatoires (tirés je pense du Lorem Ipsum). Pour exécuter la fixture, il me reste simplement à exécuter la commande : symfony console doctrine : fixtures :load Accéder aux bijoux Dans un projet Symfony, la partie modèle de l’architecture MVC est répartie sur plusieurs fichiers. Parmis eux, les entités et les repositories. Afin de sélectionner les bijoux souhaités sur les différentes pages, j’ai fait appel à ces derniers. Par exemple, pour la page d’acceil, je ne souhaite récupérer que les 6 derniers bijoux. Pour cela, j’ai écrit la fonction suivante dans le fichier src/BijouRepository.php : 1 public function findLatest (): array 2 { 3 return $this -> findVisibleQuery () 4 ->orderBy ("p. created_at ", "DESC") 5 -> setMaxResults (6) 6 ->getQuery () 7 ->getResult (); 8 } où la fonction findVisibleQuery récupère tous les bijoux en vente dans la base de données. 26
Slugs Par défaut, la route pour afficher un bijou est définie dans le contrôleur Bijou- Controller par le commentaire suivant de la fonction show : 1 * @Route ("/{ id}", name=" bijou_show ", methods ={"GET", "POST"}) On souhaiterait que la route soit un peu plus parlante, qu’elle rappelle par exemple le nom du bijou. Pou ce faire, j’ai choisi d’utiliser le bundle cocur/slugify. J’ai donc créé un getter getSlug() comme suit : 1 public function getSlug (): string 2 { 3 return (new Slugify ())->slugify ($this ->name); 4 } J’ai ensuite simplement modifié la route comme suit : 1 * @Route ("/{ slug }-{id}", name=" bijou_show ", requirements ={"slug ": "[a-z0-9 `-]*"}, methods ={"GET", "POST"}) Deux remarques : pour appeler la route dans un template, il suffit d’accéder au slug avec Twig comme ceci (exemple tiré de la page index des bijoux) : 1 Enfin, l’expression régulière permet d’ajouter un peu de sécurité en garantissant qu’aucun contenu problématique ne peut être inséré dans l ’URL. 2.2.4 Ajout des images par relation Création de l’entité Image J’ai commencé par concevoir les images comme un attribut de type array de la classe Bijou. Cependant, cette méthode s’est révélée difficile d’utilisation, notam- ment parce qu’en base de données, l’array était stocké au format JSON, qui est très peu lisible et donc difficile à manipuler. J’ai donc fait le choix de modifier ma conception, à la faveur d’images traitées comme des objets à part entière, reliées à la classe Bijou par une relation. J’ai choisi d’établir une relation ManyToMany pour me restreindre le moins possible à l’avenir, mais j’aurais tout aussi bien pu choisir une relation de type OneToMany. Petite précision sur la relation ManyToMany : en Merise, il s’agit d’une relation de type ”n,n”. Lors de la transcription d’une telle relation de le language de la base de données, on a alors non pas deux mais trois tables de générées : dans notre cas, une table image, une table bijou et une table bijou_image, dont les éléments contiendront deux clés primaires chacun, qui seront aussi clés secondaires associées aux clés primaires des deux autres tables. On aura donc le résultat suivant : 27
Figure 2.2 : MPD de la relation ManyToMany Pour mettre en place cette relation, j’ai d’abord créé l’entité Image, par la même méthode que la dernière fois : php bin/ console make: entity Image Je lui ai ajouté pour l’instant un seul attribut $name (et à nouveau Doctrine a créé automatiquement un attribut $id). J’ai ensuite ajouté un nouvel attribut $image à l’entité Bijou, en appelant à nouveau le script : php bin/ console make: entity Bijou Au moment de choisir le type, j’ai choisi la relation ManyToMany, et j’ai indiqué que la classe à associer était la classe Image. Création du service d’upload d’image Il a ensuite fallu créer un service pour uploader les images, et trouver le moyen de lier les images en base de données à leur fichier image correspondant. Pour cela, j’ai fait au plus simple : le champ $name de chaque image sera le nom du fichier uploadé. Il faudra donc établir un nom unique pour chaque image, pour par la suite renommer le fichier correspondant. La première étape a été d’ajouter un champ au formulaire associé aux bijoux : 1 $ builder 2 ->add('... ') 3 ->add('imageFile ', Filetype :: class , [ 4 'multiple ' => true , 5 'mapped ' => false , 6 ]) 7 ; Le code ci-dessus permet d’obtenir un champ d’upload de fichier : J’ai ensuite créé le service src/Services/UploaderService.php, dans lequel j’ai uti- lisé l’injection de dépendance pour appeler le chemin vers lequel je souhaite uploader 28
Vous pouvez aussi lire