Symfony 6
Développez des sites web PHP structurés et performants
Etienne Langlet
Chapitre 1
Introduction
1. Avant-propos23
2. Public visé24
3. Prérequis24
4. Objectifs du livre25
5. Le développement avec les frameworks26
5.1 Complexité des développements et productivité26
5.1.1 Productivité et qualité logicielle26
5.1.2 Intégration et livraison continues27
5.2 Particularité des développements en PHP27
5.2.1 Contexte historique de PHP27
5.2.2 Évolutions28
5.3 L'apport des frameworks28
5.3.1 Éviter les problèmes techniques liés à l'organisation du code29
5.3.2 Définir des responsabilités29
5.3.3 Ne pas réinventer la roue30
5.3.4 Utiliser des modèles de conception éprouvés30
6. Symfony31
6.1 Historique31
6.2 Gouvernance et gestion des versions32
6.2.1 Les versions32
6.2.2 Le cycle de « release »33
6.3 Choisir sa version pour un projet35
Chapitre 2
Mise en place d'un projet Symfony
1. L'outillage nécessaire37
1.1 Introduction37
1.2 Symfony : Un projet PHP38
1.2.1 Préconisation d'installation38
1.2.2 Installation sous Linux39
1.2.3 Installation sous Windows41
1.3 Symfony CLI42
1.4 Composer43
1.4.1 Installer Composer43
1.5 Les environnements de développement pour Symfony47
1.5.1 Un IDE pour Symfony !48
1.5.2 PhpStorm48
1.5.3 Visual Studio Code51
1.5.4 Conclusion53
2. Création d'un projet Symfony54
2.1 Prérequis54
2.2 Création via l'installeur Symfony54
2.3 Création via Composer55
2.4 Configurer son serveur web57
2.4.1 Serveur web PHP57
2.4.2 Apache et Nginx58
3. Structure de l'application62
3.1 Arborescence du projet62
3.2 Règles et conventions d'organisation du projet63
3.2.1 Le standard PSR-463
3.2.2 Conventions de nommage64
3.3 La configuration d'une application Symfony66
3.3.1 Les annotations67
3.3.2 Le format YAML69
3.3.3 Le format XML69
3.3.4 Le format PHP70
3.3.5 Les attributs PHP 870
3.3.6 Choisir son format de configuration71
Chapitre 3
Architecture du framework
1. Le modèle de conception MVC73
1.1 Définitions et responsabilités73
1.1.1 La vue74
1.1.2 Le modèle74
1.1.3 Le contrôleur74
1.2 En pratique75
1.2.1 Le contrôleur frontal76
1.2.2 Le routage76
1.2.3 Le contrôleur et le modèle76
1.2.4 La vue77
1.2.5 En synthèse78
2. Architecture de Symfony78
2.1 Présentation78
2.2 Le contrôleur frontal79
2.3 Le Service Container80
2.4 Le modèle MVC dans Symfony80
2.5 L'approche par composant81
3. Symfony Flex82
3.1 Présentation82
3.2 Fonctionnement de Symfony Flex83
3.3 Les recettes Symfony84
4. Les environnements85
4.1 Principe et apports85
4.2 Les fichiers de configuration85
4.3 Dans le contexte HTTP86
4.4 Dans le contexte CLI (Command Line Interface)86
5. Le chargement automatique de classes87
5.1 Le standard PSR-487
5.2 Mécanismes alternatifs88
5.3 Application aux applications Symfony88
6. La console89
6.1 Présentation89
6.2 Les commandes90
6.2.1 Lister les commandes disponibles90
6.2.2 Exécuter une commande90
6.3 Les options90
6.4 Les arguments91
6.5 L'aide sur les commandes92
6.6 Exécuter rapidement des commandes93
7. Les outils pour le débogage94
7.1 Le profiler Symfony94
7.2 La fonction dump ()96
Chapitre 4
Routage et contrôleur
1. Fonctionnement du routage dans Symfony99
1.1 Définition99
1.2 Le répertoire public et le contrôleur frontal100
1.3 Une requête, une action100
2. Définition des routes101
2.1 Les différents formats de définition101
2.2 Les options sur la définition des routes103
3. Configurer le path104
3.1 Illustration par l'exemple : /hello/world104
3.2 La notation du contrôleur108
3.3 Importer des routes depuis d'autres fichiers108
3.4 Comprendre l'ordre de chargement des routes109
3.5 Préfixer les routes110
3.6 Les paramètres de substitution des routes112
3.7 Les restrictions sur les paramètres114
3.8 Obtenir des informations sur le routage116
4. Routage par nom de domaine117
4.1 Prérequis117
4.2 Exemple de mise en oeuvre118
4.3 Explications121
5. Le contrôleur122
5.1 Modèle de programmation et règles122
5.2 Travailler avec les services122
5.3 Utiliser les paramètres de substitution123
5.3.1 Paramètres de substitution des routes123
5.3.2 Exemples123
5.4 Travailler avec les URL125
5.5 Effectuer une redirection126
5.6 La délégation de requête126
5.7 La gestion des erreurs et des pages d'erreurs dans les contôleurs127
5.7.1 Le contrôleur127
5.7.2 La vue130
Chapitre 5
L'injection de dépendances
1. Le modèle de conception IoC : Inversion Of Control133
1.1 Apports dans une architecture applicative133
1.2 IoC et injection de dépendances135
2. L'injection de dépendances135
2.1 Principes de base135
2.2 Les différentes techniques d'injection de dépendances135
2.2.1 L'injection de dépendances par le constructeur135
2.2.2 L'injection de dépendances par setter (mutateur)136
2.2.3 L'injection de dépendances par propriété137
2.3 Les avantages138
3. Le Service Container138
3.1 Les services139
3.2 Explications au travers d'un service X139
4. Créer un service et configurer ses injections140
4.1 Créer un service140
4.2 Les différents types d'injections dans un service Symfony141
4.2.1 Injection par constructeur141
4.2.2 Injection par méthode141
4.2.3 Injection par propriété142
4.3 Injection automatique avec l'autowiring143
4.4 Les services « lazy »144
5. Le chargement automatique de services145
5.1 La configuration145
5.2 Exemple d'utilisation146
6. Créer des services réutilisables et distribuables148
6.1 Le concept de bundle148
6.1.1 Créer un bundle148
6.1.2 Arborescence du bundle149
6.2 La définition de services dans un bundle150
6.3 La configuration151
6.3.1 Définir une arborescence152
6.3.2 Les différentes étapes du traitement de la configuration154
6.3.3 Récupérer la configuration validée157
6.4 Les « Compiler Passes »160
6.4.1 Concept161
6.4.2 Les tags163
6.4.3 Le Compiler Pass164
Chapitre 6
Les templates avec Twig
1. Présentation et concepts167
1.1 Le concept de Templating167
1.2 Templating et modèle MVC167
2. Twig168
2.1 Présentation168
2.2 Pourquoi un nouveau langage ?169
2.3 Mise en pratique170
2.4 Remarques sur l'utilisation171
2.5 La notation des templates171
2.6 Extension du système de templates172
2.7 L'annotation @Template173
3. Les gabarits de pages (layouts) et les blocks174
3.1 La composition de pages174
3.2 Définition des gabarits175
3.3 Les blocks177
4. Le langage Twig180
4.1 Les différents types d'instructions180
4.2 Manipulation des variables180
4.2.1 Utilisation de variables dans les templates180
4.2.2 Utilisation des variables de type tableau ou objet182
4.3 Structures de contrôle et tags183
4.3.1 Les conditions183
4.3.2 Les boucles183
4.4 Les balises Twig (tags)186
4.4.1 Créer et modifier des variables186
4.4.2 Twig et l'échappement187
4.5 Inclure des templates190
5. Les filtres et les fonctions191
5.1 Présentation des filtres191
5.2 Les principaux filtres Twig192
5.2.1 Chaînes de caractères192
5.2.2 Échappement193
5.2.3 L'encodage194
5.3 Les fonctions196
5.3.1 Twig et le routage196
5.3.2 Débogage avec la fonction dump198
6. La gestion des ressourcés statiques (images, feuilles de style, scripts JS...)198
6.1 Les ressources statiques dans une application Symfony198
6.2 Le cas des ressources statiques externes199
6.3 Référencer les ressources publiques depuis un template200
6.4 Cas pratique avec le framework CSS Bootstrap201
7. Étendre le frontend avec Webpack Encore202
7.1 Présentation202
7.2 Installation et mise en place d'Encore203
7.2.1 Prérequis203
7.2.2 Installation d'Encore203
7.3 Utilisation d'Encore204
Chapitre 7
Accéder aux bases de données avec Doctrine
1. Présentation et concepts207
1.1 Les principes de l'ORM207
1.2 Architecture de Doctrine208
1.2.1 DBAL208
1.2.2 Entité209
1.2.3 ORM209
1.3 La notion d'entité210
2. Installer et configurer Doctrine210
2.1 Mise en place de Doctrine210
2.2 Relation avec PDO.211
2.3 Configuration212
3. Définition des entités et de leur mapping214
3.1 Règles de conception des entités214
3.2 Les syntaxes pour le mapping des entités216
3.3 Le mapping d'entités simples219
3.3.1 Définir une entité avec # [ORM\Entity]219
3.3.2 Gérer les colonnes de la table avec # [ORM\Column]220
3.3.3 # [ORM\Table]223
3.3.4 Les clés primaires224
3.3.5 Configurer les index225
3.4 Le mapping des relations (clés étrangères)226
3.4.1 # [ORM\OneToOne]226
3.4.2 # [ORM\ManyToOne]228
3.4.3 # [ORM\ManyToMany]229
3.4.4 Relations bidirectionnelles230
3.5 Les outils de la console234
3.5.1 Repérer les erreurs de mapping234
3.5.2 Générer le schéma des données à partir des entités235
4. Manipulation des entités avec l'EntityManager235
4.1 Le rôle de l'EntityManager235
4.2 Insertion de données236
4.3 Modification de données238
4.4 Suppression de données239
4.5 Autres opérations de l'EntityManager239
4.5.1 refresh ()239
4.5.2 detach ()240
4.6 Les opérations en cascade240
5. Récupérer des entités244
5.1 Le repository244
5.1.1 Un rôle de centralisateur244
5.1.2 Les méthodes de base du repository245
5.1.3 Les méthodes personnalisées du repository247
5.2 Le DQL248
5.2.1 SELECT249
5.2.2 FROM250
5.2.3 JOIN et LEFT JOIN251
5.2.4 WHERE254
5.2.5 ORDER BY258
5.2.6 Les limites258
5.2.7 Les limites et la pagination259
5.3 Le QueryBuilder261
6. Fonctionnalités avancées263
6.1 Les extensions Doctrine263
6.1.1 Installation264
6.1.2 Utilisation d'un slug sur une entité264
Chapitre 8
La gestion des événements applicatifs
1. Concepts et écoute d'événement applicatifs267
1.1 La propagation des événements268
1.2 L'écoute des événements270
2. Les événements du Kernel274
2.1 Les différents type d'événements274
2.2 Applications275
3. Les événements de la console277
3.1 Prérequis277
3.2 Les événements277
Chapitre 9
Les formulaires
1. Un composant MVC279
1.1 Le modèle279
1.2 Le contrôleur281
1.3 La vue282
2. Fonctionnement du composant283
2.1 L'objet « Form »283
2.1.1 Soumission283
2.1.2 Validation284
2.1.3 Vue284
2.2 Les types284
2.3 Les options285
2.4 Les objets « Form » et « FormBuilder »286
2.4.1 Le FormBuilder286
2.4.2 Structure de l'objet Form286
2.5 Association avec l'objet de la couche Modèle288
2.6 Formulaires sans objet289
2.7 La représentation des valeurs290
2.7.1 Transformation des données290
2.7.2 Illustration avec le type date291
3. Les types de champs de formulaire292
3.1 L'héritage292
3.2 FormType293
3.2.1 label293
3.2.2 label attr293
3.2.3 data293
3.2.4 required294
3.2.5 disabled294
3.2.6 mapped294
3.2.7 property_path295
3.2.8 attr295
3.2.9 trim295
3.2.10 error_bubbling296
3.3 TextType296
3.4 PasswordType296
3.5 RepeatedType297
3.5.1 type297
3.5.2 first_options et second_options298
3.5.3 options298
3.5.4 first_name298
3.5.5 second_name298
3.5.6 invalid_message298
3.6 ChoiceType298
3.6.1 choices299
3.6.2 expanded et multiple299
3.6.3 placeholder300
3.6.4 preferred_choices300
3.6.5 Types similaires301
3.7 EntityType301
3.7.1 class301
3.7.2 choice_label301
3.7.3 query_builder302
3.7.4 group_by302
3.7.5 em302
3.8 DateType303
3.8.1 widget303
3.8.2 format303
3.8.3 model_timezone304
3.8.4 view_timezone304
3.8.5 years304
3.8.6 months304
3.8.7 days304
3.8.8 placeholder305
3.8.9 Types similaires305
3.9 FileType305
3.9.1 multiple305
3.9.2 Récupérer les fichiers306
3.9.3 Traiter les fichiers307
3.10 CheckboxType308
3.11 SubmitType, ResetType et ButtonType308
4. Créer des formulaires réutilisables310
4.1 Définir un formulaire avec la classe AbstractType310
4.2 Utiliser un formulaire défini dans une classe317
4.2.1 Définition manuelle317
4.2.2 Avec l'injection de dépendances317
5. Validation des données319
5.1 Objectifs319
5.2 La définition des contraintes de validation319
5.2.1 Ajout des contraintes lors de la configuration d'un formulaire320
5.2.2 Ajout des contraintes sur l'objet associé au formulaire321
5.2.3 Les différents formats de configuration325
5.2.4 Les options329
5.3 Les contraintes et leurs options331
5.3.1 NotBlank et NotNull332
5.3.2 IsNull et Blank332
5.3.3 IsTrue, IsFalse332
5.3.4 Type333
5.3.5 Email, Url et Ip333
5.3.6 Regex335
5.3.7 Length, Count335
5.3.8 Range337
5.3.9 Comparaisons337
5.3.10 Dates338
5.3.11 File338
5.3.12 Image339
5.3.13 Choice339
5.3.14 UniqueEntity340
5.3.15 Données financières341
5.3.16 Callback341
5.3.17 All343
5.3.18 Valid343
5.4 Groupes de validation344
5.5 Validation d'un objet hors du contexte d'un formulaire346
6. Personnaliser le rendu - thèmes de formulaires347
6.1 Afficher le formulaire manuellement347
6.1.1 form_start ()348
6.1.2 form_end ()349
6.1.3 form_widget ()349
6.1.4 form_errors ()350
6.1.5 form_label ()350
6.1.6 form_rovv ()350
6.1.7 form_rest ()350
6.1.8 Arborescence des parties de formulaires351
6.2 Créer des thèmes352
6.2.1 Formulaire d'exemple352
6.2.2 Créer et associer un thème de formulaires353
6.2.3 Comprendre le nom des blocks357
Chapitre 10
La sécurité dans une application Symfony
1. Présentation et concepts de sécurité359
1.1 Les challenges de la sécurité des applications web359
1.2 La sécurité dans Symfony360
2. Authentification361
2.1 Pare-feu361
2.2 Authentification HTTP362
2.3 Authentification par formulaire de connexion363
2.4 Connexion automatique des utilisateurs366
2.5 Déconnexion des utilisateurs366
3. Utilisateurs et rôles367
3.1 L'utilisateur367
3.2 Les fournisseurs d'utilisateurs369
3.2.1 En mémoire369
3.2.2 Fournisseur d'utilisateurs de bases de données370
3.2.3 Fournisseur d'utilisateurs personnalisé373
3.2.4 Notes additionnelles376
3.3 Cryptage des mots de passe377
3.3.1 Passwords hashers377
3.3.2 Crypter un mot de passe378
3.4 Les rôles379
4. Autorisations382
4.1 Les rôles, au coeur du processus382
4.2 Vérifier le rôle de l'utilisateur382
4.3 Sécuriser une action384
4.4 Sécuriser une section de l'application385
4.5 Sécuriser selon d'autres critères385
4.6 Pour aller plus loin387
Chapitre 11
Développer une API REST avec Symfony
1. Introduction à REST et concepts fondamentaux389
1.1 Les concepts de REST389
1.1.1 Les ressources390
1.1.2 Le changement d'état d'une ressource390
1.2 Architecture et protocole HTTP390
1.3 Les Single-Page Applications391
2. La gestion du format JSON392
2.1 Présentation du format JSON392
2.1.1 Représentation des données en JSON393
2.1.2 Types de données.393
2.1.3 Structures393
2.2 Le support de JSON en PHP395
2.3 Et dans Symfony ?395
3. Mise en place d'une API REST396
3.1 Le service serializer396
3.1.1 Sérialiser des données397
3.1.2 Désérialiser des données397
3.2 Adaptation des contrôleurs398
4. Les objets de requête et de réponse398
4.1 Le contenu et les en-têtes de requête399
4.2 Manipulation de la réponse avec Response et JsonResponse400
4.3 Les codes de réponse HTTP dans une API REST402
4.3.1 Problématique de l'état de la réponse402
4.3.2 Expression de la réponse avec HTTP403
4.3.3 Mise en oeuvre404
5. Tester une API REST405
5.1 Les limites du navigateur web405
5.2 Les outils405
5.2.1 Postman406
5.2.2 SOAP UI408
6. Créer une API REST avec API Platform409
6.1 Présentation409
6.2 Installation409
6.3 La configuration d'API Platform410
6.4 Définition de l'API411
6.4.1 Les opérations de l'API414
6.4.2 Personnaliser l'API415
Chapitre 12
Tester son application Symfony
1. Introduction au test logiciel417
1.1 Les tests : un indispensable pour la qualité logicielle417
1.2 Les différentes catégories de tests418
1.2.1 Les tests unitaires418
1.2.2 Les tests d'intégration419
1.2.3 Les tests fonctionnels419
1.3 Analogie419
1.4 L'approche des tests en PHP420
2. Les tests unitaires avec PHPUnit421
2.1 Mise en place des tests421
2.2 Règle d'écriture des tests421
2.3 Exécuter les tests423
3. Les tests fonctionnels424
3.1 Différence par rapport aux tests unitaires et d'intégration424
3.2 Tester une action424
3.3 Les objets pour l'écriture des tests425
3.3.1 L'objet Client425
3.3.2 L'objet Crawler428
3.4 Soumettre un formulaire430
3.5 Pour aller plus loin431
Chapitre 13
Journalisation et surveillance avec Symfony
1. Générer des journaux avec Monolog433
1.1 La journalisation433
1.2 La librairie Monolog434
1.3 Le service logger435
1.4 Le fichier journal436
1.4.1 Identifier la cause d'un bogue436
1.4.2 Le problème436
1.5 Les gestionnaires (handlers)437
1.5.1 Définir plusieurs gestionnaires438
1.5.2 Envoyer des logs par e-mail438
1.5.3 Utiliser un tampon (buffer)439
1.5.4 Ajouter des informations complémentaires439
1.6 Les canaux (channels)441
1.6.1 Ajouter ses propres canaux441
1.6.2 Envoyer un enregistrement sur un canal donné442
1.6.3 Configurer les gestionnaires par canaux443
1.6.4 Gestion des erreurs 404443
2. Le monitoring avec Prometheus et Grafana446
2.1 Un allié proactif au logging446
2.2 Préparation d'une application Symfony pour Prometheus447
2.3 Instrumenter les mesures451
2.4 Pour aller plus loin452
Chapitre 14
Amélioration des performances
1. La mise en cache de pages453
1.1 Autour du protocole HTTP453
1.2 Un serveur proxy inverse (ou « reverse proxy »)454
1.2.1 HttpCache456
1.2.2 Nginx456
1.2.3 Varnish457
1.3 Les en-têtes462
1.4 Les réponses publiques et privées462
1.5 L'expiration463
1.5.1 L'en-tête Expires463
1.5.2 Les directives max-age et s-max-age464
1.5.3 L'annotation @Cache464
1.6 La validation466
1.6.1 Par date avec Last-Modified466
1.6.2 Par empreinte avec l'en-tête ETag468
1.7 Les ESI469
1.7.1 Activation469
1.7.2 Générer une balise ESI470
2. L'autochargement des classes471
3. Le cache avec Doctrine472
3.1 Les différents types de cache472
3.2 Configuration473
4. Le cache d'annotations474
5. Les sessions475
6. Autres optimisations476
6.1 Choix de sa SAPI PHP476
6.1.1 Qu'est-ce qu'une SAPI ?476
6.1.2 Module du serveur477
6.1.3 CGI477
6.1.4 FastCGI478
6.1.5 Conclusion478
6.2 Mise en cache d'OPCodes479
6.2.1 Les OPCodes479
6.2.2 Une étape lourde480
6.2.3 La mise en cache480
6.3 La compression des réponses480
6.3.1 Compression gzip481
6.3.2 Précompression481
6.4 Optimisation des images482
6.4.1 Validation482
6.4.2 Expiration482
6.4.3 Autres techniques482
7. Test des performances d'un site web483
7.1 Côté serveur483
7.1.1 Apache Bench483
7.1.2 Xhprof484
7.2 Côté client484
Chapitre 15
Internationalisation des applications Symfony
1. Introduction485
1.1 Culture, internationalisation et régionalisation485
1.1.1 La culture (Locale)486
1.1.2 Internationalisation486
1.1.3 Régionalisation486
1.2 L'internationalisation dans Symfony487
2. Détecter la culture d'un utilisateur487
2.1 Les techniques487
2.1.1 Négociation de contenu487
2.1.2 Par l'URL488
2.2 En pratique488
3. Activation des traductions489
3.1 Le composant translator489
3.2 Configuration du framework489
4. Les routes et les traductions490
5. Les fichiers de traductions491
5.1 Organisation et règles de nommage491
5.2 Outillage pour la création des fichiers de traduction492
5.2.1 Afficher la liste des traductions manquantes492
5.2.2 Générer un fichier de traduction493
6. Traduction d'un message493
6.1 Le service translator493
6.2 Les paramètres de substitution (placeholders)494
6.3 Utilisation dans les templates Twig495
Annexes
1. Créer une commande pour la console497
1.1 La configuration d'une commande497
1.2 Les objets input et output498
1.3 Le Service Container501
1.4 Commande d'exemple502
2. Envoyer des e-mails grâce à Mailer503
2.1 Le protocole SMTP503
2.2 Le transport503
2.2.1 Le transport smtp504
2.2.2 Le transport sendmail505
2.3 Envoi d'un e-mail506
3. Travailler avec les sessions507
3.1 Introduction507
3.2 Intégration des sessions dans Symfony507
3.3 Configuration du gestionnaire de sauvegarde508
3.3.1 Avec PHP508
3.3.2 Avec Symfony509
3.4 Les messages « flash »509
4. Déployer une application symfony511
4.1 Le déploiement511
4.2 Faut-il déployer par FTP ?512
4.3 Les différentes étapes513
4.4 Capistrano et Capifony513
4.4.1 Installation513
4.4.2 Configuration514
4.4.3 Déploiement516
4.5 Fonctionnalités avancées516
Index517