Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Mes interventions sont sur deux modules de LP. Ces modules seront traitées dans la continuité indifféremment du code affiché.
Nous verrons les aspects suivant :
Symfony
VueJs
Lien entre Symfony et VueJs au travers des API
ApiPlatform
Testing
Vous pouvez installer Symfony dans un contexte docker ou sur votre système à votre convenance.
Dans tous les cas il vous faut :
Git
Composer et/ou Symfony CLI
PHP 8.1
Une base de données (MariaDb, MySql, PosGreSql, ...)
Une maîtrise de votre OS
PHPStorm et le plugin : https://plugins.jetbrains.com/plugin/7219-symfony-support
Vérifier que tout fonctionne
Installation de Symfony
ou avec la Symfony CLI
Réaliser un outil de dépôt de travaux étudiants, en utilisant Symfony. L'outil devra intégrer les fonctionnalités suivantes :
Inscription, connexion, déconnexion pour les étudiants
Création de rubriques (par un administrateur)
Possibilité de déposer un travail (vidéo, photo, ...), avec titre, description
Une recherche simple
Liste des catégories, et travaux associés
Administration : Création des catégories administration des utilisateurs et des dépôts
Il y aura 2 niveaux d'accès : Administrateur, étudiants (possibilité de déposer un travail ou de le modifier)
Les travaux comporteront des fichiers et/ou des liens
Possibilité de "noter" un travail (système de like par exemple). Affichage d'un top 3 par catégories.
Vous êtes libre de la structure, de la mise en page et des données de votre base de données, mais vous devez répondre à la commande
Dans le cadre de ce mini-projet vous utiliserez Webpack Encore pour la gestion de votre partie front (css/js) : https://symfony.com/doc/current/frontend.html
Le travail pourra être réalisé en binôme. Le rendu sera évalué le 13/12 en fin de séance.
L'esthétique du forum n'est pas prise en compte. L'usage d'une librairie CSS ou d'un template est suffisant.
Par contre, vous veillerez à l'ergonomie et à la lisibilité.
Le respect des consignes peut vous apporter jusque 15 points.
Les 5 points supplémentaires seront acquis en fonction des ajouts (pertinents) que vous ferez, soit pour proposer des fonctionnalités pertinentes, soit dans la qualité de la navigation et de l'accessibilité.
Réaliser un forum, en utilisant Symfony. Votre forum devra intégrer les fonctionnalités suivantes :
Inscription, connexion, déconnexion
Création de message dans les catégories du forum
Possibilité de répondre à un message
Une recherche simple
Liste des catégories, sous catégories, et messages associés
Administration : Création des catégories et sous-catégories, administration des messages
Il y aura 2 niveaux d'accès : Administrateur, membre (possibilité de créer un message ou de modifier ses messages)
Un message pourra intégrer des fichiers (images a minima)
Vous êtes libre de la structure, de la mise en page et des données de votre base de données, mais vous devez répondre à la commande d'un forum
L'esthétique du forum n'est pas prise en compte. L'usage d'une librairie CSS ou d'un template est suffisant.
Le respect des consignes peut vous apporter jusque 15 points.
Les 5 points supplémentaires seront acquis en fonction des ajouts (pertinents) que vous ferez, soit pour proposer des fonctionnalités pertinentes, soit dans la qualité de la navigation et de l'accessibilité.
Le travail est individuel, et sera évalué en direct lors de la séance prévue après le 4 janvier 2023.
Le sujet pourra évoluer en fonction de l'avancement du cours
Pour cette première séance vous devrez mettre en place les éléments suivants :
Une nouvelle installation de Symfony (6.1/6.2)
Réfléchir au MCD que vous aller mettre en place.
Mettre en place les entités et la base de données
Mettre en place les contrôleurs et les vues nécessaires à la navigation "publique" du site
Intégrer un template ou une librairie CSS et faire un minimum de mise en page
Mettre en place la sécurité et les éléments de connexions
Intégrer les formulaires et la gestion des messages sur la partie publique.
Mettre en place l'administration et les accès sécurisés.
Mettre en place l'upload
Tips : utiliser VichUploaderBundle ou manuellement FileUpload
Créer un nouveau projet Symfony et installer les dépendances nécessaires.
Pour rappel, en ligne de commande depuis Docker/serveur et dans le repertoire où vous souhaitez mettre votre projet :
symfony new nomDuProjet --webapp
Comme vous utilisez docker, pensez à créer un nouvel alias dans votre fichier de conf (symfony.conf) et redémarrer apache2
En utilisant la notion d'héritage des templates créez un menu avec 3 items :
Accueil (qui mènera vers /)
Articles (qui mènera vers /articles)
Recherche (qui mènera vers /recherche)
Chaque page sera associée à une méthode dans un controller différent.
En utilisant les assets installer Bootstrap.
Sur la page accueil insérez une image de votre choix
Sur la page articles, ajouter des articles dans votre méthode de controller (dans un tableau associatif, ajouter au moins 3 articles).
Affichez ces 3 articles dans votre page articles.
Un article est composé d'un titre, d'un texte (on peut utiliser du loreum ipsun), d'une date de publication (on utilisera un objet datetime), et d'un auteur.
Dans la page recherche, ajoutez simplement un formulaire de recherche comme vous l'auriez fait en BUT1.
Soignez un minimum la mise en page.
Pour la page recherche, on va simuler la récupération de la recherche utilisateur. Pour le moment, on a pas de source de donner pour effectuer la recherche.
Récupéré la recherche de l'utilisateur soumise avec un formulaire en method post ($request peut vous aider), et afficher dans une nouvelle page le mot recherché.
Vous veillerez à ce que le bon item soit "actif" dans le menu.
Depuis la version 4, Symfony à grandement simplifié la structure de ses répertoires et à normalisé les appellations pour coïncider avec la pratique de la majorité des framework.
Symfony à également abandonné la notion de Bundle, qui était nécessaire pour développer son projet.
bin/ : contient la console
config/ : contient les configurations des différents bundles, les routes, la sécurité et les services
public/ : c'est le répertoire public et accessible du site. Contient le contrôleur frontal "index.php" et les "assets" (css, js, images, ...)
src/ : contient votre projet (M et C du MVC)
templates/ : contient les vues (V du MVC)
var/ : contient les logs, le cache
vendor/ : contient les sources de bundles tiers et de Symfony
Vous remarques des fichiers au format yaml, le format par défaut pour la configuration de Symfony. Vous pouvez aussi remarquer les répertoires dev, prod et test. Ces répertoires permettent de facilement différencier une configuration pour un environnement de développement, pour le site en ligne, ou encore pour un contexte de test.
Par exemple, lorsque l'on développe, on ne souhaite pas réellement envoyer les mails aux usagers, par contre, on souhaite les visualiser. On peut donc configurer ce comportement dans le répertoire dev, pour le bundle de gestion des emails. Un autre exemple est la gestion des logs. En dev, on ne souhaite pas les conserver, mais les afficher, en production, on ne souhaite surtout pas les afficher, mais les stocker dans des fichiers.
Le concept est donc de définir le comportement global quelque soit l'environnement dans le fichier à la racine de config/packages, et de spécifier un comportement en fonction de l'environnement dans les répertoire dev, prod ou test.
Dans ce répertoire se trouve toute la logique de l'application, les contrôleurs, les modèles, nos classes spécifiques, les services, ...
Controller/ : Tous les contrôleurs de l'application, accessibles par des routes
Entity/ : Les classes spécifiques pour la gestion de l'application, des données et des API
Migrations/ : Contient les fichiers permettant la mise à jour de la base de données pour chaque modification effectuée sur la structure.
Repository/ : Est très généralement lié à une entité, et permet d'ajouter des requêtes spécifiques.
Tous ces points seront détaillés dans les parties suivantes.
La présentation : https://presentations.davidannebicque.fr/r319.html
Découvrir et appréhender un framework PHP web.
PHP
Programmation Orientée Objet
Structure MVC
Base de données
C'est lui qui reçoit l'interaction (la demande/request) du visiteur. Il se charge de récupérer les éléments nécessaires auprès du/des modèle(s). Il transmets toutes les données nécessaires à la vue.
C'est lui qui apporte la réponse (response/render) au visiteur. Une vue peut être une page web, un fichier pdf, ... Ne se préoccupe que de l'affiche des informations, n'assure aucun traitement
C'est lui qui s'occupe de récupérer et préparer les données. Le modèle peut être en lien avec une base de données. Le modèle peut être en lien avec des API. Le modèle prépare les données pour qu'elles soient facilement manipulables par la vue.
En programmation informatique, un framework ou structure logicielle est un ensemble cohérent de composants logiciels structurels, qui sert à créer les fondations ainsi que les grandes lignes de tout ou d’une partie d’un logiciel (architecture). Un framework se distingue d’une simple bibliothèque logicielle principalement par :
son caractère générique,
faiblement spécialisé,
contrairement à certaines bibliothèques ;
Un framework peut à ce titre être constitué de plusieurs bibliothèques chacune spécialisée dans un domaine. Un framework peut néanmoins être spécialisé, sur un langage particulier, une plateforme spécifique, un domaine particulier : reporting, mapping, etc. ;
Le cadre de travail (traduction littérale de l’anglais : framework) qu’il impose de par sa construction même, guidant l’architecture logicielle voire conduisant le développeur à respecter certains patterns (modèle de conception) ; les bibliothèques le constituant sont alors organisées selon le même paradigme.
Un framework dit orienté objet est typiquement composé de classes mères qui seront dérivées et étendues par héritage en fonction des besoins spécifiques à chaque logiciel qui utilise le framework.
Le développeur qui utilise le framework pourra personnaliser les éléments principaux du framework par extension, en utilisant le mécanisme d’héritage : créer des nouvelles classes qui contiennent toutes les fonctionnalités que met en place le framework, et en plus ses fonctionnalités propres, créées par le développeur en fonction des besoins spécifiques à son application.
Article comparatifs des 10 frameworks PHP les plus populaires de 2019: https://coderseye.com/best-php-frameworks-for-web-developers/
Framework MVC en PHP 5 (V2), PHP 7 (V3, V4 et V5 ), PHP8 (V6) libre
Développé en 2005 par la société Sensio pour répondre à ses besoins
Division de la société Sensio en deux entités l’agence Web et l’entreprise qui soutient et maintient Symfony : SensioLabs, dirigée par Fabien Potencier, l’auteur de Symfony
Framework français !, De renommée mondiale
Premier framework en France et en Europe
Connectable à presque tous les SGBD
De nombreux Bundles, contributeurs, utilisateurs
Moteur de template puissant et simple
Depuis la V4, Symfony est très léger et très rapide
Toutes les informations sur l'évolution du framework : https://symfony.com/releases
Avec sa version 4 (et suivante), Symfony à pris un virage important par rapport aux précédentes versions, et se rapproche des "standards" de la majorité des framework, mais à aussi grandement optimisé son poids et sa vitesse d'exécution. Dans une grande logique de simplification Symfony à également automatisé de nombreux mécanismes qui auparavant auraient impliqués de nombreuses lignes de configuration.
La version Skeleton de Symfony : Apporte un framework Symfony très léger, avec le minimum pour faire fonctionner un controller.
La version 4 de Symfony introduit Flex qui est un gestionnaire de "recipes" (recettes), qui permet l'ajout de fonctionnalité à Symfony (gestionnaire de vue, de base de données, d'email, ...) avec un mécanisme d'auto-configuration de ces "bundles". Cela permet donc de fournir par défaut un framework très léger, avec une grande facilité pour lui ajouter tous les composants nécessaires, sans en mettre plus que nécessaire.
Par défaut Symfony version Skeleton ne sais rien faire ! Par contre, il n'embarque pas des dizaines de Bundles dont vous n'aurez peut être jamais besoin (fonctionnement des versions 2 et 3 avec plus de 46 bundles par défaut, contre 10 aujourd'hui).
Grâce à Flex vous installez rapidement le nécessaire pour répondre à votre projet.
Avec sa version 5 (et suivante), Symfony continue sa simplification en facilitant l'usage de nombreux composants redéfinis et devenus génériques.
Une lecture intéressante sur la logique d'évolution du framework Symfony : https://www.disko.fr/reflexions/technique/symfony-4-4-5-0-les-nouveautes-venir/
Un serveur Web
PHP 8.1 ou supérieur
Le gestionnaire de dépendance Composer
ou Le nouveau gestionnaire d'installation de Symfony : https://symfony.com/download
Une maîtrise de son système d'exploitation ! (fichiers cachés, variables PATH, php.ini, console...)
Vous pouvez suivre aussi les éléments de la documentation officielle : https://symfony.com/doc/current/setup.html
L'ensemble de ce cours se base sur la version 6 de Symfony
Le cours des versions précédentes se trouve : ou
Avantages
Inconvénients
Pour éviter des erreurs dans l’organisation des appels
Éviter les appels directs aux commandes PHP
Préférer les versions des Frameworks qui apportent leur lot de contrôles.
Plus grand portabilité du code
Ne pas réinventer la roue
La gestion des formulaire, des utilisateurs, ...
Apprentissage d’une couche supplémentaire
La majorité des fonctionnalités PHP sont redéfinies
Généralement apprentissage d’un moteur de template
Apprentissage de l’utilisation du framework choisit : ses classes, ses objets, sa logique !
Pour créer une page dans Symfony, il faut, au minimum :
Une route : pour faire le lien entre une URL et une méthode d'un contrôleur
Un contrôleur : qui contient des méthodes, chacune, en générale, associée à une route
Une méthode : permet l'execution d'une action précise, généralement en lien avec une route
Ce code est votre premier contrôleur (à déposer dans src/Controller
). Ce contrôleur est composé d'une méthode qui calcul un nombre aléatoire et retourne une réponse. Ce code n'utilise pas directement les vues de Symfony, et ne fonctionne pas (en tout cas il n'est pas possible de l'appeler), car il n'est pas lié à une route.
Nous allons utiliser les Attributes, qui permettent une syntaxe plus simple, et une proximité entre la définition de la route et la définition de la méthode (il existe d'autres façons de faire, qui peuvent avoir leurs avantages et leurs inconvenients et dépendre des pratiques de l'entreprise).
Les Attributes, contrairement aux annotations, ne nécessitent pas de dépendances supplémentaires. En effet les Attributes sont maintenant natifs en PHP 8.0, et sont supportés par Symfony depuis la version 5.1.
Modifions le contrôleur précédent en intégrant directement la route sous forme d'Attribute.
Pour accéder a cette route, il faut maintenant taper l'URL suivante : http://localhost:8000/lucky/number
si vous executez le serveur de développement de Symfony. Sinon, il faut taper l'URL suivante : http://localhost:8000/public/index.php/lucky/number
. La partie locahost:8000 est à adapter en fonction de votre configuration.
Si vous testez cette URL, vous devriez voir affiché le nombre aléatoire. Cependant, regardez attentivement et vous verrez que ce qui est renvoyé n'est pas du HTML, mais du texte brut. C'est parce que nous n'utilisons pas encore les vues de Symfony, et que nous retournons directement une réponse sans plus d'information que cela sur le format retourné.
Cette solution fonctionne, mais écrire tout le code "HTML" dans la méthode n'est pas très pratique. Nous devons donc écrire des vues. Par défaut, Symfony utilise Twig. Pour cela, il faut l'installer
Il faut ensuite modifier le contrôleur pour utiliser les vues.
Il faut maintenant écrire la vue.
Et Voilà !
Symfony propose un outil qui se nomme "maker" qui permet de générer du code pour nous. Le code produit est très générique, ne correspond pas forcément exactement à vos besoin, mais permet d'avoir une première base de travail et une structure pour vos différents fichiers.
Pour installer le maker (si vous n'avez pas installé un projet avec toutes les dépendances --wepabb), en étant dans votre projet :
composer require maker --dev
ou
symfony composer require maker --dev
Ensuite pour utiliser le maker, dans le projet saisir la commande suivante
bin/console make:controller NomDuController
Cette commande va générer un controller nommé "NomDuController" (dans src/controller) et la vue associée dans le repertoire templates/NomDuController, avec une méthode index.
Pour ajouter d'autres méthodes, vous devrez le faire directement dans le controller, le maker ne permet pas d'en ajouter dans un fichier existant.
Deux notions majeures interviennent dans la conception de sécurité de Symfony :
Authentification : Qui êtes vous ? ; vous pouvez vous authentifier de plusieurs manières (HTTP authentification, certificat, formulaire de login, API, OAuth etc)
Authorization : Avez vous accès à ? ; permet d'autoriser de faire telle ou telle action ou accéder à telle page sans forcément savoir qui vous êtes, utilisateur anonyme par exemple.
Pour fonctionner, il est nécessaire d'ajouter le composant security à votre symfony.
Si vous avez installé le projet avec la version complète (webapp), cette ligne n'est pas nécessaire.
La sécurité dans symfony implique plusieurs éléments :
Le firewall: qui est la porte d'entrée pour le système d'authentification, on définit différents firewall (au minimum 1 seul) qui va permettre de mettre en place le bon système de connexion pour l'url spécifiée via un pattern.
Le provider : qui permet au firewall d'interroger une collection d'utilisateurs/mot de passe ; C'est une sorte de base de tous les utilisateurs avec les mots de passe. Il existe deux type par défaut :
in memory : directement dans le fichier security.yml mais du coup les hash des mots de passes sont disponible dans un fichier
Entity : N'importe quelle entité qui implémente à minima les deux interfaces
Enfin, plusieurs providers peuvent fonctionner en même temps par exemple in_memory et entity voire plusieurs entités simultanément.
Un encoder : qui permet de générer des hashs/d'encoder des mots de passe ; le plus connu étant MD5 mais vous pouvez utiliser d'autres encoders tels que : sha1, bcrypt ou plaintext (qui n'encode rien c'est le mot de passe en clair)
Les rôles : qui permettent de définir le niveau d'accès des utilisateurs connectés (authentifiés) et de configurer le firewall en fonction de ces rôles. Les rôles peuvent être hierarchisées afin d'expliquer par exemple qu'un administrateur (ROLE_ADMIN par exemple) et avant tout un utilisateur (ROLE_USER).
Le "guard" ou "authenticator" qui va gérer l'authentification, au travers de "passport". Il va par exemple vérifier que le couple login/mot de passe existe dans l'un des provider.
A partir de la version 4, et avec le composant "maker", la gestion de la sécurité a été grandement facilitée. Là où sur les précédentes versions (la 2 notamment), il était d'usage de passer par un bundle tierce (FOSUserBundle par exemple), aujourd'hui cela n'est plus nécessaire.
Si vous ne disposez pas encore d'une classe permettant la gestion des utilisateurs, il est possible d'en créer une avec la console. Si vous disposez déjà d'une classe utilisateur (ou que vous souhaitez utiliser plusieurs entités, il faudra modifier votre code en implémentant les interfaces UserInterface, PasswordAuthenticatedUserInterface
et en implémentant les méthodes imposées par ces interfaces).
L'instruction ci-dessous permet de lancer la console pour créer la table User.
Symfony va vous poser plusieurs questions afin de configurer les éléments (le nom de l'entité, si vous utilisez doctrine, le champ correspondant au login, et l'encodage du password.
Une fois cette commande exécutée vous avez un fichier d'entité de créé, un repository associé, et le fichier security.yaml (dans config) qui a été mis à jour.
Ce fichier fait le lien avec l'entité User (le provider), le login retenu (ici un email), et l'encodage du mot de passe, par défaut "auto"
Il faut ensuite mettre à jour votre base de données, avec les commandes suivantes:
Une nouvelle fois la console va nous permettre de dégrossir le travail et produire le contrôleur, le fichier de configuration et le formulaire de connexion.
Pour le résultat ci-dessous.
Cette commande, comme indiqué génère plusieurs fichiers :
LoginAuthenticator.php : qui explique comment on authentifie un utilisateur (au travers de passeport)
SecurityController.php : Car ici, nous avons choisi une connexion avec formulaire, ce contrôleur permettra d'afficher la page de login, de récupérer les informations et de gérer la déconnexion
login.html.twig : qui contient le formulaire
Le fichier security.yaml est mis à jour pour faire le lien avec cet authenticator.
Attention !! Il faut modifier la ligne 51 avec une route qui existe dans votre projet
La partie firewall est modifiée pour indiqué quel authenticator utiliser. On pourrait en avoir plusieurs.
Comme indiqué cette commande va créer plusieurs fichiers :
src/Security/LoginAuthenticator.php : qui va contenir la logique de votre authentification. Que faire une fois l'authetification réussie, ou en cas d'échec. Comment récupérer les informations de l'utilisateur.
src/Controller/SecurityController.php : qui va être le contrôleur gérant la partie sécurité et authentification. Par défaut la méthode login pour afficher le formulaire et traiter (avec l'aide de l'authenticator précédent), valider les données. C'est dans ce contraôleur que vous pouvez ajouter la déconnexion, l'enregistrement et le mot de passe perdu par exemple.
templates/security/login.html.twig : la vue contenant le formulaire de connexion, que vous pouvez librement adapter.
Mettre à jour le fichier security.yaml afin qu'il fasse le lien avec les différents éléments de sécurité.
Les étapes suivantes expliques ce qui a été créé.
Quasiment toute la sécurité se joue dans le fichier security.yaml qui fait le lien entre les différents éléments et gère les accès.
Tout est pré-confiuré, vous pouvez bien sûr adapter. L'encodage permet de définir le "format" de cryptage du mot de passe. Par défaut c'est "auto", c'est à dire que selon votre configuration Symfony choisira le niveau le plus élevé possible (bcrypt ou Argon2i)
Le Provider permet de faire le lien avec une source de données contenant les couples login/mot de passe ou des clés d'API... Les providers peuvent être des entités, des données "in_memory", ... Cette partie est configurée a été configurée suite à la création de l'entité User, avec la méthode de connection (login), ici l'email sera utilisé. Il est possible de coupler plusieurs provider tant que l'email est unique sur l'ensemble des sources.
C'est la partie essentielle du process de sécurisation. C'est lui qui permet de dire quand il faut vérifier et authentifier un utilisateur. Le firewall permet de déterminer pour un pattern d'url (une requête (request)), la méthode d'authentification à utiliser (une page de connexion, une clé d'API, une dépendance à un fournisseur OAuth, ...).
L'exemple ci-dessus permet de définir que pour les routes particulières (les assets, le profiler), il n'y a pas de vérification. Pour toutes les autres routes (main), il faudra utiliser le provider contenant nos User et l'authenticator gérant le formulaire de Login. C'est ici que l'on pourrait proposer plusieurs méthodes de connexion en ajoutant les authenticator adaptés.
La gestion des roles se fait dans la partie "access_control" du fichier security. Il permet de définir pour chaque pattern d'URL quel rôle peut y accèder. C'est là que l'on sécurise nos différentes parties. Il est donc important de construire et structurer nos URL correctement pour être efficace sur le filtrage. Il faut évidemment veiller à ce que les pages de connexion ne soient pas derrière une page sécurisée...
Exemple:
Enfin, il est souvent nécessaire de récupérer les informations sur l'utilisateur connecté. Pour cela, dans un contrô leur il est possible d'utiliser directement l'instruction :
Sur la même idée que pour la connexion, il est possible de gérer la déconnexion. Pour cela, dans le fichier security.yaml, il faut définir le path (la route) pour la méthode qui gére la déconnexion, et la cible (une route, optionnelle), une fois la déconnexion réussie.
La méthode dans le contrôleur peut se résumer à :
Cette méthode qui ne retourne rien, permet la déconnexion, et la redirection se fait via le target définit dans security.yaml.
Grâce à la console, il est possible de générer un mot de passe selon l'encodage utilisé par Symfony.
Il est possible d'ajouter des utilisateurs directement dans la base de données (par exemple avec PhpMyAdmin ou en mode console Mysql) avec le mot de passe encodé correctement ou alors en créant un formulaire d'inscription.
On va ajouter PhpMyAdmin à Docker, pour cela dans votre fichier docker-composer.yaml et ajouter les lignes ci-dessous :
Dans la table User ajouter une entrée, avec un mot de passe crypté, et un rôle, qui doit être un tableau, exemple : ["ROLE_ADMIN"]
Attention ! On modifie le docker-compose.yaml MMI pas celui de Symfony !!!
La aussi le maker peut nous aider grandement...
bin/console make:registration
Répondez aux questions, il est nécessaire d'installer un complément si vous voulez vérifier le mail de vos utilisateurs : composer require symfonycasts/verify-email-bundle
Mettre en place une classe User, et créer le formulaire de connexion en suivant la documentation (une commande dans le maker existe).
Ajouter une page qui ne sera accessible qu'a des utilisateurs Admin.
Vous pouvez ajouter une fonction pour récupérer le mot de passe perdu (une commande dans le maker existe...)
Dans Symfony la notion de modèle se retrouve sous la forme (entre autre) d'une Entité. Une entité est une classe PHP, qui peut être connectée à une table de votre base de données via l'ORM. Lorsqu'une entité est liée à une table, via l'ORM, il y a en général un fichier "repository" associé. Un repository permet la génération de requêtes simples ou complexes et dont le développeur peut modifier à volonté.
Un ORM (Object Relation Mapper) permet de gérer manipuler et de récupérer des tables de données de la même façon qu'un objet quelconque, donc en gardant le langage PHP. Plus besoin de requête MySQL, PostgresSQL ou autre.
Symfony utilise Doctrine comme ORM dans son système par défaut. Nous allons utiliser Doctrine mais vous pouvez utiliser d'autres systèmes si vous le souhaitez. Doctrine peut-être géré de plusieurs façon : XML, JSON, YAML, PHP et en Annotation nous allons utiliser ce dernier format de données.
Vous êtes libre d'écrire le code qui permet le traitement métiers en dehors des entités et d'avoir votre propre logique d'organisation.
Comme à chaque fois, il est d'abord nécessaire d'installer les bundles nécessaires pour manipuler la base de données avec un ORM. Il vous faut donc exécuter la commande ci_dessous :
On va également installer, si vous ne l'avez pas encore fait, le bundle "maker" qui contient des outils pour générer du code sous Symfony grâce à la console.
Une fois ces deux éléments installés, il faut configurer la connexion à la base de données. Pour ce faire, il faut éditer le fichier .env
à la racine de votre projet, qui doit normalement contenir une ligne d'exemple.
Une fois le fichier à jour avec vos données, vous pouvez créer votre base de données depuis la console.
Les modifications de structure de votre base de données devront être réalisées avec la console pour que Symfony puisse faire le lien entre les tables et l'ORM.
Utilisez la commande make:entity
(qui est dans le bundle maker) pour avoir une série de question vous permettant de créer votre entité avec l'utilisation de l'ORM Doctrine. Vous pouvez créer une nouvelle entité ou modifier (ajouter des champs) une entité déjà existante en saisissant son nom.
Vous allez devoir répondre à une suite de question avec le nom de l'entité (par défaut cela donnera le nom de la table), et les champs à créer. Dans Symfony une entité possède toujours un champs id, qui est la clé primaire et qui est auto-incrémenté. Vous ne devez donc pas l'ajouter dans la console.
Pour la création d'un champs, il vous faudra donner :
son type
sa taille le cas échéant
si ce champs peut être null
s'il doit être unique (index)
Vous pouvez obtenir la liste des types supportés en tapant "?" à la question du type.
Une fois terminé, le fichier d'Entité et le repository associé sont générés.
Exemple dans la console :
Et le code de l'entité généré dans src/Entity/Product.php
:
A ce stade l'entité est créé, mais n'existe pas dans la base de données. Il reste deux étapes à exécuter.
Sans générer de fichier de migration (qui contient toutes les instructions SQL à exécuter sur la base de données, notamment pour le déploiement d'une mise à jour)
La création d'un fichier de migration qui va contenir le code SQL a exécuter en fonction de votre SGBD.
La mise à jour de votre base de données en fonction du fichier précédemment généré.
Si vous consultez votre PHPMyAdmin vous verrez la table apparaître.
Pour modifier des champs vous pouvez éditer directement le code généré dans la partie annotation: nom (par défaut le nom de la variable), taille, type.
Pour ajouter des champs il vous faut relancer la commande make:entity
en remettant le nom de votre entité.
Après chaque modification ou ajout il faut de nouveau générer le fichier de migration et mettre à jour la base de données. Vous pouvez bien sûr modifier ou créer plusieurs entités avant de faire une mise à jour de votre base de données.
Une fois la base de données mise en place on va pouvoir insérer, modifier, supprimer et récupérer des informations de la base de données sans saisir de requêtes via des méthodes en initialisant l'entité fraichement créée :
Il existe à la place de $em->persist, $em->remove($post);
qui permettra de faire une suppression.
Configurer votre base de données (dupliquer le .env
en .env.local
et modifier les informations dans le .env.local
)
Si vous utilisez l'image docker MMI, la ligne devrait être
Créer la base de données (bin/console doctrine:database:create
)
Créer une entité (bin/console make:entity
), nommée Post et ajoute les champs suivants
titre, string de 150 caractères
message, text
datePublication, DateTime
L'id sera automatiquement ajouté
Créer un nouveau contrôleur nommé "Post"
Ajouter une route pour créer un nouvel enregistrement
Créer un objet Post et compléter les informations (titre, message, datePublication)
Récupérer la connexion à doctrine (EntityManagerInterface $entityManager
) (ne pas oublier le use associé)
Associer l'instance de Post avec l'ORM ($entityManager->persist($post))
Enregistrer dans la base de données ($entityManager->flush()
)
Appeler la route et vérifier que cela s'enregistre dans votre base de données
Essayer d'appeler la route plusieurs fois.
Symfony et Doctrine proposes des requêtes prédéfinies, qui répondent aux usages les plus courant.
Si $em
est le manager associé à une entité :
$em->find($id);
on récupère qu'un seul élément de l'entité avec l'id $id
;
$em->findAll();
on récupère toutes les entrées de l'entité concernée
$em->findBy($where, $order, $limit, $offset);
on recherche avec le tableau $where
on tri avec le tableau $order
on récupère $limit
éléments à partir de l'élément $offset
.
$em->findOneBy($where, $order);
on récupère le premier élément respectant le tableau $where
et trié avec le tableau $order
;
$em->findByX($search);
requêtes magiques où X correspond à n'importe quel champs défini dans votre entité
$em->findOneByX($search)
; requêtes magiques où X correspond à n'importe quel champs défini dans votre entité
Par exemple findBySlug('home')
; ou findByTitle('Bonjour);
génèrera des requêtes de recherche automatiquement. Pour les requêtes avec plusieurs éléments il faudra faire une itération (foreach) ou lister les différents éléments.
Exemple
Si aucune requête prédéfinie ne correspond à vos besoin, vous pouvez bien sûr en créer une en passant par le repository.
Vous pouvez également générer vos requêtes manuellement pour avoir une requête complexe et précise directement dans le controller mais idéalement il faudrait le placer dans le repository dédié.
Et l'utiliser dans votre controller
Ce dernier code effectue une création dans la base de données; pour une modification il suffit de modifier l'instanciation de l'entité de la sorte :
ici on récupère le repository de Post et on récupère l'id 1 ; tout le restant du code reste inchangé.
Créer une entité "PostCategory" avec :
title string 255
Créer une page qui va sauvegarder une catégorie avec le nom "Catégorie 1".
Créer une page qui va sauvegarder un post avec le nom Post 1 à la date courante avec comme message Lorem ipsum.
Créer une page qui va afficher le titre de la catégorie en id 1 et le post en id 1.
Créer un nouveau post identique au premier en changeant le titre.
Créer une page qui affiche la totalité des entités Post.
Créer une page qui récupère le Post avec le Titre "Post 1"
Un template ou une vue est le meilleur moyen d'organiser et de restituer le code HTML à partir de votre application, que vous deviez rendre le code HTML à partir d'un contrôleur ou générer le contenu d'un courrier électronique . Les templates dans Symfony sont créés avec Twig: un moteur de modèle flexible, rapide et sécurisé.
est un moteur de rendu de template comme (prestashop) ou (laravel). Twig a cependant été développé pour Symfony à l'origine et peut être utilisé dans d'autres contextes.
Un moteur de template permet de limiter les logiques complexes pour réaliser des templates simples à coder. Un moteur de template intègre généralement des fonctionnalités qui sont récurrentes dans le développement "front" et qui permettent de simplifier le code à écrire.
et
Exemple d'un code que vous pourriez écrire en PHP
Ce même code, écrit avec TWIG serait :
La syntaxe est plus "legére" et moins encombrées des balises PHP. Le code semble donc plus lisible et par conséquent plus facile à maintenir.
La syntaxe Twig est basée sur uniquement trois constructions:
{{ ... }}
, utilisé pour afficher le contenu d'une variable ou le résultat de l'évaluation d'une expression;
{% ... %}
, utilisé pour exécuter une logique, telle qu’une condition ou une boucle;
{# ... #}
, utilisé pour ajouter des commentaires au modèle (contrairement aux commentaires HTML, ces commentaires ne sont pas inclus dans la page rendue).
Vous ne pouvez pas exécuter de code PHP dans les modèles Twig, mais Twig fournit des utilitaires permettant d'exécuter une certaine logique dans les modèles. Par exemple, les filtres modifient le contenu avant le rendu, comme le upper
filtre pour mettre le contenu en majuscule :
{{ title|upper }}
TWIG est très puissant lorsqu'il s'agit de manipuler des variables. Pour lui, si c'est un tableau associatif ou un objet avec des propriétés cela est identique dans la syntaxe.
Par exemple si vous avez le tableau $tab['param1']
vous écrirez en TWIG
Si vous avez un objet $tab
, qui est une instance d'une classe ayant comme propriété $param1
, la syntaxe en TWIG sera :
Si vous avez un objet $tab
, qui est une instance d'une classe ayant comme propriété $param1
, qui est un tableau associatif avec une clé key1
, la syntaxe pourrait être :
La manière dont TWIG inspecte votre code pour trouver la meilleure façon d'interpréter une variable est la suivante :
For convenience's sake foo.bar
does the following things on the PHP layer:
check if foo is an array and bar a valid element;
if not, and if foo is an object, check that bar is a valid property;
if not, and if foo is an object, check that bar is a valid method (even if bar is the constructor - use __construct() instead);
if not, and if foo is an object, check that getBar is a valid method;
if not, and if foo is an object, check that isBar is a valid method;
if not, and if foo is an object, check that hasBar is a valid method;
if not, return a null value.
foo['bar'] on the other hand only works with PHP arrays:
check if foo is an array and bar a valid element;
if not, return a null value.
{% %}
permet d'utiliser des logiques tels que :
{% if %} {% else %} {%endif %}
: condition
{% for item in items %}{%endfor}
: foreach
{% set foo='foo' %}
: set des variables
Il est possible d'écrire des tests, la syntaxe est très proche de celle de PHP. Attention toutefois, les opérateurs de comparaison ne s'écrive pas de manière identique.
Le && de PHP s'écrit "and" dans TWIG, et le || de PHP s'écrit "or" dans TWIG.
Il est possible d'avoir des elseif (autant que nécessaire) et un bloc else (1 au maximum)
Il n'existe que la boucle for dans TWIG (elle est un peu l'équivalent d'un foreach).
Le code ci-dessous est une boucle qui varie de 1 à 10.
La boucle ci-dessous est une boucle qui parcours une "collection" users (l'équivalent du foreach). Attention la syntaxe est inversée par rapport au PHP
Dans le cadre d'une boucle TWIG propose une variable nommée loop qui permet d'avoir des informations sur la boucle :
La boucle ci-dessous intègre un test. Ce qui simplifie l'écriture. Elle intègre également un else dans le cas ou la boucle ne ferait aucune itération. Il est possible d'utiliser le else sans le if et réciproquement.
Le code ci-dessus serait équivalent en PHP au code suivant:
TWIG permet l'héritage de template via un extends
dans les templates enfants :
Dans les templates mère on définit des "block" que l'on vient surcharger dans les templates enfants :
On peut également reprendre le block parent via
On crée donc des templates mère assez flexibles pour pouvoir en hériter et surcharger les différents blocks
Utiliser l'héritage pour mettre le menu dans un seul fichier mais visible sur les 2 pages.
Intégrer bootstrap (CDN)
Pour la page /color afficher le mot de la même couleur dynamiquement ("bleu" en bleu) (en CSS)
Pour la couleur rouge afficher en plus le Message : "Attention risque de virus" en rouge
De la même manière que l'on peut hériter d'un template de base, on peut aussi inclure des "morceaux" de template dans une vue. Toujours dans la perspective de ne jamais multiplier un morceau de code identique dans plusieurs fichiers.
Il est possible d'appliquer des filtres sur les variables pour effectuer des transformations : Majuscules, minuscules, dates, ...
Il est possible de cumuler les filtres. Mais il faut faire attention à l'ordre dans lequel on les appliques. Il est aussi possible de créer ses propres filtres.
TWIG propose de gérer facilement les URL de vos images, fichiers CSS ou encore javascript.
Pour cela vous aurez besoin d'ajouter le bundle suivant :
Ensuite, vous pouvez écrire dans TWIG
Par défaut, vos "assets" doivent se trouver dans le répertoire public de Symfony.
Modifiez le code précédemment écrit pour manipuler des assets directement dans votre projet. Vous intégrer une image de votre choix et Bootstrap en version locale (supprimer toutes les dépendances aux CDN).
Une route permet de diriger une url (ou un pattern d'url) vers une méthode de controller appelée Action.
et
Il est possible de décrire des routes selon les formats de fichiers : XML, Classe PHP, en annotation ou avec les Attributes (php8 et +). Pour plus de commodité nous utiliserons les Attributes.
Une route peut être constante : /blog
ou dynamique : /blog/{slug}
. Ici slug englobé de { } devient une variable dynamique qui prend tous les caractères alphanumériques par exemple : /blog/42
, /blog/lorem-ipsum
, /blog/titi-32\_tata
Ces 3 urls correspondent à la méthode ciblée par la route avec une variable slug
différente. Cette variable peut être récupérée par le controller.
Une route est au minimum un chemin (path) et un nom;
Ces variables peuvent être mises par défaut grâce à "defaults"
Ces variables peuvent être soumises à une validation de format via "requirements"
On peut définir un path différent en fonction de la locale
Vous pouvez cumuler plusieurs routes pour une méthode Action
On peut spécifier le moyen d'accès à une route (GET, POST, PUT, ...), avec le paramètre "methods"
Pour pouvoir utiliser les Attributes il faut :
à ajouter après le namespace dans votre Controller.
On définit une variable d'url via des accolades {ma_variable} :
Pour récupérer la variable dans le controller, il suffit de déclarer une variable dans la méthode avec le même nom que la variable d'url.
Pour définir une valeur par défaut, on peut préciser la valeur sur le paramêtre de la méthode :
Si l'utilisateur utilise l'URL /page/
, la variable $page
sera égale à 1.
On peut cumuler plusieurs variables :
On pourrait utiliser un autre séparation que le slash, comme par exemple -, . ou _. La seule condition étant que Symfony puisse être en mesure de différencier les paramètres.
Pour générer une url en PHP on utilise :
Ou sous TWIG on a deux fonctions :
Les routes redirigent vers une méthode de Controller (une action); un controller Symfony se nomme de la sorte : NomDuController où le suffixe Controller est obligatoire et le nom du fichier et de la classe est en CamelCase.
Les différentes méthodes se nomment de la sorte :
nomDeLaMethode est lui en miniCamelCase
L'usage du suffixe Action n'est plus requis dans Symfony.
Dans le cas idéal, le controller doit contenir le minimum de code possible (20 lignes maximum selon les standards de Symfony). Il ne doit que faire le lien entre les différents éléments de l'application et une réponse.
Une Action renvoie toujours un type Response ; il existe plusieurs type de Response : JsonResponse, RedirectResponse, HttpResponse, BinaryFileResponse etc ...
La plus utilisée est Response pour l'utiliser on va ajouter dans le "use" suivant :
et dans la méthode action on :
Affiche à l'écran Ma response. Dans l'état cette réponse n'est pas du HTML, car rien n'est précisé dans le retour de la méthode.
Une méthode render() (définie quand la classe AbstractController dont votre controller doit hériter) permet aux Actions de récupérer une vue et d'afficher le contenu de la vue compilée avec les différentes variables envoyées.
Ici on va récupérer le template présent dans templates/default/index.html.twig pour affecter la variable variable.
Créer 2 nouvelles pages :
Ajouter un menu avec des liens vers les 2 pages créées.
L'objet "request" contient toutes les données envoyées par l'utilisateur (formulaire, ...), mais aussi les données envoyées par le navigateur.
En passant en paramètre un objet de type Request, on peut le manipuler selon les méthodes ci-dessous.
Passer un objet en paramètre de cette manière est ce que l'on nomme de l'injection de dépendance. Le lien est fait automatiquement par Symfony grâce au mécanisme d'autowiring.
Symfony propose des exemples pour de nombreuses méthodes d'authentification (login, ldap, json, ...) que vous
De cette manière les URL seront automatiquement bloquées si l'utilisateur ne dispose pas du bon rôle. Il est aussi possible de tester ce rôle directement dans un contrôleur ou dans une vue selon les besoins.
Pour vous connecter , puis vos identifiants.
Twig intègre une permettant de répondre aux usages courant. Mais il est très simple d'ajouter nos propres filtres afin de répondre parfaitement à nos besoins.
Vous trouverez la liste des filtres sur l'adresse :
Depuis la version 3.4 et 4, Symfony propose de gérer les assets avec WebPack-Encore, qui est une adaptation de Webpack pour Symfony Vous trouverez les éléments sur WebPack-Encore ici :
: afficher la date l'heure minute et seconde
: affiche "blue" à l'écran dynamiquement
: affiche "red" à l'écran dynamiquement
Variable | Description |
loop.index | The current iteration of the loop. (1 indexed) |
loop.index0 | The current iteration of the loop. (0 indexed) |
loop.revindex | The number of iterations from the end of the loop (1 indexed) |
loop.revindex0 | The number of iterations from the end of the loop (0 indexed) |
loop.first | True if first iteration |
loop.last | True if last iteration |
loop.length | The number of items in the sequence |
loop.parent | The parent context |
Symfony dispose d'une large communauté très active qui contribue à développer des "bundles" afin de venir enrichir le framework avec des fonctionnalités récurrentes : Back office, gestion d'upload, ...
Il existe un site regroupant les bundles https://flex.symfony.com/ (ou pour les versions précédentes de Symfony http://knpbundles.com/).
Parmis quelques bundles intéressants on peut citer :
EasyAdminBundle (bundle reconnu par Symfony pour la génération automatique de backoffice)
SonataAdminBundle
StofDoctrineExtensionsBundle, qui permet d'enrichir Doctrine (gestion de date created/updated, de traduction, d'upload, ...)
KnpSnappyBundle, pour la génération de PDF à partir de WKHtmlToPdf
et beaucoup d'autres pour la sérialization, l'authentification, la génération de pagination, ...
Avec Symfony 4 l'installation d'un Bundle est devenue très simple (notamment si le bundle dispose d'une recette recipe pour l'utilsisation optimale de flex).
Liste des recipes officielles pour Flex et Symfony https://github.com/symfony/recipes, et le dépôt des recipes "non-officielles" https://github.com/symfony/recipes-contrib
Il suffit, en général, d'installer le bundle avec Composer pour que ce dernier installe et configure les éléments.
Ce bundle permet la gestion de l'upload en lien avec Doctrine.
That's a tough question but thankfully, our team is on it. Please bear with us while we're investigating.
Yes, after a few months we finally found the answer. Sadly, Mike is on vacations right now so I'm afraid we are not able to provide the answer at this point.
Mettre en production un projet réalisé avec Symfony
La mise en production d'un projet avec Symfony est simple, mais implique de suivre les différentes étapes.
Pour effectuer une mise en ligne de votre projet avec un logiciel FTP, il faut télécharger sur le serveur les fichiers ou répertoires suivants.
Pour une mise à jour d'un produit existant, l'upload de src/
et templates/
peut suffire, selon ce que vous avez modifié sur votre projet.
Il vous faut ensuite exécuter les différentes opérations de mise en ligne de la partie Mise en production
Pour une première mise en ligne vous pouvez faire un clone de votre dépôt.
Cette commande va créer un nouveau répertoire et copier les fichiers de votre dépôt sur votre serveur.
Il vous faut ensuite exécuter les différentes opérations de mise en ligne de la partie Mise en production
Pour mettre à jour un projet déjà existant sur votre serveur, et géré avec Git, vous devez executer la commande suivante
Où master est la branche qui contient la version de votre projet que vous souhaitez installer.
Il vous faut ensuite exécuter les différentes opérations de mise en ligne de la partie Mise en production
Symfony propose une gestion poussée des environnements, et vous pourriez avoir plusieurs fichiers en fonction du contexte : https://symfony.com/doc/current/configuration.html#configuration-environments
Si vous n'avez qu'un fichier .env
, vous devez le mettre à jour avec les informations de votre serveur de production (base de données, éventuellement serveur de mail, ...).
C'est également dans ce fichier d'environnement que vous devez définir que votre projet est en production et plus en développement :
En production Symfony utilise un système de cache, n'affiche plus le profiler ou les messages d'erreur, mais utilise les pages 404, 500 que vous avez définies.
Les erreurs peuvent être sauvegardées dans des fichiers de log, selon votre configuration.
Toutes les configuration se trouvant dans config/packages/dev
sont ignorées et celles se trouvant dans config/packages/prod
sont utilisées.
Le répertoire vendor n'est jamais installé ou téléchargé, quelque soit la méthode que vous utilisez. Il faut donc soit le créer (une première installation), soit le mettre à jour (si vous avez ajouté des bundles ou que vous souhaitez obtenir la dernière version des bundles que vous utilisez)
L'information "--no-dev" permet de ne pas installer les bundles qui ne servent qu'en développement (make, profiler, ...). Si vous souhaitez être en développement sur ce serveur, vous devez retirer cette instruction.
En production Syfmony utilise un système de cache très performant. Mais cela peut empêcher de voir vos dernières modifications. Il faut donc s'assurer de nettoyer le cache de Symfony.
La commande suivante permet de supprimer le cache :
Si vous avez ajouté des éléments dans vos entités, vous devez mettre à jour votre base de données. Pour cela vous pouvez executer la commande suivante :
Symfony comes packed with a lot of useful objects, called services. These are used for rendering templates, sending emails, querying the database and any other "work" you can think of.
If you need a service in a controller, type-hint an argument with its class (or interface) name. Symfony will automatically pass you the service you need:
1 2 3 4 5 6 7 8 9 10 11
Awesome!
Symfony nécessite tout un environnement pour fonctionner. Symfony implique aussi différents "langages" et utilise un vocabulaire spécifique (souvent repris dans d'autres frameworks).
Composer est un logiciel gestionnaire de dépendances libre écrit en PHP. Il permet à ses utilisateurs de déclarer et d'installer les bibliothèques dont le projet principal a besoin. Développé, depuis 2011, par Nils Adermann et Jordi Boggiano (qui continuent encore aujourd'hui à le maintenir), il est aujourd'hui en version 2.
Le logiciel Composer trouve son équivalent pour le front avec npm ou Yarn
Une entité est une classe PHP ! Elle peut faire le lien avec une base de données, on y déclare les différentes propriétés accessibles; Symfony utilise par défaut un outil de persistence de données : Doctrine pour lier une entité à une table de base de données.
Système permettant de se libérer des requêtes pour la base de données. Il se charge de générer les requêtes à effectuer sur les Entités spécifiées. Il existe plusieurs ORM, dans Symfony, il s'agit de Doctrine.
Classe PHP qui fait le pont entre une entité et l'ORM, il permet notamment de structurer des requêtes complexes.
Format de structuration de données très utilisé dans Symfony, mais on peut utiliser du XML, du PHP ou encore les annotations (PHP 7) ou les attributs (php 8), les fichiers de configurations par défaut sont en YAML.
Commentaire PHP directement dans les classes utiles (controller, entité, ...) interprété par Symfony pour générer des fichiers de configuration ;
Les Attributes sont la nouvelle version des annotations, intégrés nativement dans les versions 8 et supérieures de PHP. Les Attributes sont une forme de données structurées, qui permet d'ajouter des métadonnées à nos déclarations de classes, propriétés, méthodes, fonctions, paramètres et constantes. Ils vont nous permettre de définir de la configuration au plus près du code, directement sur nos déclarations.
Les routes permettent de faire un lien entre une URL et un contrôleur.
Sorte de modules Symfony qui peuvent contenir tout et n'importe quoi ; C'est la force de Symfony les modules peuvent fonctionner indépendamment et même sur d'autres structures PHP, autre framework etc.
Symfony propose par défaut 2 environnements : dev et prod qui permettent de donner des configs différentes en fonction de l'environnement de travail ;
dev permet une utilisation sans cache avec des outils de dev comme le profiler ;
prod lui permet d'utiliser le site avec le cache et sans aucun message d'erreurs.
De plus on peut configurer les différents environnements pour par exemple rediriger tous les mails vers toto@titi.com en dev et laisser le fonctionnement normal pour prod ; pratique pour les debugs.
Symfony propose également de définir autant d'environnement que nécessaire afin d'avoir différentes configurations. Le changement d'un environnement à un autre se faire en modifiant la ligne suivante dans le fichier ".env" (ou .env.local) :
Le profiler est un outil puissant (et indispensable) pour débuger une application. Par défaut le profiler n'est pas installé. Pour l'ajouter il faut exécuter la commande suivante :
Le profiler est toujours visible en bas de la page en mode développement.
Le maker est un outil puissant pour générer du code, et des éléments dans notre projet. Par défaut le maker n'est pas installé. Pour l'ajouter il faut exécuter la commande suivante :
Il est assez facile de modifier le maker pour que le code généré corresponde exactement à notre projet et nos attentes.
Un moteur de template est un "langage", un "outil" permettant d'écrire les vues (partie visible) de manière efficace et rapide. Symfony utilise Twig par défaut.
Il est fréquent que les entités soient liées entre-elles. Et nous avons la notion de clé étrangère qui peut apparaître dans nos tables. Il est possible (voire nécessaire) de gérer cela avec Doctrine.
Pour ce faire, il va falloir expliquer à Doctrine, les liens qui existent entre nos entités. Et Doctrine, se chargera de créer les clés étrangères où cela est nécessaire.
La documentation officielle de Symfony sur les relations/associations
Il existe les relations suivantes dans doctrine :
OneToMany (et son inverse ManyToOne)
ManyToMany
OneToOne
Il existe également une notion très importante dans ces relations : propriétaire et inverse.
Dans une relation entre deux entités, il y a toujours une entité dite propriétaire, et une dite inverse. L'entité propriétaire est celle qui contient la référence à l'autre entité.
Prenons un exemple simple, les commentaires de nos annonces. En SQL pur, vous disposez de la tablecomment et de la tableadvert. Pour créer une relation entre ces deux tables, vous allez mettre naturellement une colonne advert_id dans la tablecomment. La tablecomment est donc propriétaire de la relation, car c'est elle qui contient la colonne de liaison advert_id.
Enfin, une relation peut être unidirectionnelle ou bidirectionnelle. Les relations bidirectionnelles peuvent être gérées automatiquement par Symfony modifiant un peu les entités inverses avec inversedBy et mappedBy.
Dans le cas d'une relation bidirectionnelle, il faut aussi explicité la relation dans l'entité inverse. La relation bidirectionnelle permet de faciliter la recherche d'élement en partant de l'inverse (Article vers Commentaires).
La relation 1..n définit une dépendance multiple entre 2 entités de sorte que la première peut être liée à plusieurs entités
Prenons l'exemple des étudiants et des absences. Un étudiant peut avoir plusieurs (many) absences, mais une absence n'est associée qu'a un (one) seul étudiant.
Cette relation peut donc se résumer à : plusieurs (many) absences pour un (one) étudiant, ou de manière équivalent un (one) étudiant pour plusieurs (many) absences.
On se place prioritairement du coté du Many, et on doit écrire la relation ManyToOne. Elle est obligatoire pour définir la relation précédente.
Le code précédent est le minimum pour définir une relation.
On dit dans ce cas que Absence est propriétaire de la relation (toujours du coté du Many).
La relation décrite précédemment est unidirectionnelle. Pour la rendre bidirectionnelle il faut décrire la relation dans l'entité etudiant (avec la relation inverse OneToMany).
Le code de Absence devient
Le code de Etudiant sera :
La relation OneToMany n'est pas obligatoire. Elle permet juste d'inverser la relation, et de rendre la manipulation plus simple.
Dans ce cas, on fait apparaître un tableau ($this->absences
), de type ArrayCollection
contenant tous les objets associés à cette relation (many).
La relation 1..1 est peu utilisée mais permet une flexibilité en terme relationnelle très importante. Elle définit une dépendance unique entre 2 entités :
Utilisateur -> Adresse Produit -> Image Commande -> Facture
Le fonctionnement est assez similaire à une relation ManyToOne/OneToMany, sauf que cette relation est forcément bidirectionnelle. Il faut décrire le comportement dans les deux entités et choisir, selon la logique désirée, qui sera la relation propriétaire (inversedBy) de la relation inverse (mappedBy).
Cette relation va créer une nouvelle table, contenant les deux clés étrangères.
La console (make:entity
), nous facilite la création des relations. En créant ou en modifiant l'entité, il est possible d'ajouter le champs contenant la relation. Pour cela le type sera "relation". La console vous demandera de préciser l'entité liée, ainsi que le type de relation. Vous pourrez ensuite selon la relation choisie, préciser la relation inverse, de manière optionnelle ou obligatoire.
Attention, il est d'usage de lancer la console dans l'entité qui porte la relation (propriétaire), ou l'entité qui recevra la clé étrangère.
Comme après chaque modification, il faudra générer le fichier de migration, et appliquer les modifications sur la base de données.
Créer la liaison entre Post et PostCatégorie.
Modifier la page de génération de Post pour créer un nouveau post avec la relation vers "Catégorie 1"
La catégorie de ce post sera Catégorie 1 (s'il existe, sinon le créer, cf. séance précédente)
Modifier la page avec tous les posts pour afficher la catégorie liée à l'article.
Afficher la catégorie 1 avec tous les posts qui lui sont associés
Créer une route qui supprime "Post 1"
Créer une route qui supprime "Catégorie 1"
En plus : Flash Messages https://symfony.com/doc/current/controller.html#flash-messages
Essayer d'utiliser les flash messages.
La gestion des formulaire se fait via plusieurs classes PHP qui permettent entre autre :
La structure et les propriétés du formulaire se gèrent via FormBuilder et peuvent être réutilisées;
On peut créer des classes spécifiques pour chacun de nos formulaires
Permet une gestion des validations simplifiée et une sécurité renforcée
Permet d'hydrater une entité ou un objet rapidement
Gestion de template simple
La documentation officielle de Symfony sur les formulaires se trouve ici
Pour pouvoir utiliser les formulaires, selon la version d'installation de Symfony, il peut être nécessaire d'installer les packages :
Pour les exemples ci-dessous, on considère l'entité suivante (exemple issue de la documentation Symfony) :
On peut créer un Form de 2 façons différentes :
Cette première solution est rapide à mettre en place, et ne nécessite pas de fichier supplémentaire. Cependant, le formulaire ainsi créé n'est pas réutilisation dans d'autres méthodes.
Cette seconde solution, qui implique des fichiers complémentaires, permet une plus grande souplesse et une meilleure ré-utilisation dans d'autres contextes.
Le fichier ci-dessous permet de créer le même formulaire.
On utilise la classe FormBuilder accessible avec la méthode
dans un contrôleur ; l'argument $task
est l'entité que vous souhaitez hydrater; l'argument n'est pas obligatoire (pour un formulaire de recherche par exemple)
On peut mettre des champs de formulaire par défaut en modifiant l'entité avant de créer le formulaire et de lier le formulaire à l'entité :
Par exemple
Pré-remplira le formulaire avec Ma tâche pré-définie.
Ensuite nous aurons des suites de ->add('nom_du_champs', TypeDeChamps::class, $options);
Par défaut si vous ne mettez que le nom du champs Symfony se chargera de récupérer un type de champs en fonction du type de champs (string, text, boolean, date, ...)
Liste des champs possibles : https://symfony.com/doc/current/reference/forms/types.html
Dans une classe dédiée le createFormBuilder
est déjà instancié il ne vous reste qu'à rajouter les différents add
.
Une fois le formulaire créé et initié il faut renvoyer le tout à TWIG via la méthode :
Soit par exemple
Ensuite nous aurons plusieurs fonctions twig utiles:
{{ form }}
permet d'afficher tout le formulaire
{{ form_start }}
permet de générer la balise <form>
avec les différents attributs
{{ form_end }}
permet de générer la fermeture de <form>
avec les différents champs restants non affichés
{{ form_errors }}
affiche les erreurs éventuelles du formulaire
{{ form_widget(mon formulaire.nomduchamps) }}
affiche le type de champs
{{ form_label(mon formulaire.nomduchamps) }}
affiche le label du champs
{{ form_row(monformulaire.nomduchamps) }}
affiche le form_widget et form_label
{{ form_rest }}
affiche les champs restants non récupéré précédemment (token de vérification par exemple)
Ces fonctions permettent une grande maîtrise de la mise en forme d'un formulaire. Cependant, elle implique de détailler les éléments.
Il est donc possible d'afficher un formulaire en une seule ligne, et le rendu dépendra du paramètrage (ou du template modèle) existant.
la variable_form
correspond à la variable contenant le formulaire envoyée par le contrôleur. Il est enfin possible de préciser un "thème" pour votre formulaire avec la syntaxe :
Le template est un fichier twig qui vient préciser et définir pour chaque élément du formulaire (de manière globale), le rendu en HTML.
Des thèmes par défaut sont proposées : https://symfony.com/doc/current/form/bootstrap4.html Et la documentation pour créer votre template : https://symfony.com/doc/current/form/form_customization.html
Une fois le formulaire créé et affiche via TWIG il faut rajouter un comportement qui va gérer la soumission du formulaire grâce à ces méthodes :
handleRequest($request)
permet d'associer les valeurs input à la classe Form précédemment créé
isSubmitted()
permet de savoir si le formulaire a été envoyé
isValid()
permet de savoir si les données saisies sont valides
Dans la majorité des cas on va tester si :
Les validations permettent de gérer des contraintes au niveau du formulaire ; Par exemple pour pourra forcer en PHP que le champs email soit bien un email ou que tel champs ne peut pas dépasser tel nombre de caractères, vous trouverez la liste des contraintes basiques sur site site de symfony : http://symfony.com/doc/4.1/validation.html
Ces contraintes ou assert peuvent être gérée de plusieurs façon XML, JSON, YAML, PHP ou en annotation dans notre cas; il faudra utiliser cette ligne tout en haut du contrôleur :
Pour ensuite pouvoir utiliser l'annotation :
Ici on vérifiera que le champs name doit être rempli.
Créer un formulaire directement dans DefaultController qui gèrera la création des Post
Créer un formulaire directement dans DefaultController qui gèrera la modification des Post
Modifier la page de listing des postes pour rajouter un lien edition et suppression
Mettre en place les différentes routes pour le backoffice de Post (ajout / modification / suppression / visualisation)
Déporter le formulaire de gestion de Post vers une classe dédiée Form/PostType.php
Modifier DefaultController pour utiliser PostType
Ajouter une validation au formulaire sur le titre qui ne doit pas dépasser 255 caractères
Rechercher pour mettre en place le template bootstrap pour les Form
Afficher le message d'erreur en rouge.
Ce que nous venons de faire manuellement peut être généré en ligne de commande par Symfony via la commande :
On vous demandera le nom de l'entité précédé du nom de bundle, le chemin pour ce crud et si vous souhaitez avoir les fonction d'édition (ajout/ modification) mettez oui.
On peut également générer seulement les FormType :
Attention si vous modifier une entité les FormType ne sont pas générés automatiquement il faudra rajouter manuellement le champs fraichement créé.