0% ont trouvé ce document utile (0 vote)
123 vues287 pages

Symfony

Transféré par

tsourirakia88
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
123 vues287 pages

Symfony

Transféré par

tsourirakia88
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Symfony 6

Introduction
AYMEN SELLAOUTI
C’est quoi symfony ?
« Symfony is a set of PHP Components, a Web Application framework,
a Philosophy, and a Community — all working together in harmony. »
[site Officiel Symfony]
Ensemble de composants PHP
Framework pour les applications web
Basée sur des composants
Structuration du code
Maintenabilité
C’est quoi symfony ?
Une philosophie
Les bonnes pratiques
standardisation
Une très grande communauté
FrameWork : Cadre De Travail (Boite à outils)
Ensemble de composants servant à créer :
Fondation
Architecture
Pourquoi utiliser un Framework
Productivité : ensemble de composants déjà prêt à l’emploi

Propreté du code => maintenabilité et évolutivité

Basée sur une architecture => facilite le travail en équipe

Communauté et documentation
Installation de Symfony (1)
Afin d’installer Symfony, vous devez disposer de Composer qui est un
PHP Package Manager. https://getcomposer.org/download/
Pré requis :
PHP 8.1 ou plus, ceci dépendra de la version Symfony.
 Lancer la commande : composer create-project
symfony/website-skeleton nomProjet pour une version d’un projet
web qui contient les bibliothèques de bases dédiées à un projet web.
 Lancer la commande : composer create-project
symfony/skeleton nomProjet pour une version orientée vers les
microservices ou les API.
Installation de Symfony (2)
Vous pouvez aussi utiliser le symfony client : https://symfony.com/download
Installer tout d’abord scoop (pour windows) via ce lien https://scoop.sh/
Lancer ensuite la commande scoop install symfony-cli
Vous n’avez qu’à utiliser donc la commande symfony new nomProjet pour
avoir votre projet.
Vous allez avoir deux choix, la version Webapp qui contient l’ensemble des
bibliothèques nécessaires pour la création d’une application ajouter l’option
--webapp.
La version minimaliste pour créer des api, des micro services ou une
application desktop.
Installation de Symfony (3)
 symfony new my_project_directory --version="6.1.*" --webapp
 symfony new my_project_directory --version="6.1.*“
 composer create-project symfony/skeleton:"6.1.*" my_project_directory
 composer create-project symfony/skeleton:"6.1.*" my_project_directory
Symfony Roadmap
Vous pouvez vérifier les différentes roadmap des versions symfony.
Choisissez les versions stables LTS (Long Term Support)

https://symfony.com/roadmap
Architecture d’un projet Symfony 2.8 et 3.*
•app/ : La configuration de l'application,
•src/ : Le code PHP du projet,
•vendor/: Les bibliothèques tierces,
•web/ : Le répertoire Web racine.
Symfony 3

Identifier les
différences entre
symfony2.8 et 3
Architecture d’un projet Symfony 4.*
Le contrôleur frontal (1)
public/index.php
Il joue le rôle de dispatcheur :

Intercepte les requêtes

Appelle le noyau de symfony (AppKernel.php)

Le noyau prépare la réponse à rendre

https://symfony.com/doc/4.2/create_framework/front_controller.html
Le contrôleur frontal (2)
Le contrôleur principal s'occupe de gérer les requêtes, mais cela signifie
plus que simplement déterminer une action à exécuter. En fait, il
exécute le code qui est commun à chaque action, soit les étapes
suivantes :
Définir les constantes.
Déterminer les chemins des bibliothèques Symfony.
Charger et initialiser les classes du cœur du framework.
Charger la configuration.
Symfony 6
Les contrôleurs
AYMEN SELLAOUTI

1
Introduction (1)

2
Introduction (2)

/ rootAction Réponse
R R
e e
q p
Contrôleur Noyau Symfony2
u /root1 Frontal
rootAction1 Réponse e
ê n
t s
Requête
e /root2 URI
Contrôleur e
rootAction2 Réponse
s s

Routeur

3
Introduction (3)
Fonction PHP (action)
Rôle : Répondre aux requêtes des clients.

Page HTML
Requête HTTP Réponse Document XML
Contrôleur Tableau JSON
Image
Redirection

4
Exemple d’un contrôleur

#[Route('/personne', name: 'personne')]


public function index(){
// On crée un objet Response puis on la retourne c’est le rôle du contrôleur
$resp = new Response('<html><body>Bonjour le monde !</body></html>');
return $resp;

5
Exercice
Créer une classe FirstController
Créer une action first
Faite en sorte que lors de l’appel de la route /first cette action soit
exécuté et qu’elle affiche une page contenant ‘Hello forma’
Fonctions de base de la classe
AbstractController
Méthode fonctionnalité Valeur de retour
generateUrl(string $route, array() $parameters) Génère une URL à partir de la route String
forward(String Action, array () $parameters) Forward la requête vers un autre Response
contrôleur
Redirect(string $url, int $tatut) Redirige vers une url RedirectResponse
RedirectToRoute(string $route, array $parameters) Redirige vers une route Response
Render(string $view, array $parameters) Affiche une vue Response
Get(string $id) Retourne un service à travers son id object
createNotFoundException(String $messag) Retourne une NotFoundException NotFoundException

7
Génération automatique d’un contrôleur
Afin d’automatiquement générer un contrôleur via la console, vous
pouvez utiliser le maker de Symfony disponible depuis sa version 4.

php bin/console make:controller NomController


symfony console make:controller NomController

8
Lien entre la route et le contrôleur
Création de la route
Voici un exemple de correspondance entre une route et le contrôleur
qui lui est associé :
Nous prenons l’exemple d’une route écrite en attributs, YAML et en
annotation.
#[Route('/personne', name: ‘personne')]
personne:
path: /personne
controller: App\Controller\PersonneController::index
/**
* @Route("/personne", name="personne")
*/
9
Lien entre la route et le contrôleur
Passage de paramétré : route vers contrôleur
Afin de récupérer les paramètres de la root dans le contrôleur nous
utilisons les noms des paramètres.
Exemple

#[Route('/first/{section}', name: 'app_first')]


public function index($section)
{
$resp = new Response('<html><body>Bonjour’. $section.’!</body></html>');
return $resp;
}

10
Exercice
Dans la classe FirstController
Créer une méthode param qui prend en paramètre une variable nom à
travers la route.
Faite en sorte d’afficher Bonjour suivi du nom passé en paramètre.
Récupérer les paramètres de la requête (1)
Afin de récupérer l’objet Request dans le contrôleur, il suffit d’utiliser le
type-hint et le déclarer dans l’entête du contrôleur en question En
spécifiant qu’il s’agit d’un objet de type Request.

Exemple
use Symfony\Component\HttpFoundation\Request;
public function indexAction(Request $req)
{

}

12
Exercice
Dans la classe FirstController
Créer une action second
Faite en sorte d’y dumper (via la fonction dump) l’objet Request et
l’objet Response. Vérifier les informations encapsulées par ses deux
objets.
Récupérer les paramètres de la requête (2)
L’objet Request permet de récupérer l’ensemble des attributs passées
dans la requête

Méthode
Type de paramètres Méthode Symfony2 Exemple
traditionnelle
Variables d'URL $request->query $_GET $request->query->get(‘var')
Variables de $request->request $_POST $request->request->get(‘var')
formulaire
Variables de cookie $request->cookies $_COOKIE $request->cookies->get(‘var')

14
Récupérer les paramètres de la requête (3)
Exemple : pour l’url suivante
http://127.0.0.1/symfoRT4/web/index.php/test/bonjour/forma?groupe=1
Pour récupérer le groupe passé dans l’url (donc du Get) on devra récupérer le
request puis utiliser $request->query->get('tag')

public function index($section,Request $req)


{
$groupe = $request->query->get(‘groupe');
return new Response(« Bonjour ».$section.« groupe ».$groupe);
}

15
Récupérer les paramètres de la requête (4)
La classe Request offre plusieurs informations concernant la requête
HTTP à travers un ensemble de méthodes
(https://symfony.com/doc/current/introduction/http_fundamentals.ht
ml#symfony-request-object)
getMethod() : retourne la méthode de ma requête
isMethod() : vérifie la méthode
getLocale : retourne la locale de la requête (langue)
isXmlHttpRequest : retourne vrai si la requête est de type
XmlHttpRequest
…
16
Réponse aux requêtes
Renvoi (1)
Le rôle principale du contrôleur est de répondre à la requête du client en envoyant
une réponse.
Vous pouvez créer un objet Response et y injecter votre contenu et le retourner.
Sinon, le traitement se fait à travers un Helper qui utilise le service templating qui
se charge de créer et d’irriguer un objet de type Response.
Rôle : créer la réponse et la retourner
Méthode :
 En utilisant les helpers :
 $this->render (‘l’url’, ‘les paramétres à transferer’);

17
Réponse aux requêtes
Renvoi (2)
Exemple :
public function index ($section,Request $req)
{
$groupe = $request->query->get(‘groupe');
return $this->render(‘default/index.html.twig’, array(’section’=>$section,
‘goupe’=>$groupe));
}

18
Exercice
 Créer l’action (contrôleur) cv
 Préparer des variables permettant de créer un mini Portfolio. Le contenu de ces variables devra vous
permettre d’afficher vos nom et prénom, votre âge et votre Section.
 Ensuite, utiliser la méthode render afin d’invoquer votre page TWIG en lui passant les variables que
vous venez de préparer.
 Sachant que pour afficher une variable dans TWIG il suffit de l’entourer de {{ nomVariable }}, créer
une page TWIG « cv.html.twig » dans un dossier « Premier» que vous créerez dans le dossier
« templates ».
 Cette page devra afficher les données transmises par votre contrôleur

19
Réponse aux requêtes
Redirection
 Rôle : Redirection vers une deuxième page ( en cas d’erreur
ou de paramètres erronées ou de user non identifié par
exemple)
 Redirection vers une url.
return this->redirect($url);

 Redirection vers une route


return this->redirectToRoute(‘nomDeMaRoute’);

20
Réponse aux requêtes
Forwarding
Rôle : Forwarder vers une action
Méthode :

$response = $this->forward('App\Controller\NomController::NomAction',
array('name' => $name));

21
Gestion des sessions
 Une des fonctionnalités de base d’un contrôleur est la
manipulation des sessions.
 Un objet session est fournit avec l’objet Request.
 La méthode getSession() permet de récupérer la session.
 Il est préférable d’utiliser le type-hint via L’interface
SessionInterface :
 public function index (SessionInterface $session)

22
Gestion des sessions
L’objet Session fournit deux méthodes : get( ) pour récupérer une
variable de session et set( ) pour la modifier ou l’ajouter.
get prend en paramètre la variable de session.
set prend en entrée deux paramètres la clef et la valeur.
Dans la TWIG on récupère les paramètres de la session avec la
méthode
app.session.get(‘nomParamétre')

23
Gestion des sessions : les méthodes
all() Retourne tous les attributs de la session dans un tableau de la
forme clef valeur
has() Permet de vérifier si un attribut existe dans la session. Retourne
Vrai s’il existe Faux sinon
replace() Définit plusieurs attributs à la fois: prend un tableau et
définit chaque paire clé => valeur
remove() Efface un attribut d’une clé donnée.
clear() Efface tous les attributs.

24
Gestion des sessions : les FlashMessages
Les variables de sessions qui ne dure que le temps d’une seule page
sont appelées message Flash.
Utilisées généralement pour afficher un message après un traitement
particulier ( Ajout d’un enregistrement, connexion, …).
La méthode getFlashBag() permet de récupérer l’objet FlashBag à
partir de l’objet session.
La méthode add de cet objet permet d’ajouter une variable à cet objet.
Vous pouvez utilisez un helper via la méthode addFlash.

25
Gestion des sessions : les FlashMessages
Pour récupérer le Flash message de la TWIG on utilise
app.session.flashbag.get(‘nomParamétre‘).
Vous pouvez aussi utiliser la méthode flashes de la variable globale
app qui contient le tableau des flashBags messages.

26
Exercice
 Créer un contrôleur appelé ToDoController
 Créer une première action (indexAction) qui permet d’initialiser Astuce : Afin d’afficher les éléments et les
un tableau associatif de clés d’un tableau associatif dans la twig on
todos et qui le met dans la session puis appelle la page peut utiliser la syntaxe suivante qui sera
‘listeToDo.html.twig’. Lors de l’appel de ce contrôleur, il faudra explicité dans le chapitre consacré aux TWIG.
{% for cle,element in tableau %}
vérifier si la liste des todo existe déjà dans la session. Si la liste existe
{{ cle }} {{ element }}
il ne faut pas la réinitialiser. {% endfor %}
Exemple $todos = array(
'achat'=>'acheter clé usb',
'cours'=>'Finaliser mon cours',
'correction'=>'corriger mes examens'
);

27
Exercice
Quelques Astuces
Ajouter bootstrap pour avoir les classes Alert ou un peu de css pour
colorer le background de vos DIV ou paragraphe.
Utiliser la fonction unset de php qui permet de supprimer un élément
du tableau partir de sa clé.
Pour ajouter un élément dans un tableau associatif il suffit d’utiliser la
section suivante : $monTab[‘identifiant’]=$var ;

28
Exercice
Créer une action addToDoAction qui permet d’ajouter un ToDo ou
de le mettre à jour. Cette action devra afficher la liste mise à jour. Si
la liste de ToDo n’est pas encore initialisée, un message d’erreur
sera affiché.

29
Exercice
 Si le ToDo est ajouté avec succès, un message de succès sera
affiché. Si le ToDo est mis à jour il faut le mentionner.

30
Exercice
Créer une action deleteToDo qui permet de supprimer un ToDo à
partir de son indice dans le tableau. Cette action devra afficher la
liste mise à jour. Si le toDo à supprimer n’existe pas, un message
d’erreur est affiché.
Si la suppression est effectuée avec succès un message est
affiché.

31
Exercice
 Créer une action resetToDo qui permet de vider la session et de la
remettre à son état initial. Prenez en considération le cas où la liste
n’est pas encore initialisée

32
{# templates/base.html.twig #}
{# read and display just one flash message type #}
{% for message in app.flashes('notice') %}
<div class="flash-notice">
{{ message }}
</div>
{% endfor %}

{# read and display several types of flash messages #}


{% for label, messages in app.flashes(['success', 'warning']) %}
{% for message in messages %}
<div class="flash-{{ label }}">
{{ message }}
</div>
{% endfor %}
{% endfor %}

{# read and display all flash messages #}


{% for label, messages in app.flashes %}
{% for message in messages %}
<div class="flash-{{ label }}">
{{ message }}
</div>
{% endfor %}
{% endfor %}
https://symfony.com/doc/current/controller.html#flash-messages
33
[email protected]

34
Symfony 6
Routing
AYMEN SELLAOUTI
Introduction
Système permettant de

 gérer les liens internes du projet

 avoir des URLs plus explicites

 associer une URL à une action


Introduction
Cette architecture illustre le
fonctionnement de Symfony.
1- Requête de l’utilisateur
2- La requête est envoyé vers le noyau
de Symfony.
3- Le Noyau consulte le routeur afin de
connaitre quel Action exécuter.
4- Le routeur envoi les informations
concernant l’URI
5- Le noyau invoque l’action exécuter.
6- Exécution de l’action
7- L’action retourne la réponse.

Routing (http://www.lafermeduweb.net/)
Format de gestion du routing
Les fichiers de routing peuvent être de quatre formats différents :

YAML
 XML
 PHP
Annotations
Attributs
Squellete d’une route
Jusqu’à la version 3, Sensio recommande l’utilisation du format Yaml
au sein des applications. Les bundles développés sont partagés entre
deux formats : le XML e le Yaml.
Sensio a décidé de recommander Yaml parece qu’il est « user-friendly ».
A partir de la version 3.4, la documentation s’est focalisé
essentiellement sur les annotation et la recommande. Nous allons donc
voir ces deux formats.
Dans la version 8 de PHP, une nouvelle syntaxe plus lisible et plus
fonctionnelle a été introduite : les attributs.
Squelette d’une route en utilisant les
Annotations et les attributs

/**
*
* @Route("/blog", name="blog_list") #[Route('/blog', name: 'blog_list')]
*/ public function list(): Response
{
public function list()
// ...
{ }
// ...
}
Squelette d’une route en utilisant YAML

# config/routes.yaml
blog_list:
# Matches /blog exactly
path: /blog
controller: App\Controller\BlogController::list

https://symfony.com/doc/current/routing.html
Squelette d’une route en utilisant XML
<!-- config/routes.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">

<!-- Matches /blog exactly -->


<route id="blog_list" path="/blog"
controller="App\Controller\BlogController::list">
<!-- settings -->
</route>
</routes>

https://symfony.com/doc/current/routing.html
Squelette d’une route en utilisant PHP
<?php
// config/routes.php
use App\Controller\BlogController;
use
Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;

return function (RoutingConfigurator $routes) {


// Matches /blog exactly
$routes->add('blog_list', '/blog')->controller(
[BlogController::class, 'list']
);
};

https://symfony.com/doc/current/routing.html
Organisation des routes YAML
Lorsque vous utilisez YAML, il est préférable de ne pas centraliser
l’ensemble de vos routes dans un même fichier. Ceci peut nuire à la
lisibilité de vos routes.
Décomposer vos routes en des fichiers logiques. Exemple si vous avez
une partie Back et une partie front, ayez deux fichiers back.yaml et
front.yaml.
Garder le fichier principal de vos routes pour appeler ces fichiers la.
Organisation des routes YAML
Afin d’identifier un fichier de ressources « route» utiliser la clé
ressource afin d’informer le chemin de la ressource et la clé type afin
de spécifier le type de votre ressource (dans notre cas c’est directory).
Les préfixes
 Dans certains cas vous avez besoins d’avoir des endpoints
particuliers pour un ensemble de fonctionnalités. Par exemple
lorsque vous aller réaliser une partie administration vous aurez
généralement des routes qui commencent par /admin.

 Afin de gérer ca, le routeur de Symfony offre la possibilité d’ajouter


des préfixes à vos routes.
Les préfixes YAML
Afin de préfixer une route YAML aller dans le fichier ou vous avez
appelé la ressource et ajouter la clé prefix :

app_personne:
resource: 'personne'
type: directory
prefix: /personne

https://symfony.com/doc/4.2/routing/external_resources.html
Préfixe annotation
Une annotation Route sur une classe Contrôleur définit un préfixe
sur toutes les routes des actions de ce contrôleur
/**
* @Route("/personne")
*/
class PersonneController extends AbstractController
{
}

#[Route('/first']
class FirstController extends AbstractController
Paramétrage de la route : Yaml
Nous pouvons ajouter autant de paramètre dans la route
Le séparateur est ‘/’
 Exemple
front_article:
path: /article/{year}/{langue}/{slug}/{format}
controller: App\Controller\BlogController::add
 Ici l’url doit contenir l’année de l’article {year}, la langue de
l’article{langue} les mots clefs {slug} ainsi que le format {fomrat}
Paramétrage de la route : Annotation
/**
* @Route("/hello/{name}", name=" front_homepage")
*/
public function test ($name){}

/**
* @Route("/article/{year}/{locale}/{slug}/{format}",
name="front_article")
*/
public function showArticle($year,$locale,$slug,$format){}
Paramétrage de la route : Attributs
#[Route('/second/{name}', name: 'app_second')]
public function index($name): Response
{
return $this->render('second/index.html.twig', [
'myName' => $name,
]);
}
Paramétrage de la route : valeurs par
défaut Annotations
 En utilisant les annotations, nous ajoutons un champ defaults qui
contiendra les valeurs par défaut.
/**
* @Route(
* "/article/{year}/{locale}/{slug}/{format}",
* name="front_article",
* defaults={"format":"html", "slug":"Symfony"}
* )
*/
public function showArticleAction($year,$_locale,$slug,$_format){
dump($year,$_locale,$slug,$_format);
die();
} Important : Seul les paramètres optionnels terminant la route pourront être absents de l’URL

 Maintenant l’URL suivante devient correcte : http://127.0.0.1:8000/article/2005/fr


et les variables slug et format prendront leur valeur par défaut
Paramétrage de la route : valeurs par
défaut Annotations Raccourci
 Vous pouvez utiliser le raccourci { attribut?defaultValue}.
 Evitez ce type de raccourci si vous avez des routes complexes afin d’avoir une bonne
lisibilité de vos routes.
/**
* @Route(
* "/article/{year}/{locale}/{slug?symfony}/{format?html}",
* name="front_article",
* )
*/
public function showArticleAction($year,$locale,$slug,$format){
dump($year,$_locale,$slug,$_format);
die();
} Important : Seul les paramètres optionnels terminant la route pourront être absents de l’URL

 Maintenant l’URL suivante devient correcte : http://127.0.0.1:8000/article/2005/fr


et les variables slug et _format prendront leur valeur par défaut
Paramétrage de la route : valeurs par
défaut Attributs
#[Route(
'/second/{name}',
name: 'app_second',
defaults: ['name' => 'aymen']
)]
public function index($name): Response
{
return $this->render('second/index.html.twig', [
'myName' => $name,
]);
}
Paramétrage de la route : valeurs par
défaut Attributs
#[Route(
'/second/{name?skander}',
name: 'app_second',
)]
public function index($name): Response
{
return $this->render('second/index.html.twig', [
'myName' => $name,
]);
}
Paramétrage de la route : valeurs par
défaut Yaml
 Afin d’avoir des valeurs par défauts nous utilisons la syntaxe suivante :
Syntaxe
front_article:
path: /article/{year}/{locale}/{slug}/{format}
controller: App\Controller\BlogController::add
defaults:
attribut: defaultValue
Paramétrage de la route : Requirements
Annotation
 En utilisant les annotations, nous ajoutons un champ requirements
qui contiendra les différentes contraintes.
/**
* @Route(
* "/article/{year}/{locale}/{slug}/{format}",
* name="front_article",
* defaults={"_format":"html", "slug":"Symfony"},
* requirements={
* "locale" : "fr|en",
* "year" : "\d{4}"
* }
* )
*/
public function showArticleAction($year,$_locale,$slug,$_format){}
Paramétrage de la route : Requirements
Annotation, le raccourci
Vous pouvez utiliser le raccourci { attribut<requirement>}.
Evitez ce type de raccourci si vous avez des routes complexes afin
d’avoir une bonne lisibilité de vos routes.
/**
* @Route(
* "/article/{year<\d+>}/{locale}/{slug}.{format}",
* name="front_article")
*/
public function showArticleAction($year,$_locale,$slug,$_format){

}
Paramétrage de la route : Requirements
Attributs
 En utilisant les annotations, nous ajoutons un champ requirements
qui contiendra les différentes contraintes.
#[Route(
'/second/{name}/{age}',
name: 'app_second',
requirements: ['age'=> '\d+']
)]
public function index($name, $age): Response
{
return $this->render('second/index.html.twig', [
'myName' => $name,
'myAge'
]);
}
Paramétrage de la route : Requirements
Attributs
 En utilisant les annotations, nous ajoutons un champ requirements
qui contiendra les différentes contraintes.
#[Route(
'/second/{name}/{age<\d+>}',
name: 'app_second',
)]
public function index($name, $age): Response
{
return $this->render('second/index.html.twig', [
'myName' => $name,
'myAge‘=> $age
]);
}
Requirements autres exemples
\d équivalente à \d{1}
\d+ ensemble d’entiers
Ordre de traitement des routes (1)
Le traitement des routes se fait de la première route vers la dernière.
Attention à l’ordre d’écriture de vos routes.
front: Comment accéder au path front_pages ? Quel est le problème avec ces 2 routes

path: /front/{page}
controller: App\Controller\BlogController::front
front_pages:
path: /front/{Keys}
controller: App\Controller\BlogController::show
Exercice
 Reprenez les deux routes précédentes.

 Testez l’accessibilité à la deuxième route.

 Ajouter ce qu’il faut pour remédier au problème


Ordre de traitement des routes (2)
front:
path: /front/{page}
controller: App\Controller\BlogController::front
}
front_pages:
path: /front/{Keys}
controller: App\Controller\BlogController::show
Les deux routes sont de la forme /front/* donc n’importe quel route de cette
forme sera automatiquement transféré au Default controller pour exécuter
l’index action.
Proposer une solution
Ordre de traitement des routes (3)
front:
path: /front/{page}
controller: App\Controller\BlogController::front
requirements:
page: \d+
front_pages:
path: /front/{Keys}
controller: App\Controller\BlogController::show
Tester le fonctionnement des routes suivantes : /front/1234
/front/test-ordre-de-routeing
Ordre de traitement des routes (4)
Que se passe t-il si on inverse l’ordre des deux routes ? Est-ce que la solution
persiste?
front_pages:
path: /front/{Keys}
controller: App\Controller\BlogController::show
front:
path: /front/{page}
controller: App\Controller\BlogController::front
requirements:
page: \d+
Ordre de traitement des routes (5)
Les Routes précédentes Gagnent toujours
L'ordre des routes est très important.
En utilisant un ordre clair et intelligent, vous pouvez accomplir tout ce
que vous voulez.
http://symfony.com/fr/doc/current/book/routing.html
Ordre de traitement des routes (6)
Débogage des routes
Afin de visualiser l’ensemble des routes utiliser la
debug toolbar
Vous pouvez aussi utiliser la commande :
symfony console debug:router
symfony console debug:router
 On peut aussi vérifier quelle route correspond à
une URL spécifique
symfony console router:match URI
php bin/console router:match URI
Symfony 6
TWIG et Webpack
Encore
AYMEN SELLAOUTI
Introduction (1)
Introduction (2)
Moteur de Template PHP.

Développé par l'équipe de Sensio Labs,

Directement intégré dans Symfony (pas besoin de l’installer).


Introduction (3)
L'objectif principal de Twig est de permettre aux développeurs de
séparer la couche de présentation (Vue) dans des Templates dédiés, afin
de favoriser la maintenabilité du code.
Idéal pour les graphistes qui ne connaissent pas forcément le langage
PHP et qui s'accommoderont parfaitement des instructions natives du
moteur, relativement simples à maîtriser.
Il y a quelques fonctionnalités en plus, comme l'héritage de templates.
Il sécurise vos variables automatiquement (htmlentities(), addslashes())
Syntaxe de bases de Twig
{{ maVar }} : Les doubles accolades (équivalent de l’echo dans php ou
du <%= %> pour les jsp) permettent d'imprimer une valeur, le résultat
d'une fonction...

{% code %}: Les accolades pourcentage permettent d'exécuter une


fonction, définir un bloc...

{# Les commentaires #}: Les commentaires.


Comment afficher une variable dans TWIG (1)
Fonctionnalité Exemple Twig Équivalent PHP

Afficher une variable Variable : {{ MaVariable }} Pseudo : <?php echo $MaVariable; ?>

Afficher le contenu d’une case


Identifiant : {{ tab['id'] }} Identifiant : <?php echo $tab['id']; ?>
d'un tableau
Afficher l'attribut d'un objet, dont
le getter respecte la Identifiant : {{ user.id }} Identifiant : <?php echo $user->getId(); ?>
convention $objet->getAttribut()

Afficher une variable en lui MaVariable majus: <?php echo


MaVariable majus :
appliquant un filtre. Ici, « upper » strtoupper($MaVariable);
{{ MaVariable|upper }}
met tout en majuscules : ?>
Comment afficher une variable dans TWIG (2)
Fonctionnalité Exemple Twig Équivalent PHP

Afficher une variable en


combinant les filtres. Message : <?php
« striptags » supprime les balises echo ucwords(strip_tags($news->
Message : {{ news.texte|striptags|title }}
HTML. getTexte()));
« title » met la première lettre de ?>
chaque mot en majuscule.

Utiliser un filtre avec des


Date : <?php echo
arguments.
Date : {{ date|date('d/m/Y') }} $date->format('d/m/Y');
Attention, il faut que date soit un
?>
objet de type Datetime ici.

Identité : <?php echo $nom.' '.


Concaténer Identité : {{ nom ~ " " ~ prenom }}
$prenom; ?>
Comment afficher une variable dans les TWIGS :
Exemple :
Twig et l’affichage d’un attribut
Lorsqu’on veut accéder à un attribut d’un objet avec twig on a le fonctionnement suivant pour l’exemple
{{personne.name}} :
Vérification si personne est un tableau, si oui vérifier que nous avons un index valide dans ce cas elle
affiche le contenu de personne[‘name’]
Sinon, si personne est un objet, elle vérifie si name est un attribut valide public. Si c'est le cas, elle
affiche personne->name.
Sinon, si personne est un objet, elle vérifie si name() est une méthode valide publique. Si c'est le cas,
elle affiche personne->name().
Sinon, si personne est un objet, elle vérifie si getName() est une méthode valide. Si c'est le cas, elle
affiche personne->getName().
Sinon, et si personne est un objet, elle vérifie si isName() est une méthode valide. Si c'est le cas, elle
affiche personne->isName().
Sinon, elle n'affiche rien et retourne null.
Les filtres
 Un filtre permet de changer l’affichage d'une variable sans changer son
contenu. Il peut avoir un ou plusieurs paramètres.
Filtre Description Exemple Twig
Upper Met toutes les lettres en majuscules. {{ var|upper }}
Striptags Supprime toutes les balises XML. {{ var|striptags }}
Date Formate la date selon le format {{ date|date('d/m/Y') }}
donné en argument. La variable en Date d'aujourd'hui : {{ "now"|date('d/m/Y') }}
entrée doit être une instance
de Datetime.
Format Insère des variables dans un texte, {{ "Il y a %s pommes et %s poires"|format(153,
équivalent à printf. nb_poires) }}
Length Retourne le nombre d'éléments du Longueur de la variable : {{ texte|length }}
tableau, ou le nombre de caractères Nombre d'éléments du tableau : {{ tableau|length }}
d'une chaîne.
Exercice
Reprenez l’exemple du cv et appliquer les filtres suivants sur
l’affichage :
Les nom et prénoms doivent être en majuscule
L’âge doit être affiché en entier positif
Donner des valeurs par défaut aux variables
Les fonctions
Une fonction peut changer la valeur d'une variable et peut avoir un ou plusieurs
paramètres. {% if date(user.created_at) < date('-2days') %}
{# do something #}
Quelques fonctions offertes par twig :
{% endif %}
 date : convertie un argument en une date afin de permettre une comparaison
entre dates.
max, min : retourne le min et le max d’un ensemble
parent : utiliser dans l’héritage et retourne le contenu du bloc parent.
{{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #}
random: retourne un élément aléatoire {{ random('ABC') }} {# example output: C #}
{{ random() }}{# example output: 15386094
selon les paramètres passées à la fonction (works as the native PHP mt_rand function) #}
{{ random(5) }} {# example output: 3 #}
{{ random(50, 100) }} {# example output: 63 #}
https://twig.symfony.com/doc/2.x/functions/index.html
Exercice
Créer une page TWIG qui prend en paramètre un tableau de notes,
qui l’affiche, affiche le nombre de ces éléments, le min et le max de ce
tableau en utilisant les fonctions et les pipes twig.
Le nombre d’éléments du tableau doit être paramétrable à travers la
route et doit être de 5 par défaut.
Le contenu du tableau doit être aléatoire.
Structures de contrôle
Les structures que ce soit séquentielles ou itératives sont souvent très
proches du langage naturel.

Elles sont introduites entre {% %}

Généralement elle se termine par une expression de fin de block


Affectation de variables
Afin d’affecter une valeur à une variable dans TWIG, utiliser la syntaxe
suivante :

{% set maVar = « valeur » %}

Exemple
{% set sum = 0 %}
Structure conditionnelle
if
Syntaxe :
{% if cnd %}
Block de traitement
{%endif%}
Exemple
{% if employee.salaire < 250 %}
ce salaire est inférieur au smig
{%endif%}
Structure conditionnelle
IF else elseif Exemple
Syntaxe :
{% if cnd %} {% if maison.tempertature <0%}
block traitement Très Froid
{% elseif cnd2 %} {% elseif maison.tempertature <10 %}
block traitement
Froid
{% else %}
{% else %}
block traitement
Bonne température
{% endif %}
{% endif %}
Tests
is defined l’équivalent de isset en php
Rôle vérifie l’existence d’une variable
Exemple:{% if MaVariable is defined %} J’existe {% endif%}

even odd
Rôle vérifie si la variable est pair Rôle vérifie si la variable est impair
Exemple : {% if MaVariable is even %}Pair{% endif%} Exemple : {% if MaVariable is odd%}Impair{% endif%}
Structure itérative
{% for valeur in valeurs %} Exemple
block à répéter La formation de l’équipe A est : <br>
{% else %} <ol>
Traitements à faire si il n’y {% for joueur in joueurs %}
a aucune valeur <li> {{joueur.nom}} </li>
{% endfor %} {% else %}
La liste n’a pas encore été renseignée
{% endfor %}
</ol>
Structure itérative
 La boucle for définit une variable loop ayant les attributs suivants :
Variable Description

{{ loop.index }} Le numéro de l'itération courante (en commençant par 1).

{{ loop.index0 }} Le numéro de l'itération courante (en commençant par 0).

{{ loop.revindex }} Le nombre d'itérations restantes avant la fin de la boucle (en finissant par 1).

{{ loop.revindex0 }} Le nombre d'itérations restantes avant la fin de la boucle (en finissant par 0).

{{ loop.first }} true si c'est la première itération, false sinon.


{{ loop.last }} true si c'est la dernière itération, false sinon.
{{ loop.length }} Le nombre total d'itérations dans la boucle.
Exercice
 Reproduire ce tableau permettant d’afficher un tableau de user.
Accès aux Templates
Les Templates doivent se trouver dans l’un des emplacements suivants :
 templates/
 /Resources/views d’un bundle
Afin d’accéder aux Template, une convention de nommage est définit :
Si on est dans vos vues : Dossier/pageTwig
Exemples
index.html.twig // ce fichier se trouve directement dans templates
Si vous voulez accéder à la vue d’un bundle :
@NomBundle/Dossier/pageTwig
Le nom du bundle ne doit pas contenir le mot Bundle
Nommage des pages TWIG
Par convention le nommage des vues dans symfony se fait selon la
convention suivante :
NomPage.FormatFinal.MoteurDeTemplate
Exemple
index.html.twig
Le nom du fichier est index, le format final sera du html et le moteur
de template suivi est le TWIG
Héritage 1- Définition
 Vision proche de l’héritage dans l’orienté objet
Template de base :
Eléments communs
Définition de Bloc

Surdéfinition de blocs

Template Template Template


fils 1 fils 2 fils 3

Template
fils 3.1
Héritage 2 – Exemple de Template père
 Exemple de Template de base
Héritage 3- Syntaxe
Afin d’hériter d’un Template père il faut étendre ce dernier avec la
syntaxe suivante :
{% extends 'TemplateDeBase' %}
Exemple :
{% extends 'base.html.twig' %}
Si le fils ne surcharge aucun des blocs et n’ajoute rien on aura le même
affichage que pour la base
Héritage 4- Le Bloc
L’élément de base de l’héritage est le bloc
Un bloc est définit comme suit : {% block nomBloc%} contenu du
bloc{%endblock%}
Pour changer le contenu de la page il faut sur-définir le bloc cible
 En héritant d’une page et si vous écrivez du code à l’extérieur des
blocs vous aurez le message suivant qui est très explicite.
Héritage 5- Récupérer le contenu d’un
bloc parent
 Pour récupérer le contenu d’un bloc père il suffit d’utiliser la méthode
parent()

Ceci peut être aussi appliqué pour toute la hiérarchie


Exercice
 Aller dans la page base.html.twig
 Ajouter y via Bootstrap une partie header avec un menu.
 Ajouter une partie footer.
 Gérer vos blocs de sorte que vous ayez le maximum de
flexibilité.
 Exemple :
Inclusion de Template
Afin d’inclure un Template ou un fragment de code dans un autre
template on utilise la syntaxe suivante :
{% include 'Dossier/nomTemplate‘ with {'labelParam1':
param1,'labelParam2': param2,... } %}
Le chemin commance par le dossier Template
Exemple :

{{ include('Default/section.html.twig', {'Section': section})


Inclusion de Contrôleur
Que faire si on veut inclure un template dynamique ? Un template des meilleurs
ventes un template des articles les plus vus, les derniers cours postés …
La solution consiste à afficher la valeur de retour de la fonction render qui prend en
paramètres le controlleur à appeler et les attributs qu’il attend de recevoir.
Inclure un contrôleur sans ou avec des paramètres.
Syntaxe :
{{ render(controller(‘StringSyntaxControllerName::function', {'labelParam1':
param1,'labelParam2': param2,... })) }}
Exemple
{{ render(controller(‘App\\Controller\\PersonneController::List', { ‘page': 10 })) }}
Génération de liens avec TWIG
Twig permet de générer des liens à partir des noms de root en utilisant
la fonction path.
Génération de liens paramétrable avec
TWIG
Si le lien contient des paramètres, on garde la même syntaxe de la fonction path et on y ajoute
comme deuxième paramètre un tableau contenant les paramètres passer à la route.
Syntaxe : {{ path('root', { 'param1': param1, 'param2': param2,... }) }}
Génération de liens absolus
Pour générer l’url absolue nous utilisons la fonction url. Elle prend en
paramètre le nom de la root souhaitée. Cet fonctionnalité peut être utile
par exemple si vous envoyer un lien par mail. Ce lien ne peut pas être
relatif sinon il sera traité relativement à la ou il est exécuté et non
relativement à votre serveur.
Syntaxe : {{ url('root') }}
Asset
Pour générer le path d’un fichier (img, css, js,…) nous utilisons la
fonction asset.
Cette fonction permet la portabilité de l’application en permettant une
génération automatique du path du fichier indépendamment de
l’emplacement de l’application.
Exemple :
Si l’application est hébergé directement dans la racine de l’hôte alors le
path des images est /images/nomImg.
Asset
Si l’application est hébergé dans un sous répertoire de l’hôte alors le
path des images est /nomApp/images/nomImg.
Syntaxe :
asset('ressource')
Exemples
<img src="{{ asset('images/logo.png') }}" alt="Symfony!" />
<link href="{{ asset('css/blog.css') }}" rel="stylesheet"
type="text/css" />
Exercice
 Intégrer le template du lien suivant
https://themewagon.com/themes/free-bootstrap-5-admin-template-sb-admin/
Exercice
 Ajouter deux block. Un block Header et un block footer contenant
le header et le footer de votre template.
 Créer deux twig header.html.twig et footer.html.twig.
 Mettez y le code du header et du footer.
 Incluez le header à travers un controller
 Incluez le footer à travers le twig directement
Accéder aux variables globales
A chaque requête, Symfony vous fournit une variables globale app dans votre
Template. Cette variable vous permet d’accéder à plusieurs informations très
utiles.
1. app.session que nous avons vu dans le skill Controller nous permet de
récupérer la session courante. Elle a comme valeur null en cas d’absence de
session.
2. app.user permet de récupérer l’utilisateur courant connecté et null si aucun
utilisateur n’est connecté.
3. app.environment : permet de récupérer l’environnement courant, e.g. dev,
prod, test.
4. app.debug retourne true si on est dans le debug mode false sinon.
Débugger avec dump
Afin de débugger les variables dans votre page TWIG vous pouvez
utiliser la fonction dump.
Exemple :
{% extends "base.html.twig" %}

{% block body %}

{{ dump(app) }}

{% endblock %}
Symfony 6
L’ORM DOCTRINE
AYMEN SELLAOUTI

1
Introduction (1)

2
Introduction (2)
ORM : Object Relation Mapper
Couche d’abstraction
Gérer la persistance des données
Mapper les tables de la base de données relationnelle avec
des objets
Crée l'illusion d'une base de données orientée objet à
partir d'une base de données relationnelle en définissant des
correspondances entre cette base de données et les objets
du langage utilisé.
Propose des méthodes prédéfinies

3
Introduction (3)

 Doctrine : ORM le plus utilisé avec Symfony2


 Associe des classes PHP avec les tables de votre BD (mapping)

4
Fonctionnement de Doctrine
Doctrine utilise deux design pattern objet :
Data Mapper
Unit of Work

5
Data Mapper
C’est la couche entre les objets (entités) et les tables de la base de données.
Dans le cas de PHP elle synchronise les données stockées en base de données avec vos objets PHP.
Elle se charge d’insérer et de mettre à jour les données de la base en se basant sur le contenu des
propriété de votre objet.
Elle peut aussi supprimer des enregistrement de la base de données.
Elle peut aussi hydrater vos objets en utilisant les informations contenues dans la base de données.
Ceci permet d’avoir une abstraction complète de la base de données vu que les objets sont
indépendants du système de stockage. C’est le Data Mapper qui se charge de ca.
Doctrine implémente ce design pattern via l’objet EntityManager.

Patterns of Entreprise Application Architecture

6
Unit of Work
 Afin d’éviter une multitude de petite requêtes envoyé à votre base de données, et
de garder un historique des requetés effectuées au niveau de votre base de données,
Doctrine utilise le design pattern Unit of work.
 Pour une raison de performance et d'intégrité, La synchronisation effectuée par
l'Entity Manager ne se fait pas pour chaque changement avec la base de données.
 Le design pattern Unit of Work permet de gérer l'état des différents objets
hydratés par l'Entity Manager.
 Une transaction est ouverte regroupant l’ensemble des opérations. Le commit de
cette transaction déclenchera l’exécution de l’ensemble de ses requêtes.
 En cas d’échec l’ensemble des requêtes et annulées.

7
Les entités (1)
 Objet PHP
 Les entités représente les objets PHP équivalentes à une table de la
base de données.
 Une entité est généralement composée par les attributs de la tables
ainsi que leurs getters et setters
 Manipulable par l’ORM

8
Les entités (2)
Exemple

9
Configuration des entités
Configuration Externe : YAML, XML, PHP
Configuration Interne : annotations, attributs (php8)
Choix de la configuration ?
Deux Visions :
Pro-Externe
Séparation complète des fonctionnalités spécialement lorsque l’entité est
conséquente
Pro-Interne
Plus facile et agréable de chercher dans un seul fichier l’ensemble des information,
plus de visibilité
10
Mapping : Annotation et attributs des
entités (1)
Rôle : Faire le lien entre les entités et les tables de la base de données
Lien à travers les métadonnées
Remarque : Un seul format par bundle (impossibilité de mélanger)
Syntaxe :
/**
 * les différentes annotations
*/
Remarque : Afin d’utiliser les annotations il faut ajouter :
use Doctrine\ORM\Mapping as ORM;
11
Mapping : Annotation et attributs des entités (2)
Entity
Permet de définir un objet comme une entité
Applicable sur une classe
Placée avant la définition de la classe en PHP
Syntaxe : @ORM\Entity #[ORM\Entity]
Paramètres :
repositoryClass (facultatif). Permet de préciser le namespace complet du repository
qui gère cette entité.
Exemple :
@ORM\Entity(repositoryClass="Rt4\AsBundle\Entity\animalRepository")
#[ORM\Entity(repositoryClass: PersonneRepository::class)]
12
Mapping : Annotation et attributs des entités (3)
Table
Permet de spécifier le nom de la table dans la base de données à associer à
l'entité
Applicable sur une classe et placée avant la définition de la classe en PHP
Facultative sans cette annotation le nom de la table sera automatiquement le
nom de l'entité
Généralement utilisable pour ajouter des préfixes ou pour forcer la première
lettre de la table en minuscule /**
*
#[ORM\Table(‘table’)]
Syntaxe : @ORM\Table() * @ORM\Table(‘animal’)
*
Exemple : @ORM\Entity(repositoryClass="Rt4\AsBundle\Entity\animalRe
pository")
*/
13
Mapping : Annotation et attributs des entités (4)
Column
Permet de définir les caractéristiques de la colonne concernée
Applicable sur un attribut de classe juste avant la définition PHP de l'attribut
concerné.
Syntaxe : @ORM\Column()
Exemple :
/**
#[ORM\Column(type: Types::STRING,length: 255)]
*
* @ORM\Column(param1="valParam1" ,param2="valParam2")
*/

14
Mapping : Annotation et attributs des entités (5)
Les paramètres de Column
Paramètre Valeur par défaut Utilisation
type string Définit le type de colonne comme nous venons de
le voir.
name Nom de l'attribut Définit le nom de la colonne dans la table. Par
défaut, le nom de la colonne est le nom de l'attribut
de l'objet
length 255 Définit la longueur de la colonne (pour les strings).
unique false Définit la colonne comme unique (Exemple :
email).
nullable false Permet à la colonne de contenir des NULL.
precision 0 Définit la précision d'un nombre à virgule(decimal)
scale 0 le nombre de chiffres après la virgule (decimal)

15
Mapping : Annotation et attributs des entités (6)
Les types de Column
Type Doctrine Type SQL Type PHP Utilisation
string VARCHAR string Toutes les chaînes de caractères jusqu'à
255 caractères.
integer INT integer Tous les nombres jusqu'à 2 147 483 647.
smallint SMALLINT integer Tous les nombres jusqu'à 32 767.
bigint BIGINT string Tous les nombres jusqu'à 9 223 372 036
854 775 807.

boolean BOOLEAN boolean Les valeurs booléennes true et false.


decimal DECIMAL double Les nombres à virgule.

16
Mapping : Annotation et attributs des entités (7)
Les types de Column
Type Doctrine Type SQL Type PHP Utilisation
date ou datetime DATETIME objet DateTime Toutes les dates et heures.
time TIME objet DateTime- Toutes les heures.
text CLOB string Les chaînes de caractères de plus de 255 caractères.
object CLOB Type de l'objet stocké Stocke un objet PHP en utilisant serialize/unserialize.
array CLOB array Stocke un tableau PHP en utilisant serialize/unserialize.
float FLOAT double Tous les nombres à virgule.
Attention, fonctionne uniquement sur les serveurs dont
la locale utilise un point comme séparateur.

17
Mapping : Annotation et attributs des entités (8)
Conventions de Nommage
Même s’il reste facultatif, le champs « name » doit être modifié afin de
respecter les conventions de nommage qui diffèrent entre ceux de la
base de données et ceux de la programmation OO.
Les noms de classes sont écrites en « Pascal Case » TheEntity.
Les attributs de classes sont écrites en « camel Case » oneAttribute
Les noms des tables et des colonnes en SQL sont écrites en
minuscules, les mots sont séparés par « _ » one_table, one_column.

18
Gestion de la base de données (1)
Configuration de l’application
Afin de configurer la base de données de l’application il faut renseigner les champs
dans le fichier .env qui est renseigné dans le fichier config/packages/doctrine.yml
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'

# IMPORTANT: You MUST configure your server version,


# either here or in the DATABASE_URL env var (see .env file)
#server_version: '13'
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App 19
Gestion de la base de données (1)
Configuration de l’application

# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
DATABASE_URL="mysql://root:@127.0.0.1:3306/sf1test?serverVersion=10.4.24-MariaDB&charset=utf8mb4"
#DATABASE_URL="postgresql://username:[email protected]:5432/app?serverVersion=10.4.24-MariaDB&charset=utf8"
Gestion de la base de données (2)
Création de base de données
Afin de créer la base de données du projet 2 méthodes sont utilisées :
 Manuelle en utilisant le SGBD (le nom de la BD doit être le même
que celui mentionné dans le fichier doctrine.yml)
 En utilisant la ligne de command avec la command suivante :
 php bin/console doctrine:database:create
symfony console doctrine:database:create
 Une base de données avec les propriétés mentionnées dans .env sera
automatiquement générée

21
Gestion de la base de données (3)
Génération des entités
Deux méthodes pour générer les entités :
 Méthode manuelle (non recommandée)
 Créer la classe
 Ajouter le mapping
 Ajouter les getters et les setters (manuellement ou en utilisant la commande
suivante :
php bin/console make:entity --regenerate App
(elle crée les getters et les setters de toutes les entités)

22
Gestion de la base de données (3)
Génération des entités
Deux méthodes pour générer les entités :
Méthode en utilisant les commandes
Il suffit de lancer la commande suivante :
php bin/console make:entity
symfony console make:entity
 Ajouter les attributs ainsi que les paramètres qui vont avec
 Une fois terminé, Doctrine génère l’entité avec toutes les métadonnées de
mapping

23
Gestion de la base de données
Les migrations
Les migrations sont une nouvelle façon utilisée par Symfony 4 afin de
gérer les mises à jours et évolutions de votre base de données.

Ayant une images des différentes évolutions de votre base de donnée,


vous pouvez annuler des changements ou passer d’une version à une
autre.

24
Gestion de la base de données
Les migrations : les commandes
Pour connaitre l’état de vos fichiers de migrations, vous pouvez utiliser
la commande
php bin/console doctrine:migration:status

25
Gestion de la base de données
Les migrations : les commandes
Créer un fichier de migration
Pour créer un fichier de migration, utilisez la commande :
symfony console doctrine:migration:generate.
Ceci vous créera un fichier de migration vide de tout traitement.
Si vous avez besoin d’écrire votre propre code de migration vous
pouvez le faire.

26
Les migrations
Créer un fichier de migration pour adapter
votre base de données à vos entités
Pour créer un fichier de migration, utilisez la commande :
symfony console doctrine:migration:diff
Vous pouvez aussi utiliser
php bin/console make:migration
Cette commande fait appel à la commande précédente.

27
<?php

//….

final class Version20220920155201 extends AbstractMigration


{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void


{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE personne (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL,
age SMALLINT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}

public function down(Schema $schema): void


{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE personne');
$this->addSql('DROP TABLE test');
$this->addSql('DROP TABLE messenger_messages');
}
}
Migration
Exécuter une migration particulière
Afin d‘exécuter une migration particulière que ce soit la méthode up ou la méthode
down utiliser la méthode suivante :
php bin/console doctrine:migration:execute ‘DoctrineMigrations\numVersion’ –fct

Exemple

symfony console doctrine:migrations:execute --up 'DoctrineMigrations\Version20220920155201'

29
Résumé
:diff [diff] Génères une migration en comparant la base de données avec
les informations de mapping.
:execute [execute] Exécute une migration manuellement.
:generate [generate] Crées une classe de Migration.
:migrate [migrate] Effectues une migration vers le fichier de migration le
plus récent ou celui spécifié.
:status [status] Affiche le status des migrations.
:version [version] Ajoute et supprime manuellement des versions à partir
de la version en en base.
30
Exercice
Créer votre base de données à travers la ligne de commande.
Générer une Entité Personne.
Cette entité contient un attribut id, un attribut nom, prenom, age, cin
et path.
Doctrine

Les opérations de persistance Read


Read Repository (commun)
de la BD Select
Update ReadSelect
Delete Select
Insert Repository
Repository
Entity Manager
Repository

Doctrine
Le service Doctrine
 Rôle : permet la gestion des données dans la BD : persistance des données et consultation des données.

Avant Symfony 6 A partir de Symfony 6


Méthode : Doctrine n’est plus accessible via les helpers.
 $this->get(‘doctrine’); Vous devez l’injecter via la classe ManagerRegistry
en le spécifiant au niveau méthode ou au niveau
 $this->getDoctrine(); //helper (raccourcie de la constructeur.
classe Controller)
Le service Doctrine offre deux services pour la gestion
d’une base de données : public function index(ManagerRegistry $doctrine): Response {
}
 Le Repository qui se charge des requêtes Select
public function __construct(private ManagerRegistry $doctrine)
L’EntityManager qui se charge de persister la base de
données donc de gérer les requêtes INSERT, UPDATE {}
et DELETE.

33
Le service EntityManager
Rôle : L’interface ORM proposée par doctrine offrant des méthodes
prédéfini pour persister dans la base ou pour mettre à jour ou supprimer
une entité.
Méthode :
 $EntityManager = $this->get(‘doctrineorm.entity_manager’)
 $doctrine->getManager();
 L’injecter en tant que service (à voir dans la partie service)

34
Le service EntityManager
Insertion des données
Enregistrement des données
Etant un ORM, Doctrine traite les objets PHP
Pour enregistrer des données dans la BD il faut préparer les objets contenant ces
données la
La méthode persist() de l’enityManager permet d’associer les objets à persister avec
Doctrine
Afin d’exécuter les requêtes sur la BD (enregistrer les données dans la base) il faut
utiliser la méthode flush()
L’utilisation de flush permet de profiter de la force de Doctrine qui utilise les
Transactions
La persistance agit de la même façon avec l’ajout (insert) ou la mise à jour (update)
35
Exercice
Créer un contrôleur PersonneController
Créer une action qui permet l’ajout d’une Personne au niveau de la base de
données.
Les données seront introduites via la route.
Une fois la personne ajoutée, une page contenant ses informations sera affichée.
Faite de même pour la mise à jour, faite en sorte que cette action prenne l’id de la
personne à modifier et les nouvelles valeurs.
Le service EntityManager
Suppression d’une entité
Suppression d’une entité
La méthode remove() permet de supprimer une entité

37
Exercice
Créer une action qui permet la suppression d’une personne en utilisant
son id.
Si la personne n’existe pas un message d’erreur est affiché
Une petite parenthèse : Fixtures
Les fixtures sont utilisées pour charger des données « fake » au sein de
votre base de données pour tester les fonctionnalités que vous avez
développé.
Installer le bundle responsable des Fixtures.
composer require --dev orm-fixtures
Créer une classe VotreEntitéFixture à l’aide de la commande :
symfony console make:fixtures

https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html 39
Une petite parenthèse : Fixtures
Implémenter la méthode load avec le fonctionnement que vous voulez
pour charger vos données.
Lancer vos fixtures : php bin/console doctrine:fixtures:load, cette
commande effacera le contenu de votre Base de données.
Si vous voulez garder la base ajouter l’option –append
php bin/console doctrine:fixtures:load --append

https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html 40
Fixture exemple
<?php

namespace App\DataFixtures;

use App\Entity\Personne;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;

class PersonneFixtures extends Fixture


{
public function load(ObjectManager $manager)
{
for($i=0; $i<10; $i++) {
$personne = new Personne();
$personne->setAge(mt_rand(20, 80));
$personne->setName("personne $i");
$personne->setJob("Job $i");
$personne->setDesignation("Designation $i");
$manager->persist($personne);
}

$manager->flush();
}
} 41
Exercice
Créer un fixture permettant d’ajouter quelques personnes dans la base
de données.

Vous pouvez utiliser le composant faker

https://fakerphp.github.io/

composer require fakerphp/faker


Le Repository
Les repositories (dépôts)
Des classes PHP dont le rôle est de permettre à l’utilisateur de
récupérer des entités d’une classe donnée.
Syntaxe :
Pour accéder au repositorie de la classe Maclasse on utilise Doctrine ou
on l’injecte (voir dans la partie Service)
$repo = $doctrine->getRepository(ClassName::class);

43
Le Repository
Quelque méthodes offertes par le repository :
$repository->findAll(); // récupère tous les entités (enregistrements) relatifs
à l’entité associé au repository
$repository->find($id);// requête sur la clé primaire
$repository->findBy();//retourne un ensemble d’entités avec un filtrage sur
plusieurs critères (nbre donné)
$repository->findOneBy();//même principe que findBy mais une seule
entité
$repository->findByNomPropriété();
$repository->findOneByNomPropriété();
44
Le Repository
findAll
findAll()
Rôle : retourne l’ensemble des entités qui correspondent à l’entité associé au
repositorie. Le format du retour est un Array
Exemple :
//On récupère le repositorie de l’entity manager correspondant à l’entité Etudiant
$repository = $doctrine->getRepository(ClassName::class) ;
//On récupère la liste des étudiants
$listAdverts = $repository->findAll();
Généralement le tableau obtenu est passé à la vue (TWIG) et est affiché en
utilisant un foreach
45
Exercice
Créer une page list.html.twig
Faite en sorte que cette page affiche la liste des personnes de votre base de
données.
Le Repository
find
find($id)
Rôle : retourne l’entité qui correspond à la clé primaire passé en
argument. Généralement cette clé est l’id.
Exemple :
//On récupère le repository de l’entity manager correspondant à
l’entité Etudiant
$repo = $doctrine->getRepository(Etudiant::class);
//on lance la requéte sur l’étudiant d’id 2
$etudiant = $repository->find(2);
47
Exercice
Créer une page profil.html.twig
Faite en sorte que cette page affiche le profil d’une personne selon son
id.
Le Repository
findBy
findBy()
Rôle : retourne l’ensemble des entités qui correspondent à l’entité associé au
repositorie comme findAll sauf qu’elle permet d’effectuer un filtrage sur un
ensemble de critère passés dans un Array. Elle offre la possibilité de trier les entités
sélectionnées et facilite la pagination en offrant un nombre de valuer de retour.
Synatxe: $repository->findBy( array $criteria, array $orderBy = null, $limit = null,
$offset = null);
Exemple : $repository = $doctrine->getRepository(Etudiant::class);
$listeEtudiants = $repository->findBy(array('section' => 'RT4','nom' =>
'Mohamed'), array('date' => 'desc'),10, 0);

49
Exercice
Créer une méthode qui permet d’afficher la liste des personnes d’un
nom donnée ordonnée par prénom.
Le nombre maximum de résultat à afficher est de 5.
Le Repository
findOneBy
findOneBy()
Rôle : Même principe ue FindBy mais en retournant une seule entité ce
qui élimine automatiquement les paramètres d’ordre de limite et d’offset
Exemple :
$repository = $doctrine->getRepository(Etudiant::class);
$Etud = $repository->findOneBy(
array('section' => 'RT4','nom' => 'Mohamed')
);

51
Le Repository
findByPropriété
findByPropriété()
Rôle : En remplaçant le mot Propriété par le nom d’une des propriété
de l’entité, la fonction va faire le même rôle que findBy mais avec un
seul critère qui est le nom de la propriété et sans les options.

Exemple :
$repository = $doctrine->getRepository(Etudiant::class);
$listeEtudiants = $repository->findByNom(‘Aymen’);

52
Le Repository
findOneByPropriété
findOneByPropriété()
Rôle : En remplaçant le mot Propriété par le nom d’une des propriété
de l’entité, la fonction va faire le même rôle que findOneBy mais avec
un seul critère.

Exemple :
$repository = $doctrine->getRepository(Etudiant::class);
$listeEtudiants = $repository->findOneByNom(‘Aymen’);

53
Le Repository
Création de requêtes
Les requêtes de doctrine sont écrites en utilisant le langage de doctrine
le Doctrine Query Lanquage DQL ou en utilisant un Objet créateur de
requêtes le CreateQueryBuilder
createQuery : Méthode de l’Entity Manager
CreateQueryBuilder : Méthode du repositorie

DQL
Classes + Propriétés
~ SQL
Tables + colonnes

https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository 54
Le Repository
CreateQuery et DQL
Le DQL peut être défini comme une adaptation du SQL adapté à
l’orienté objet et donc à DOCTRINE
La requête est défini sous forme d’une chaine de caractère
Afin de créer une requête DQL il faut utiliser la méthode
createQuery() de l’EntityManager
La méthode setParameter(‘label’,’valeur’) permet de définir un
paramètre de la requête

55
Le Repository
CreateQuery et DQL
Pour définir plusieurs paramètres ou bien utiliser setParameter
plusieurs fois ou bien la méthode setParameters(array(‘label1’,’valeur1’,
‘label2’,’valeur2’),.. ‘labelN’,’valeurN’))
Une fois la requête créée la méthode getResult() permet de récupérer
un tableau de résultat
Le langage DQL est explicité dans le lien suivant :
http://docs.doctrine-project.org/projects/doctrine-
orm/en/latest/reference/dql-doctrine-query-language.html

56
Le Repository : Création de requêtes
createQuery
public function findPersonneByIntervalAge2($min, $max)
{
$query = $this->_em->createQuery(
'SELECT p
FROM App\Entity\Personne p
WHERE p.age >= :ageMin And p.age <= :ageMax
ORDER BY p.age
ASC'
)
->setParameter('ageMin', $min)
->setParameter('ageMax', $max)
;
return $query->execute();
}

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/dql-doctrine-query-language.html 57
Le Repository
QueryBuilder
Constructeur de requête DOCTRINE Alternative au DQL
Accessible via le Repositorie
Le résultat fourni par la méthode getQuery du QueryBuiler permet de
générer la requête en DQL
De même que le createQuery, une fois la requête créée la méthode
getResult() permet de récupérer un tableau de résultat.

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html 58
Le Repository
QueryBuilder
 Afin de récupérer le QueryBuilder dans notre Repository, on utilise la méthode
createQueryBuilder.
 Cette méthode récupère en paramètre l’allias de l’entité cible et offre la requête
« select from » de l’entité en question.
 Généralement l’allias est la première lettre en minuscule du nom de l’entité
 Si aucun paramètre n’est passé a createQueryBuilder alors on aura une requête vide et
il faudra tout construire.
$qb=$this->_em->createQueryBuilder()
->select('t')
->from($this->_entityName,'alias');

$qb=$this->createQueryBuilder(‘t’)
59
Le Repository
QueryBuilder : Méthodes
from(‘entityName’,’entityAlias’)
from($this->_entityName,’t’)
where(‘condition’) permet d’ajouter le where dans la
requête
where(‘t.destination= :dest‘)
setParameter(‘nomParam’,param) permet d’ajouter la
définition d’un des paramètres définis dans le where
setParameter(‘dest’,$dest)

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html 60
Le Repository
QueryBuilder : Méthodes
andWhere(‘condition’) permet d’ajouter d’autres conditions
andWhere(‘t.statut = :status)
orderBy(‘nomChamp’,’ordre’) permet d’ajouter un orderBy et
prend en paramètre le champ à ordonner et l’ordre DESC ou
ASC.
orderBy(‘t.dateTransfert’,’DESC’)
 setParameters(array(1=>’param1’,2=>’param2’))

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html 61
Le Repository
QueryBuilder : Méthodes
orWhere
groupBy
having
andHaving
orHaving
leftJoin
rightJoin
Join
innerJoin
…

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html 62
Le Repository
QueryBuilder : Méthodes
getQuery() : retourne la requête dql
getResult() : retourne un tableau d’objets contenant le résultat
getOneOrNullResult() : retourne le premier résultat ou Null
getSingleScalarResult() : retourne un résultat sus format scalaire.
Imaginer le use case ou vous voulez récupérer le COUNT ou la SUM
d’un de vos objets.

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html 63
Requêter des attributs spécifiques
Afin de sélectionner des propriétés particulières utiliser la méthode
select du queryBuilder
Syntaxe :
->select('SUM(u.age) as sumAge, AVG(u.age) as
avgUserAge')

64
Réutilisation de la logique de vos requêtes
Imaginer les uses cases suivants :
Vous voulez sélectionner les formations d’un topic donné.
Vous voulez sélectionner les formations d’un topic donné dont le nombre
d’inscrits est inférieur à un nombre données.
Vous voulez sélectionner les formations d’un topic donné dont le nombre
d’inscrits est supérieur à un nombre données.
Vous voulez sélectionner les formations d’un topic donné entre deux dates …
On remarque ici une redondance dans ces différentes requêtes.
L’idée est donc d’isoler ce traitements redondant dans une méthode et de la
réutiliser.

65
/**
* @param $min
* @param $max
* @return mixed
*/
public function getPersonneByAge($min, $max) {

$qb = $this->createQueryBuilder('p');
$qb = $this->findByAge($qb, $min, $max);
return $qb->getQuery()->getResult();
}

/**
* @param QueryBuilder $qb
* @param $min
* @param $max
* @return QueryBuilder
*/
private function findByAge(QueryBuilder $qb, $min, $max) {
if($min) {
$qb->andWhere('p.age > :minAge')
->setParameter('minAge', $min);
}
if($max) {
$qb->andWhere('p.age < :maxAge')
->setParameter('maxAge', $max);
}
return $qb;
}
66
public function getCommunesByZipCode($zipCode = null, $like = null,
$type = null) {
$qb = $this->createQueryBuilder('l')
->select('l.id, l.name, l.zipCode')
->where('1=1');

if ($zipCode) {
$qb = $qb->andWhere('l.zipCode = :zipCode ')
->setParameter('zipCode', $zipCode);
}

if ($like) {
$qb = $qb->andWhere('l.name like :like ')
->setParameter('like', "%$like%");
}

return $qb->getQuery()->getArrayResult();
}
Gestion des relations entre les entités (1)
Les types de relation
Les entités de la BD présentent des relations d’association :

 A OneToOne B : à une entité A on associe une entité de B et


inversement
 A ManyToOne B : à une entité B on associe plusieurs entité de A et à
une entité de A on associe une entité de B
 A ManyToMany B : à une entité de A on associe plusieurs entité de B
et inversement

68
Gestion des relations entre les entités (2)
Relation unidirectionnelle et bidirectionnelle
 La notion de navigabilité de UML est la source de la notion de relation
unidirectionnelle ou bidirectionnelle
 Une relation est dite navigable dans les deux sens si les deux entité doivent avoir
une trace de la relation.
 Exemple : Supposons que nous avons les deux classes CandidatPresidentielle et
Electeur.
 L’électeur doit savoir à qui il a voté donc il doit sauvegarder cette information par
contre le candidat pour cause d’anonymat de vote ne doit pas connaitre les
personnes qui ont voté pour lui.
 On aura donc un attribut Candidat dans la table Electeur mais pas de collection ou
tableau nommé électeur dans la table CandidatPresidentielle. Ici on a une relation
unidirectionnelle.
69
Création de la relation
Vous pouvez créer votre relation via la console.
Créer un attribut et mettez y comme type « relation ».
Ceci va générer un attribut annoté avec la relation et les informations
minimalistes nécessaires pour sa création.
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Hobbies",inversedBy="personnes")
*/
private $hobbies;

70
Gestion des relations entre les entités (3)
OneToOne unidirectionnelle
 Relation unidirectionnelle //**Entity **//
Class Etudiant
puisque Media ne référence pas {
Etudiant // …
/**
* @ORM\OneToOne(targetEntity=
targetEntity="App\Entity\Media"
)
*/
private $media;
// …
}
//**Entity **//
Class Etudiant
{
// …
}

71
Gestion des relations entre les entités (4)
OneToOne Bidirectionnelle
Si nous voulons qu’à partir du //**Entity **//
Class Etudiant
media on peut directement {
// …
savoir à quel étudiant il /**
* @ORM\OneToOne(targetEntity= "App\Entity\Media")
appartient nous devons faire */
private $media;
une relation bidirectionnelle // …
}
Media aussi doit référencer //**Entity **//
Class Media
Etudiant {
/**
* @ORM\OneToOne(targetEntity=
"App\Entity\Etudiant",mappedBy="media")
*/
private $etudiant;
// …
}

72
Gestion des relations entre les entités (5)
ManyToOne Unidirectionnelle
 Relation unidirectionnelle //**Entity **//
Class Etudiant
puisque Section ne référence {
// …
pas Etudiant /**
* @ORM\ManyToOne(targetEntity="App\Entity\Section")
*/
private $section;
// …
}
//**Entity **//
Class Section
{
// …
}

73
Gestion des relations entre les entités (6)
OneToMany Bidirectionnelle
//**Entity **//
Si nous voulons connaitre dans l’objet section Class Section
{
l’ensemble des étudiants qui lui sont affectés alors // …
on doit avoir une relation bidirectionnelle /**
*@ORM\OneToMany(targetEntity="App\Entity\Etudiant",
 Section aussi doit référencer Etudiant *mappedBy="section")
*/
private $etudiants;
 On aura une relation OneToMany coté Section // …
public fonction __construct() {
puisqu’à « One » Section on a « Many » Etudiants. $this->etudiants = new ArrayCollection () ;
}
 On doit ajouter l’attribut mappedBy côté }//**Entity **//
OneToMany et inversedBy côté ManyToOne Class Etudiant
{ //…
/**
 On doit spécifier dans le constructeur du * @ORM\ManyToOne(targetEntity="App\Entity\Section",
OneToMany que l’attribut mappé est de type inversedBy="etudiants")
*/
ArrayCollection en l’instanciant private $section;
// …
}
74
Gestion des relations entre les entités (7)
ManyToMany
//**Entity **//
 Relation unidirectionnelle Class Matiere
puisque Cours ne référence pas {
// …
Prof }
//**Prof**//
Class Etudiant
 Ici on peut savoir quels sont { //…
/**
les cours de chaque étudiant * @ORM\ManyToMany(targetEntity="App\Entity\Matiere"")
mais pas l’inverse (on peut */
private $cours ;
l’extraire via une requête) /…
/**
* Constructor
*/
public function __construct()
{
$this->matieres = new
\Doctrine\Common\Collections\ArrayCollection();
}
75 }
Gestion des relations entre les entités (8)
ManyToMany Bidirectionnelle
On doit spécifier dans les deux constructeurs que l’attribut mappé est
de type ArrayCollection en l’instanciant

Même chose que la bidirectionnelle OneToMany en ajoutant les


mappedBy et inversedBy

 Cette relation peut être traduite à deux relation


OneToMany/ManyToOne entre les 3 classes participantes.

76
Gestion des relations entre les entités (9)
Cas particulier ManyToMany
Etudiant Cours
* *

Transformation

Etudiant Cours_Etudiant Cours


1 1
* *
Date

77
Exercice
Créer les entités suivantes ainsi que les relations qui les relient :
Job
Personne Personne
* designation
Job firstname description
name 1
Hobby age
*

Créer les fixtures pour les entités Hobby, Job et Profile. *


Hobby
designation
Détour : les Traits
 Servent à externaliser du code redondant dans plusieurs classes différentes.
 Pourquoi les traits et non l’héritage ? Parce que PHP ne supporte pas l’héritage multiple.
 Non instanciable
 Un trait peut contenir des méthodes et des attributs
 Syntaxe :
Trait nomTrait{
public $x;
Function fct1(){
}
Function fct2(){
}
}

79
Les événements de Doctrine (1)
 Appelé aussi les callbacks du cycle de vie, ce sont des méthodes à exécuter par doctrine et dépendant
d’événement précis :
PrePersisit
PostPersist ( s’exécute après le $em->flush() non après $em->persist() )
PreUpdate
PostUpdate
/**
PreRemove
* Transfer
PostRemove
*
* @ORM\Table(name="transfer")
Afin d’informer doctrine qu’une entité contient des
*
clallbacks nous devons utiliser l’annotation @ORM\Entity(repositoryClass="AppBundle\
@ORM\HasLifecycleCallbacks() Repository\TransferRepository")
Ceci ne s’applique que lors de l’utilisation * @ORM\HasLifecycleCallbacks()
des annotations */
class Transfer

80
Les événements de Doctrine (2)
 Pour informer Doctrine de l’existence d’un événement on utilise maintenant l’annotation sur
l’action à réaliser.

/**
* @PrePersist
*/
public function onPersist(){
$this->createdAt = new \DateTime('NOW');
}

81
Les traits et Les événements de Doctrine
 Imaginons maintenant que nous voulons « sécuriser plusieurs de nos entités » et d’avoir un peu
d’historique. L’idée est d’avoir deux attributs qui sont createdAt et modifiedAt pour avoir toujours
une idée sur la création de notre entité et de sa dernière modification.
 L’idée est de créer pour chacune des entités à suivre des lifecycle callback qui vont mettre à jour ces
deux attributs lors de la création (prePersisit) et la modification (preUpdate).
 Est-ce normal de le refaire pour toutes les entités ?
 Si la réponse est non, que faire alors ?

Les traits

82
Exercice
Créer le Trait qui permet la gestion de la date d’ajout et de modification d’une entité.
Associer le avec l’entité formation
Tester le
Symfony
Les formulaires
AYMEN SELLAOUTI

1
Introduction
 Rôle très important dans le web

 Vitrine, interface entre les visiteurs du site web et le contenu du site

 Généralement traité en utilisant du html <form> … </form>

 Symfony et les formulaires : le composant Form

 Bibliothèque dédiée aux formulaires

2
Qu’est ce qu’un formulaire Symfony
La philosophie de Symfony pour les formulaires est la suivante :
Vision 1
 Un formulaire est l’image d’un objet existant
 Le formulaire sert à alimenter cet objet.
Classe Exemple
{ Nom
private $id;
private $nom; Age
private $age;
}

Vision 2
 Un formulaire sert à récupérer des informations indépendantes de n’importe quel objet.
3
Comment créer un formulaire
Méthodes de création de formulaire
La création du formulaire se fait de 2 façons différentes :

1) Dans le contrôleur qui va utiliser le formulaire

2) En externalisant la définition dans un fichier

4
Comment créer un formulaire
FormBuilder
La création d’un formulaire se fait à travers le Constructeur de
formulaire FormBuilder
Exemple :
$monPremierFormulaire= $this->createFormBuilder($objetImage)
Pour indiquer les champs à ajouter au formulaire on utilise la méthode
add du FromBuilder

http://symfony.com/doc/current/reference/forms/types.html 5
Comment créer un formulaire
FormBuilder
La méthode add contient 3 paramètres :
1) le nom du champ dans le formulaire
2) le type du champ
3) un array qui contient des options spécifiques au type du champ
Exemple :
$monPremierFormulaire= $this->createFormBuilder($exemple)
->add(‘nom’ ,TextType::class)
->add(‘age’ , IntegerType::class)
6
Comment créer un formulaire
Récupérer le formulaire avec getForm()
Pour récupérer le formulaire crée, il faut utiliser la méthode getForm()

Exemple :
$monPremierFormulaire= $this->createFormBuilder($exemple)
->add(‘nom’ ,TextType::class)
->add(‘age’ , IntegerType::class)
->getForm();

7
Externalisation de la définition des formulaires
AbstractType
Afin de rendre les formulaires réutilisables, Symfony permet l’externalisation
des formulaires en des objets.
 Convention de nommage : L’objet du formulaire doit être nommé comme
suit NomObjetType
 Cet objet doit obligatoirement étendre la classe AbstractType
 Deux méthodes doivent obligatoirement être implémentées :
 buildForm(FormBuilderInterface $builder, array $options) qui est la
méthode qui va permettre la création et la définition du formulaire
 Il y a aussi la méthode configureOptions qui permet de définir l’objet
associé au formulaire. Cette fonction est obligatoire si vous voulez associer
votre form à une classe.
8
Externalisation de la définition des formulaires
Commande de génération de formulaire
Maker permet aussi d’automatiquement générer la classe du formulaire
php bin/console make:form FormNameType
symfony console make:form FormNameType
Exemple :
symfony console make:form PersonneType

9
Externalisation de la définition des formulaires
Commande de génération de formulaire

10
Externalisation de la définition des formulaires
Commande de génération de formulaire
Maker vous demandera si votre formulaire est associé à une entité ou
non. Répondez selon votre besoin.
La récupération du formulaire au niveau des contrôleurs devient
beaucoup plus facile :
$form = $this->createForm(TacheType::class, $entity);
Le second parameter n’est pas obligatoire

11
Affichage du formulaire dans TWIG
CreateView
Afin d’afficher le formulaire crée, il faut transmettre la vue de ce
formulaire à la page Twig qui doit l’accueillir.
La méthode createView de l’objet Form permet de créer cette vue
Il ne reste plus qu’à l’envoyer à la page twig en question
Exemple :
$form= $this->createForm (ExempleType::class,$exemple) );
return $this->render('Rt4AsBundle:Default:myform.html.twig',
array('form'=>$form->createView()));

12
Affichage du formulaire dans TWIG
form
Deux méthodes permettent d’afficher le formulaire dans Twig :
1) Afficher directement la totalité du formulaire avec la méthode form
{{ form(nomDuFormulaire) }}

2) Afficher les composants du formulaire séparément un à un (


généralement lorsqu’on veut personnaliser les différents champs)

13
Customiser vos Form avec Bootstrap
Afin d’intégrer directement bootstrap sur vos formulair, il suffit de :
Spécifier à symfony dans le fichier twig.yml que vous voulez du
Bootstrap pour vos formes.
Informer la Twig qui contient vos formulaire qu’elle doit utiliser ce
thème la
twig:
default_path: '%kernel.project_dir%/templates'
form_themes: ['bootstrap_5_layout.html.twig']
14
Récupérer les données envoyées
La gestion de la soumission des formulaires se fait à l’aide de la
méthode handleRequest($request)
HandleRequest vérifie si la requête est de type POST. Si c’est le cas,
elle va mapper les données du formulaire avec l’objet affecté au
formulaire en utilisant les setters de cet objet. Si aucun objet n’est
mappé, vous pouvez récupérer directement ces données.
Cette fonction prend en paramètre la requête HTTP de l’utilisateur
qui est encapsulé dans Symfony au sein d’un objet de la classe Request
de HttpFoundation.

15
Récupérer les données envoyées
Vous pouvez récupérer les données envoyées via votre formulaire en
accédant au champ via la méthode getData() de l’objet form.
Exemple : $form->getData() retourne un tableau associatif avec les
données envoyées par le formulaire.
Chaque élément aura comme clé le contenu de l’attribut name dans le
formulaire. public function showFormAction(Request $request) {
$form->handleRequest($request);
if ($form->isSubmitted() ){
$data = $form->getData();
// ToDo
}
} 16
Exercice
Récupérer les données envoyées à travers le formulaire et afficher le résultat.
Affichage du formulaire dans TWIG
Les composants du formulaire
form_start() affiche la balise d'ouverture du formulaire HTML, soit
<form>. Il faut passer la variable du formulaire en premier argument, et les
paramètres en deuxième argument. L'index attr des paramètres, et cela
s'appliquera à toutes les fonctions suivantes, représente les attributs à
ajouter à la balise générée, ici le <form>. Il nous permet d'appliquer une
classe CSS au formulaire, ici form-horizontal.
Exemple : {{ form_start(form, {'attr': {'class': 'form-horizental'}}) }}
form_errors() affiche les erreurs attachées au champ donné en argument.
form_label() affiche le label HTML du champ donné en argument. Le
deuxième argument est le contenu du label.
18
Affichage du formulaire dans TWIG (3)
Les composants du formulaire (2)
form_widget() affiche le champ HTML
Exemple : {{ form_widget(form.title, {'attr': {'class': 'form-control'}}) }}
form_row() affiche le label, les erreurs et le champ.
form_rest() affiche tous les champs manquants du formulaire.
form_end() affiche la balise de fermeture du formulaire HTML
Remarque : Certains types de champ ont des options d'affichage
supplémentaires qui peuvent être passées au widget. Ces options sont
documentées avec chaque type, mais l'option attr est commune à tous les
types et vous permet de modifier les attributs d'un élément de formulaire.
19
Exercice
Reprenez le formulaire que vous avez crée et changer le en décortiquant
chaque champs.
Passer une URL à l’objet du formulaire
Ne pouvons pas accéder dans la classe AbstractType à la méthode
generateUrl afin de modifier l’action du formulaire, il faut donc procéder
ainsi :
 Utiliser le troisième paramètre de la méthode createForm. C’est un
tableau associatif contenant un ensemble d’option. On peut y ajouter deux
clé :
 action : pour ajouter l’url de l’action
 method : si vous voulez modifier l’attribut method qui est par défaut à post.

$form = $this->createForm(FakeFormType::class, null ,array(


'action' => $this->generateUrl('personne.add'),
'method' => 'GET'
)); 21
Les propriétés d’un champ dans le
formulaire
Le troisième paramètre de la méthode add est un tableau
d’options pour les attributs du formulaire
Parmi les options communes à la majorité des champs nous
citons :
label : pour le label du champ si cette option n’est pas mentionné
alors le label sera le nom du champ
required : Permet de dire si le champ est obligatoire ou non (Par
défaut l’option required est défini à true)

22
Les principaux types dans le formulaire
Liste des types
 Les formulaires sont composés d’un ensemble de champs
 Chaque champ possède un nom, un type et des options
 Symfony propose une grande panoplie de types de champ
Texte Choix Date et temps Divers Multiple Caché
TextType ChoiceType DateType CheckboxType CollectionTyp HiddenType
TextareaType EntityType DatetimeType FileType e CsrfType
EmailType CountryType TimeType RadioType RepeatedType
IntegerType LanguageType BirthdayType
MoneyType LocaleType
NumberType TimezoneType
PasswordType CurrencyType
PercentType
SearchType
http://symfony.com/doc/current/forms.html
RangeType… 23
Les principaux types dans le formulaire
Le type choice
Type spécifique aux champs optionnels (select,
boutons radio, checkboxs)
Pour spécifier le type d’options qu’on veut avoir il
faut utiliser le paramètre expanded. S’il est à false
(valeur par défaut) alors nous aurons une liste Expanded=true
déroulante. S’il est à true alors nous aurons des
boutons radio ou des checkbox qui dépendra du
paramètre multiple
Exemple :
http://symfony.com/doc/current/reference/forms/types/choice.html Expanded=false

24
Les principaux types dans le formulaire
Le type Entity
Champ choice spécial
Les choices (les options) seront chargés à partir des éléments d’une
entité Doctrine
->add('emploi',EntityType::class, array(
'class' => 'Tekup\BdBundle\Entity\Emploi',
'choice_label'=>'designation',
'expanded'=>false,
'multiple'=>true)
)

http://symfony.com/doc/current/reference/forms/types/entity.html

25
Personnaliser le choice label
Afin de personnaliser ce que vous voulez afficher dans vos choix, vous avez deux
solutions :
1. Définir la méthode magique to_string de votre entité, c’est la méthode appelé
par défaut en cas d’absence d’une information sur ce qu’il faut afficher.
2. Affecter à la propriété choice_label une callback function qui retournera la
chaine à afficher pour chaque enregistrement. Elle prendra en paramètre
l’instance de l’entité à traiter.
->add('formateur', EntityType::class, array(
'choice_label' => function(Formateur $formateur){
return (
sprintf( %s-%s", $formateur->getName(),
$formateur->getField())
);
})
26
EntityType query_builder
Afin de customiser la liste de choix de l’utilisateur vous pouvez utilisé
la propriété query_builder
$builder->add('users', EntityType::class, [
'class' => User::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.username', 'ASC');
},
'choice_label' => 'username',
]);

27
Exercice
Créer une méthode permettant d’ajouter une personne à travers le
formulaire.
Les principaux types dans le formulaire (4)
Le type country
Affiche la liste des pays du monde
La langue d’affichage est celle de la locale de votre
application (config.yml)
Exemple

->add('pays',CountryType::class)

http://symfony.com/doc/current/reference/forms/types/country.html

29
Ne pas afficher un champs du formulaire
Dans certains cas, vous n’avez pas envie d’afficher un champs de
votre entité. Prenons l’exemple de l’état. Par défaut et lorsque vous créer
une formation, vous voulez qu’elle soit active. Ce n’est pas un choix
dépendant du créateur.
Votre objet form contient une méthode remove (l’opposé de add) qui
permet de supprimer un champs.
Pensez à ajouter une valeur au champs supprimé ou bien ajouter une
valeur initiale au niveau de l’entité à cet attribut.

30
Les principaux types dans le formulaire (4)
Le type file
 Le type file permet l’upload de n’importe quel type de fichier.
 Créer un champ de ce type dans votre form et mettez l’option mapped à false.
 Le champ permet de récupérer un objet de type uploadedFile contenant le path de
l’objet à uploader
Afin de récupérer ce champs utiliser votre objet form et accéder au paramètre
ayant le même nom que votre propriété. Ensuite via la méthode getData récupérer
votre objet. Exemple pour une propriété image : $monImage = $form[‘image']-
>getData();
Pour pouvoir gérer cet objet il faut le copier dans le répertoire web de votre projet
et de préférence dans un dossier spécifique pour vos images ou vos upload.

http://symfony.com/doc/current/reference/forms/types/file.html 31
Les principaux types dans le formulaire (4)
Le type file
 Attribuer un nom unique à votre fichier pour ne pas avoir de problème lors de l’ajout de
fichier ayant le même nom (vous pouvez utiliser la méthode suivante md5(uiniqueid());
 Pour récupérer le nom de votre file utiliser getClientOriginalName()
 Pour récupérer l’extension vous pouvez utiliser la méthode guessExtension de votre objet
file.
 Pour déplacer votre fichier utiliser la méthode move($pathsrc,$pathdest) de votre objet
file.
 __DIR__ vous donne le path de l’endroit ou vous l’utilisez.
 Vous pouvez créer un paramètre dans services.yml afin d’y stocker le path de votre dossier
et le récupérer dans le Controller avec la méthode getParameter(‘nom du paramètre’);
 Remarque : %kernel.root_dir% vous permet de récupérer le path du dossier app

http://symfony.com/doc/current/reference/forms/types/file.html 32
Le type file
/** @var UploadedFile $file */
$file = $form->get('file')->getData();
if ($file) {
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
// this is needed to safely include the file name as part of the URL
$safeFilename = $slugger->slug($originalFilename);
$newFilename = $safeFilename . '-' . uniqid() . '.' . $file->guessExtension();
// Move the file to the directory where brochures are stored
try {
$file->move(
$this->getParameter('upload_directory'),
$newFilename
);
} catch (FileException $e) {
// ... handle exception if something happens during file upload
}
} parameters:
upload_directory: '%kernel.project_dir%/public/uploads'
https://symfony.com/doc/current/controller/upload_file.html 33
Exercice
 Ajoutez un champs image pour
l’entité Personne et mettez en place le
mécanisme d’upload de l’image.
Exercice
Ajouter la fonctionnalité de mise à jour d’une personne.
Les validateurs
Définition
Le validateur est conçu pour valider les objets selon des contraintes.
Le validateur de symfony est utilisé pour attribuer des contraintes sur les formulaires.
La validation peut être faite de plusieurs façons :
YAML (dans le fichier validation.yml dans le dossier /Resources/config du Bundle en question)
Annotations sur l’entité de base du formulaire
XML
PHP
La méthode isValide() du FORM déclenche le processus de validation
http://symfony.com/doc/current/reference/constraints.html

36
Exemple Validateur
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table(name="personne")
*/
class Personne
{
/**
* @var int
* @ORM\Column(name="id", type="integer") Ici nous indiquons à Symfony qu’il
* @ORM\Id ne faut accepter que les fichiers
* @ORM\GeneratedValue(strategy="AUTO") dont le type est pdf
*/
private $id;
/**
* @Assert\File(mimeTypes = {"application/pdf"})
* @ORM\Column(name="path", type="string")
*/
// …
}
37
Les validateurs : Les annotations
Afin de pouvoir utiliser les annotations de validation il faut importer la class Constraints
use Symfony\Component\Validator\Constraints as Assert;
Syntaxe :
@Assert\MaContrainte(option1="valeur1", option2="valeur2", …)
Exemples :
@Assert\NotBlank( message = " Ce champ ne doit pas être vide ")
@Assert\Length(min=4, message="Le login doit contenir au moins {{ limit }} caractères.")
@Assert\Url()

38
Enlever la validation HTML
Afin d’enlever la validation html ajouter le mot clé novalidate à votre form

{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}


{{ form_widget(form) }}
{{ form_end(form) }}

39
Les annotations : Les contraintes de base
Contrainte Rôle Options
NotBlank La contrainte NotBlank vérifie que la -
Blank valeur soumise n'est ni une chaîne de
caractères vide, ni NULL.
La contrainte Blank fait l'inverse.

True La contrainte True vérifie que la valeur -


False vaut true, 1 ou "1".
La contrainte False vérifie que la valeur
vaut false, 0 ou "0".

NotNull La contrainte NotNull vérifie que la -


Null valeur est strictement différente de null.

Type La contrainte Type vérifie que la valeur type (option par défaut) : le type duquel
est bien du type donné en argument. doit être la valeur,
parmi array, bool,int, object

40
Les annotations : Nombre, date
Contrainte Rôle Options
Range La contrainte Range vérifie que la valeur ne min : nbre de car minimum
dépasse pas X, ou qu'elle dépasse Y. max : nbre de car maximum
minMessage : msg erreur nbre de car min
maxMessage : msg erreur nbre de car max
invalidMessage : msg erreur si non nmbre
Date vérifie que la valeur est un objet de -
type Datetime, ou une chaîne de type YYYY-
MM-DD.
Time vérifie qque c’est un objet de type Datetime, ou -
une chaîne type HH:MM:SS.
DateTime vérifie que c’est un objet de typeDatetime, ou
une chaîne de caractères du type YYYY-MM-
DD HH:MM:SS.

41
Les annotations : File
Contrainte Rôle Options
File La contrainte File vérifie que la valeur est un maxSize : la taille maximale du fichier.
fichier valide, c'est-à-dire soit une chaîne de Exemple : 1M ou 1k.
caractères qui pointe vers un fichier existant, mimeTypes : mimeType(s) que le fichier
soit une instance de la classe File (ce qui inclut doit avoir.
UploadedFile).
Image La contrainte Image vérifie que la valeur est maxSize : la taille maximale du fichier.
valide selon la contrainte précédente File (dont Exemple : 1M ou 1k.
elle hérite les options), sauf que les minWidth /maxWidth : la largeur minimale
mimeTypes acceptés sont automatiquement et maximale que doit respecter l'image.
définis comme ceux de fichiers images. Il est minHeight /maxHeight : la hauteur
également possible de mettre des contraintes minimale et maximale que doit respecter
sur la hauteur max ou la largeur max de l'image.
l'image.

42
Validation Exemple
/**
* @var string
* @Assert\Length(min="3",max="10",maxMessage="Trop c'est trop")
* @ORM\Column(name="nom", type="string", length=50)
*/
private $nom;

/**
* @var string
* @Assert\File(mimeTypes = {"application/pdf"},mimeTypesMessage="Le
fichier doit être du format PDF")
* @ORM\Column(name="path", type="string")
*/
private $path;

43
Valider des champs non mapés
Lorsque le champs que vous voulez valider est non mapé et que vous souhaiter le valider, il faut
ajouter un paramètre constraints dans le tableau d’option de votre méthode add.

->add('imageFile', FileType::class, array(


'mapped'=> false,
'constraints'=> array(
new Image(),
);
))

44
Exercice
Ajouter les validateurs nécessaires à votre formulaire.
Symfony
Sécurité
AYMEN SELLAOUTI

1
Introduction
Un site est généralement décomposé en deux parties :
Partie public : accessible à tous le monde
Partie privée : accessible à des utilisateurs particuliers.
Au sein même de la partie privée, certaines ressources sont spécifiques à des
rôles ou des utilisateurs particuliers.
Nous identifions donc deux niveaux de sécurité :

Authentification Autorisation

2
Authentification
 Processus permettant d’authentifier un utilisateur.

Deux réponses possibles

Non authentifié : Anonyme.

Authentifié : membre

3
Security Bundle
Le Bundle qui gère la sécurité dans Symfony s’appelle SecurityBundle.
Si vous ne l’avez pas dans votre application, installer le via la
commande
composer require security

4
Fichier de configuration security.yml
security:
# https://symfony.com/doc/current/security/authenticator_manager.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords Le Firewall qui gère la
password_hashers: configuration de
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' l’authentification de vos
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers utilisateurs
providers:
users_in_memory: { memory: null }
firewalls: Cette partie assure
dev: que le débuggeur de
pattern: ^/(_(profiler|wdt)|css|images|js)/ Symfony ne soit pas
security: false bloqué
main:
lazy: true
provider: users_in_memory
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/admin, roles: ROLE_ADMIN } 5
La classe user
L’ensemble du système de sécurité est basé sur la classe User qui
représente l’utilisateur de votre application.
Afin de créer la classe User, utiliser la commande :
symfony console make:user
Si vous n’avez pas le MakerBundle, installer le.
Cette outils vous posera un ensemble de questions, selon votre besoin
répondez y et il fera tout le reste.

6
UserProvider
Le User Provider est un ensemble de classe associé au bundle Security de
Symfony et qui ont deux rôles
 Récupérer le user de la session. En effet, pour chaque requête, Symfony
charge l’objet user de la session. Il vérifie aussi que le user n’a pas changé au
niveau de la BD.
 Charge l’utilisateur pour réaliser certaines fonctionnalités comme la
fonctionnalité se souvenir de moi.

https://symfony.com/doc/current/security/user_provider.html 7
UserProvider
Afin de définir le userProvider que vous voulez utiliser passer par le fichier
de configuration security.yaml

providers:
users:
entity:
# the class of the entity that represents users
class: 'App\Entity\User'
# the property to query by - e.g. username, email, etc
property: email

https://symfony.com/doc/current/security/user_provider.html 8
Exercice
Reprenez votre diagramme de classe.
Job
Ajouter la classe user. Personne
* designation
Ajouter les relations nécessaires. firstname description
name 1
age
*

*
Hobby
designation
Encoder le mot de passe
 Vous n’avez pas toujours besoin de mot de passe
 En cas de besoin, vous pouvez configurer la manière avec lequel votre
mot de passe doit être géré dans le fichier security.yml.
# config/packages/security.yaml
security:
security:
encoders:
# ...
App\Entity\User:
password_hashers:
algorithm: auto
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# use your user class name here Avant Symfony 5,3
App\Entity\User:
# Use native password hasher, which auto-selects the best
# possible hashing algorithm (starting from Symfony 5.3 this is
"bcrypt")
algorithm: auto A partir de Symfony 5,3 10
Encoder le mot de passe
Le service responsable de l’encodage des mots de passe est le service
UserProviderEncoder (avant Symfony 5.3) ou UserPasswordHasher à
partir de Symfony 5.3 .
Afin de l’utiliser, et comme tous les services de Symfony, il suffit de
l’injecter.
private $userPasswordHasher;
public function __construct( UserPasswordHasherInterface $userPasswordHasher)
{
$this->userPasswordHasher = $userPasswordHasher;
}

public function __construct( private UserPasswordHasherInterface $passwordEncoder)


{
}
PHP 8 11
Exercice
Créer un fixture qui permet de créer quelques utilisateurs.
Ne lancer que les fixtures du user. Pour se faire, les fixtures que vous voulez lancer
doivent implémenter l’interface FixtureGroupeInterface. Ceci permettra de lancer
les fixtures d’un groupe donnée.
En implémentant cette interface, vous devez implémenter la méthode getGroupes.
Cette méthode retourne un tableau contenant le nom des groupes auxquels
appartient cette fixture.
Exemple : return [‘groupeRedondant’,’groupeTest1’];
Enfin lancer la commande de chargement de fixture avec l’option –
group=nomGroupe ajouter aussi l’option –append pour ne pas purger la base de
données.
https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html 12
Authentification et Firewall
Le système d’authentification de Symfony est configuré au niveau de la
partie firewalls de votre fichier security.yaml.
Cette section va définir comment vos utilisateurs seront authentifié,
e.g. API Token, Formulaire d’authentification.
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true

13
Authentification et Firewall
Comme décrite dans la documentation, l’authentification dans Symfony ressemble à
de « la magie ».
En effet, au lieu d’aller construire une route et un contrôleur afin d’effectuer le
traitement, vous devez simplement activer un « authentication provider ».
« L’authentication provider » est du code qui s’exécute automatiquement avant
chaque appel d’un contrôleur.
Symfony possède un ensemble d’ « authentication provider » prêt à l’emploi. Vous
trouverez leur description dans la documentation :
https://symfony.com/doc/current/security/auth_providers.html
 Dans la documentation, il est conseillé de passer par les « Guard Authenticator » qui
permettent un contrôle total sur toutes les parties de l’authentification.
14
Les Guard Authenticator
Un « Guard authenticator » est une classe qui vous permet un control
complet sur le processus d’authentification.
Cette classe devra ou implémenter l’interface AuthentiatorInterface ou
étendre la classe abstraite associée au besoin, e.g.
AbstractFormLoginAuthenticator en cas de formulaire
d’authentification ou AbstractGuardAuthenticator en cas d’api
La commande make:auth permet de générer automatiquement cette
classe.
Une fois lancée, cette commande vous demande si vous voulez créer
un « empty authenticator » ou un « login form authenticator ».
15
Guard Authenticator
Symfony 5.3
A partir de la version 5.3, vous devez implémenter uniquement les méthodes
authenticate et la méthode onAuthenticationSuccess.
 Il y a aussi des méthodes optionnelles que vous pouvez surcharger :
supports
onAuthenticationFailure
start
Symfony utilises à partir de la version 5,3 un nouveau Authenticator based
Security
Pour la gestion des utilisateurs elle utilises Passport

16
Guard Authenticator
Symfony 5.3 public function authenticate(Request $request): PassportInterface
{
$username = $request->request->get('username', '');
$request->getSession()->set(Security::LAST_USERNAME, $username);
return new Passport(
new UserBadge($username),
new PasswordCredentials($request->request->get('password', '')),
[
new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token,
string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
return new RedirectResponse($targetPath);
}
throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
} 17
Activer le guard
(Symfony 5.3)
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
appLogin:
pattern: ^/login
custom_authenticator: App\Security\LoginFormAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route

18
Se déconnecter
Afin de se déconnecter, il suffit d’ajouter la clé logout dans votre firewalls
configuration dans security.yaml.
Ajouter ensuite une méthode vide logout dans votre securityController avec la
route associé à votre méthode logout.
Vous pouvez débuger les autres options de logout avec la commande
symfony console debug:config security
/** firewalls:
* @Route("/logout", name="logout") main:
*/ logout:
public function logout() { path: logout

} 19
Exercice
Créer un LoginForm en utilisant la commande
symfony console make:auth.
Terminer les étapes définies par la commande à la fin de son exécution.

20
Récupérer le user dans le contrôleur
Afin de récupérer le user dans un contrôleur, il suffit d’utiliser la méthode helper getUser.
Utiliser ensuite sa méthode

public function list()


{
$user = $this->getUser();
}

21
Récupérer le user dans le service
Afin de récupérer le user dans un service, il suffit d’injecter le Securiy Service.
Utiliser ensuite sa méthode getUser

use Symfony\Component\Security\Core\Security;
class HelperService
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function sendMoney() {
$user = $this->security->getUser()
}
}

22
Exercice
Fait en sorte que le lien login de votre template vous envoi vers la page
de login.
Ajouter un lien pour le logout.

23
Register
Afin de permettre l’ajout ou l’enregistrement de vos utilisateurs, vous pouvez
utiliser la commande :
symfony console make:registration-form
 Cette fonctionnalité n’a rien de particulier, elle permet tout simplement d’ajouter
un utilisateur dans votre base de données.
 Vous pouvez personnaliser le contrôleur généré comme vous le voulez.

24
Authentification manuelle d’un utilisateur
Une fois l’utilisateur inscrit, vous pourrez l’authentifier d’une façon manuelle en
injectant le service UserAuthenticatorInterface.
Utiliser sa méthode authenticateUser qui prend en paramètre le user, votre
authenticator et l’objet request
public function register(Request $request, UserPasswordHasherInterface
$userPasswordHasherInterface, LoginFormAuthenticator $authenticator,
UserAuthenticatorInterface $userAuthenticator): Response
{
//…
if ($form->isSubmitted() && $form->isValid()) {
//…
// Authenticate user
// retourne un Objet Response, celui généré par la méthode onAuthenticationSuccess
return $userAuthenticator->authenticateUser($user, $authenticator, $request);
}
25
Autorisation
 Processus permettant d’autoriser un utilisateur à accéder à une
ressource selon son rôle.
Le processus d’authentification suit deux étape.
1- Lors de l’authentification l’utilisateur est associé à un ensemble de
rôles.
2- Lors de l’accès à une ressource, on vérifie si l’utilisateur a le rôle
nécessaire pour y accéder.

26
Les Rôles
 Chaque utilisateur connecté a au moins un rôle : le ROLE_USER

 Tous les rôles commencent par ROLE_


/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';

return array_unique($roles);
} 27
Définir les droits d’accès
Les droits d’accès sont définit de deux façons :
1- Dans le fichier security.yaml
2- Directement dans la ressource

28
Sécuriser les patrons d’url
La méthode la plus basique pour sécuriser une partie de votre application est de
sécuriser un patron d’url complet dans votre fichier security.yaml.
Ceci se fait sous la clé access_control. Chaque entrée est un objet avec comme clé :
-path : le pattern à protéger
-roles : les rôles qui peuvent accéder à ce pattern.
Lorsque vous essayer d’accéder à une ressource, Symfony cherche dans cette
rubrique s’il y a un matching avec la route recherché de haut vers le bas. Le premier
qu’il trouve lui permet de vérifier si vous avez le bon rôle pour accéder à la ressource
demandé ou non. L’ordre donc est très important.
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profile, roles: ROLE_USER }
https://symfony.com/doc/current/security/access_control.html 29
Exercice
Créer une action avec la route ’/admin’. Décommenter les
access_control et essayer deux scénarios.
1. Connecter vous en tant que USER et essayer d’accéder à cette route.
Que se passe t-il ?
2. Déconnecter vous et essayer d’y accéder. Que se passe t-il ?
Modifier votre classe UserFixture et faite en sorte d’ajouter un user
avec le ROLE_ADMIN. N’effacer rien de votre base.
Connecter vous en tant qu’admin. Essayer d’accéder à la route /admin.
Que se passe t-il ?

30
Exercice
Créer une action permettant d’inscrire des utilisateurs.
Créer une action pour l’admin lui permettant d’ajouter des utilisateurs
avec le ROLE qu’il veut.

31
Définir la route à activer en cas d’erreur
401
 Par défaut lorsque un utilisateur non authentifié essaye d’accéder à une ressource
protégé, un page d’erreur apparait.
 Cependant ce n’est pas le comportement standard. Ce qu’on veut généralement
c’est de le rediriger vers la page de login.
 Pour ce faire, vous devez implémenter la méthode start.
A l’intérieur de cette méthode implémenter le comportement que vous voulez, c’est
cette méthode qui sera appelé en cas de 401.

https://symfony.com/doc/current/security/access_denied_handler.html#customize-the-unauthorized-response 32
Sécuriser Les contrôleurs
Vous pouvez directement sécuriser vos contrôleurs en utilisant :
1- Le helper denyAccessUnlessGranted(‘ROLE_*’);
2- En utilisant l’annotation @IsGranted(‘ROLE_*’)
/** /**
* Matches /blog exactly * Matches /blog exactly
* *
* @IsGranted("ROLE_ADMIN") * @Route("/blog", name="blog_list")
* @Route("/blog", name="blog_list") */
*/ public function list()
public function list() {
{ $this->denyAccessUnlessGranted("ROLE_USER");
// ... // ...
} }

33
Sécuriser un service
Afin de sécuriser un service, il suffit d’injecter le Securiy Service.
Utiliser ensuite sa méthode isGranted
use Symfony\Component\Security\Core\Security;
class HelperService
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function sendMoney() {
if ($this->security->isGranted("ROLE_ADMIN")){
// Todo Send Money
}
}
} https://symfony.com/doc/current/security/securing_services.html
34
Sécuriser vos pages TWIG
Si vous voulez vérifier le role de l’utilisateur avant d’afficher une ressource ou des
informations dans vos pages TWIG, utiliser la méthode is_granted(‘ROLE_*’)

{% if is_granted('ROLE_ADMIN') %}
<a href=« /admin">Administration</a>
{% endif %}

35
Exercice
Faite en sorte que le menu s’adapte au rôle de l’utilisateur connecté.

36
Hiérarchie de rôles
Vous pouvez définir une hiérarchie de rôles.
Dans le fichier security.yaml et sous la clé role_hierarchy, définissez le rôle
principale suivie de l’ensemble des rôles dont il hérite.
Un use case très récurant est quand l’admin possédé tout les droits, donc l’admin
devra hériter de tous les rôles.
role_hierarchy:
ROLE_COMMERCIAL: ROLE_AGENT
ROLE_SECRETARY: ROLE_COMMERCIAL
ROLE_ADMIN: [ROLE_PARTNER, ROLE_SECRETARY]

Ici un commercial a les accès de l’Agent.


L’admin peut avoir les accès du Partner et de la secrétaire.
37
Spécial Rôles
PUBLIC_ACCESS : Un utilisateur non authentifié

IS_AUTHENTICATED_REMEMBRED : Vérifie qu’un utilisateur


est authentifié indépendamment de son ROLE.

IS_AUTHENTICATED_FULLY : Vérifie qu’un utilisateur est


authentifié indépendamment de son ROLE. Cependant si le user est
authentifié à cause de la fonctionnalité ‘remember_me’ alors il n’est pas
authenticated fully.

38

Vous aimerez peut-être aussi