SlideShare une entreprise Scribd logo
1  sur  43
SOLID : LES PRINCIPES
À L’ORIGINE DU SUCCÈS DE SYMFONY
ET DE VOS APPLICATIONS
https://vria.eu
contact@vria.eu
https://twitter.com/RiaVlad
RIABCHENKO Vladyslav
5+ ans full stack web-développeur
Certifié Symfony
Architecte technique à Webnet
Symfony
SOLID
Responsabilité unique
Ouvert / fermé
Substitution de Liskov
Ségrégation des interfaces
Inversion de dépendances
Plan
3
1.
2.
S.
O.
L.
I.
D.
Symfony framework
Symfony
2. Framework PHP pour projets web
1. Ensemble de composants PHP
MVC Pattern
Model View
Requête HTTP Routage Contrôleur Réponse HTTP
5
Symfony
HttpKernel
DependencyInjection
HttpFoundation
Routing
EventDispatcher
Cœur du framework qui gère le cycle de requête-réponse HTTP
Couche orientée objet aux spécifications HTTP
Mapper les requêtes aux variables (contrôleur, etc.)
Médiateur permettant aux composants découplés de
communiquer à l’aide d’événements
Conteneur de service qui instancie des services en se basant sur
la configuration et injecte leurs dépendances
et 45 autres, y compris Security, Form, Console, Cache, Asset, Validator, Serializer, etc.
6
Symfony
FrameworkBundle
Configure les composants Symfony et les colle ensemble.
Il enregistre les services et les listeners d'événements.
Les bundles sont des plugins réutilisables qui fournissent des services, des routes, des
contrôleurs, des templates, etc.
Your code
Fournit des routes, des contrôleurs, des services, une logique
métier et des templates adaptés à vos besoins.
doctrine/orm DBAL et ORM pour communiquer avec des bases de données.
twig/twig Moteur de template.
7
Principes SOLID
SOLID
– Responsabilité unique
– Ouvert / fermé
– Substitution de Liskov
– Ségrégation des interfaces
– Inversion des dépendances
Réutilisable
Flexible
Évolutif
Compréhensible
Fragile
Dupliqué
Visqueux
Complexe sans raison
SOLID aide à créer le code qui est … et à éviter le code qui est
S
O
L
I
D
9
Principe de responsabilité unique
class ReportService
{
public function createReport($data)
{
// working with report manager at domain layer
}
public function getLastThreeReportsByAuthor($author)
{
// working with database at ORM or DBAL layer
}
public function searchBy($criteria)
{
// working with database at ORM or DBAL layer
}
public function export(Report $report)
{
// working with filesystem at by means of PHP functions
}
}
Une classe ne devrait avoir qu'une seule responsabilité.
La responsabilité est une raison de modifier la classe.
Single responsibility principle
11
// working with database at ORM and/or DBAL layer
class ReportRepository
{
public function getLastThreeReportsByAuthor($author)
{ ... }
public function searchBy($criteria)
{ ... }
}
// working with report manager at domain layer (business logic)
class ReportManager
{
public function createReport($data)
{ ... }
}
// working with filesystem and pdf, excel, csv, etc.
class ReportExporter
{
public function export(Report $report)
{ ... }
}
Manager
Repository
Exporter
Single responsibility principle
12
Feature : Stocker les utilisateurs dans la base de données
Feature : Stocker les commandes dans la base de données
Feature : Authentifier des utilisateurs (formulaire de connexion, HTTP, peu importe …),
stocker les informations d'identification dans la session et authentifier chaque
requête ultérieure
Feature : Lors de la création de la commande,
affecter automatiquement cette commande à un utilisateur connecté
Single responsibility principle
13
SecurityContext
Stocke le token d’utilisateur setToken($token), getToken()
Vérifie l’autorisation isGranted('attr', $sub)
AuthenticationProvider Authentifie le token
UserProvider Récupère ou rafraîchit l'utilisateur
EntityManager Toutes les interactions avec la base de données, ORM
OrderListener Notre listener qui modifie la commande avant qu'il ne soit inséré
L’injection du service SecurityContext dans n’importe quel listener
d’EntityManager crée une dépendance circulaire.
Single responsibility principle
14
Single responsibility principle
La solution est diviser SecurityContext en AuthorizationChecker et TokenStorage.
AuthorizationChecker
AuthenticationProvider
UserProvider
EntityManager
OrderListener
TokenStorage
getToken()
setToken($token)
isGranted('attr', $sub)
15
Principe Ouvert / fermé
Les entités doivent être ouvertes à l’extension, mais fermées à la modification.
Ouvert à l’extension:
• Altérer ou ajouter un comportement
• Étendre une entité avec de nouvelles propriétés
Fermé à la modification:
• Adapter une entité sans modifier son code source
• Doter une entité d’une interface claire et stable
Open/closed principle
17
Techniques pour rester en conformité avec le principe ouvert / fermé :
• Abstraction / Héritage / Polymorphisme
• Injection de dépendance
• Patrons de conception. Par exemple, ceux du GoF :
• Abstract Factory, Factory Method, Builder, Prototype,
• Bridge, Decorator, Proxy,
• Command, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor.
Open/closed principle
18
• …
SymfonyComponentHttpKernel
App
// public/index.php
use AppKernel;
use SymfonyComponentHttpFoundationRequest;
$kernel = new Kernel($env, $debug);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
HttpKernel
- dispatcher
+ handle($request): Response
- container
- httpKernel
Kernel
+ handle($request)
+ registerBundles()
+ configureRoutes()
Kernel
+ registerBundles()
+ configureRoutes()
Toutes les requêtes HTTP arrivent sur le
front controller.
Open/closed principle
19
Open/closed principle
Le traitement « requête-réponse » est ouvert à l’extension grâce aux événements levés à
chaque étape.
Request
Response
resolve
controller
REQUEST
resolve
arguments
call
controller
CONTROLLER CONTROLLER_ARGUMENTS
Response?
RESPONSE FINISH_REQUEST
Response
exists
TERMINATE
VIEW
Exception EXCEPTION
20
Principe de substitution de Liskov
Les objets peuvent être remplacés par des instances de leurs sous-types
sans altérer l'exactitude du programme.
LSP décrit une héritage comportemental –
sémantique plutôt que purement syntaxique.
Liskov substitution principle
22
Rectangle
Carré est un rectangle à quatre côtés égaux.
- width
- height
+ setWidth($width)
+ setHeight($height)
+ getArea()
+ setWidth($width)
+ setHeight($height)
Square
function client(Rectangle $rect)
{
$rect->setHeight(8);
$rect->setWidth(3);
assert($rect->area() == 24);
}
Le code client va échouer si on passe un
objet de type Square
class Square extends Rectangle
{
public function setWidth($width)
{
$this->width = $width;
$this->height = $width;
}
public function setHeight($height)
{
$this->height = $height;
$this->width = $height;
}
}
Liskov substitution principle
23
• Préconditions ne peuvent pas être renforcées dans une sous-classe
• Postconditions ne peuvent pas être affaiblies dans une sous-classe
• Invariants doivent être préservée dans un sous-type
LSP suggère des conditions comportementales similaires à celles de
programmation par contrat :
Rectangle Précondition: width > 0
Postcondition: $this->width == $width
Invariant: $this->height reste inchangé
Précondition: width > 0
Postcondition: $this->width == $width
Invariant: $this->height reste inchangé
Invariant: $this->width == $this->height
- width
- height
+ setWidth($width)
+ setHeight($height)
+ getArea()
+ setWidth($width)
+ setHeight($height)
Square
Liskov substitution principle
24
Autorisation – vérification des droits d'accès/privilèges de l'utilisateur authentifié.
Dans Symfony, l'autorisation est basée sur :
• Token : les informations d'authentification de l'utilisateur (rôles, …),
• Attributs : droits/privilèges à vérifier (ROLE_ADMIN, EDIT, …),
• Objet optionnel : tout objet pour lequel il faut contrôler les droits.
$authorizationChecker->isGranted('ROLE_ADMIN');
$authorizationChecker->isGranted('EDIT’, $comment);
$authorizationChecker->isGranted(['VIEW', 'MANAGE'], $order);
Liskov substitution principle
25
Liskov substitution principle
- voters : VoterInterface[]
+ decide($token, $attributes, $object)
AuthorizationChecker
- tokenStorage
- accessDecisionManager
+ isGranted($attributes, $object)
AccessDecisionManager
+ vote($token, $subject, $attributes)
VoterInterface
isGranted renvoie vrai/faux. Il délègue la
décision à AccessDecisionManager::decide.
decide demande à tous les voters de voter
et prend la décision finale.
vote doit renvoyer une de ces valeurs :
ACCESS_GRANTED, ACCESS_ABSTAIN or ACCESS_DENIED.
26
DoctrineORM
Doctrine est une bibliothèque PHP axée sur le stockage données et « object mapping ».
Instance d’Article
id: 17
author: Author(id=3, name=Marie)
createdAt: DateTime(2018-10-01)
text: "Salut PHP Forum! Ajour…"
Instance d’Author
id: 3
name: Marie
articles: [Article(id=17, …)]
article
id author_id created_at text
16 2 2018-05-21 In thi…
17 17 2018-10-01 Hi sec…
…
author
id name
2 Albert
3 Marie
4 Isaac
…
27
Liskov substitution principle
Doctrine déclenche une série d'événements au cours de la vie des entités stockées :
prePersist et postPersist, preUpdate et postUpdate, preRemove et postRemove, etc.
use DoctrineORMEventLifecycleEventArgs;
use DoctrineORMMapping as ORM;
class Article
{
private $createdAt;
private $updatedAt;
private $createdBy;
private $updatedBy;
/** @ORMPrePersist() */
public function prePersist(LifecycleEventArgs $event)
{
$this->createdAt = new DateTime();
}
/** @ORMPreUpdate() */
public function preUpdate(LifecycleEventArgs $event)
{
$article = $event->getEntity();
$article->setUpdatedAt(new DateTime());
}
}
Précondition: $event->getEntity()
est une instance d’Article
28
Liskov substitution principle
use AppEntityArticle;
use DoctrineORMEventLifecycleEventArgs;
class ArticleLifecycleListener
{
/** @var AppEntity|Author */
private $user;
public function prePersist(LifecycleEventArgs $event)
{
$article = $event->getEntity();
if ($article instanceof Article) {
$article->setCreatedBy($this->user);
}
}
public function preUpdate(LifecycleEventArgs $event)
{
$article = $event->getEntity();
if ($article instanceof Article) {
$article->setUpdatedBy($this->user);
}
}
}
Précondition: $event->getEntity()
est n’importe quelle entité
Les listeners-services ont accès à d'autres services via l'injection de dépendances :
29
Liskov substitution principle
Principe de ségrégation des interfaces
De nombreuses interfaces spécifiques au client sont préférables à une grande
interface général.
Interface segregation principle
31
Aucun client ne devrait être obligé de dépendre de méthodes qu'il n'utilise pas.
Conteneur de
services
Configuration:
yaml, xml, php
Pour chaque service :
- id
- FQCN
- dépendances
- …
- Instancie l'objet de service à la demande
- Instancie ses dépendances
- Injecte des dépendances en service
- Renvoie et stocke le service
- Renvoie la même instance pour des
demandes consécutives
“Compilation”
Container gère les services qui sont des objets utiles.
Interface segregation principle
32
PsrContainer
Récupérer des services ContainerInterface
+ get($id): mixed
+ has($id): bool
SymfonyComponentDependencyInjection
ContainerInterface
+ set($id, $service)
+ initialized($id): bool
+ getParameter($name): mixed
Container
- services
- parameterBag
- aliases
+ compile()
Configurer les services et les
paramètres
Compiler le conteneur (init, cache)
(Code client)
(Extensions)
(Kernel)
Interface segregation principle
33
Routes configuration
Url matcher
'_route’ => string 'blog_list'
'_controller' => string 'AppControllerBlog::list'
'page’ => string '2'
'category’ => string 'php-forum'
Url generator
'/blog/php-forum'
'/blog/php7/4'
$matcher->match('/blog/php-forum/2');
$generator->generate('blog_list', ['category' => 'php-forum']);
$generator->generate('blog_list', ['category' => 'php7', 'page' => 4]);
# config/routes.yaml
blog_list: # nom de route
path: /blog/{category}/{page} # path pattern
controller: AppControllerBlog::list # contrôleur à exécuter
requirements: # contraintes
category: '[a-z0-9-_]+'
page: 'd+'
defaults: # valeurs par défaut
page: 1
Interface segregation principle
34
SymfonyComponentRouting
Interface segregation principle
UrlMatcherInterface
+ match($pathinfo): array
UrlGeneratorInterface
+ generate
($name, $parameters, $referenceType): string
RouterInterface
+ getRouteCollection(): RouteCollection
Router
- collection: RouteCollection
- options: array
- context
Contient la configuration
de toutes les routes.
35
Principe d'inversion des dépendances
Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau.
Les deux devraient dépendre d’abstractions.
Les abstractions ne doivent pas dépendre des détails.
Les détails devraient dépendre des abstractions.
Dependency inversion principle
37
Framework
namespace Monolog;
class Logger
{
public function log($message)
{
echo $message;
}
}
namespace Framework;
use MonologLogger;
class Kernel
{
private $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function handle()
{
$this->logger->log('...');
// ...
}
}
Monolog
Kernel Logger
Dependency inversion principle
38
namespace Framework;
class Kernel
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
namespace Monolog;
use FrameworkLoggerInterface;
class Logger implements LoggerInterface
{
public function log($message)
{
echo $message;
}
}
namespace Framework;
interface LoggerInterface
{
public function log($message);
}
Framework Monolog
Kernel LoggerLoggerInterface
Dependency inversion principle
39
AbstractLogger
Solution + flexible
Framework
Monolog
Kernel
Logger
LoggerInterface
Dependency inversion principle
40
Dependency inversion principle
PsrLog
SymfonyHTTPKernel
Monolog
Kernel
Logger
LoggerInterface
PSR – PHP Standards Recommendations
FIG – Framework Interoperability Group
SymfonyRouting
Router
SymfonySecurity
Handlers ...
...
...
41
Dependency inversion principle
Symfony utilise l’injection de dépendances et les interfaces quasiment partout
SymfonyForm
SymfonyValidator
ACMEValidator
FormInterface
Form
ExtensionValidator
ValidatorExtension
ValidatorInterface
Validator
Validator
- validator: ValidatorInterface
FormExtensionInterface
42
Merci de votre
attention
https://vria.eu
contact@vria.eu
https://twitter.com/RiaVlad
https://webnet.fr

Contenu connexe

Tendances

Chap 6 : classes et interfaces
Chap 6 : classes et interfacesChap 6 : classes et interfaces
Chap 6 : classes et interfacesAziz Darouichi
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Scott Wlaschin
 
Cours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vieCours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vieMohammed Amine Mostefai
 
CWIN17 Morocco / Microservices architecture ghofrane benaziz
CWIN17 Morocco / Microservices architecture ghofrane benazizCWIN17 Morocco / Microservices architecture ghofrane benaziz
CWIN17 Morocco / Microservices architecture ghofrane benazizCapgemini
 
Design Patterns
Design PatternsDesign Patterns
Design PatternsKoffi Sani
 
Méthodes agiles: Scrum et XP
Méthodes agiles: Scrum et XPMéthodes agiles: Scrum et XP
Méthodes agiles: Scrum et XPYouness Boukouchi
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code SmellsMario Sangiorgio
 
Chp2 - Cahier des Charges
Chp2 - Cahier des ChargesChp2 - Cahier des Charges
Chp2 - Cahier des ChargesLilia Sfaxi
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
eServices-Chp5: Microservices et API Management
eServices-Chp5: Microservices et API ManagementeServices-Chp5: Microservices et API Management
eServices-Chp5: Microservices et API ManagementLilia Sfaxi
 
softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...ENSET, Université Hassan II Casablanca
 
Présentation Git & GitHub
Présentation Git & GitHubPrésentation Git & GitHub
Présentation Git & GitHubThibault Vlacich
 
Intégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec JenkinsIntégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec JenkinsKokou Gaglo
 
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMUSFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMULinaro
 

Tendances (20)

Cours Génie Logiciel - Introduction
Cours Génie Logiciel - IntroductionCours Génie Logiciel - Introduction
Cours Génie Logiciel - Introduction
 
Chap 6 : classes et interfaces
Chap 6 : classes et interfacesChap 6 : classes et interfaces
Chap 6 : classes et interfaces
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
UML
UMLUML
UML
 
Cours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vieCours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vie
 
Ch 01 poo
Ch 01 pooCh 01 poo
Ch 01 poo
 
CWIN17 Morocco / Microservices architecture ghofrane benaziz
CWIN17 Morocco / Microservices architecture ghofrane benazizCWIN17 Morocco / Microservices architecture ghofrane benaziz
CWIN17 Morocco / Microservices architecture ghofrane benaziz
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
 
Méthodes agiles: Scrum et XP
Méthodes agiles: Scrum et XPMéthodes agiles: Scrum et XP
Méthodes agiles: Scrum et XP
 
Clean code and Code Smells
Clean code and Code SmellsClean code and Code Smells
Clean code and Code Smells
 
Git
GitGit
Git
 
Chp2 - Cahier des Charges
Chp2 - Cahier des ChargesChp2 - Cahier des Charges
Chp2 - Cahier des Charges
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
eServices-Chp5: Microservices et API Management
eServices-Chp5: Microservices et API ManagementeServices-Chp5: Microservices et API Management
eServices-Chp5: Microservices et API Management
 
softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...
 
Présentation Git & GitHub
Présentation Git & GitHubPrésentation Git & GitHub
Présentation Git & GitHub
 
Intégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec JenkinsIntégration continue et déploiement continue avec Jenkins
Intégration continue et déploiement continue avec Jenkins
 
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMUSFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
SFO15-202: Towards Multi-Threaded Tiny Code Generator (TCG) in QEMU
 
Support NodeJS avec TypeScript Express MongoDB
Support NodeJS avec TypeScript Express MongoDBSupport NodeJS avec TypeScript Express MongoDB
Support NodeJS avec TypeScript Express MongoDB
 
Cours design pattern m youssfi partie 3 decorateur
Cours design pattern m youssfi partie 3 decorateurCours design pattern m youssfi partie 3 decorateur
Cours design pattern m youssfi partie 3 decorateur
 

Similaire à SOLID : les principes à l’origine du succès de Symfony et de vos applications

Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyHugo Hamon
 
Soutenance Zend Framework vs Symfony
Soutenance Zend Framework vs SymfonySoutenance Zend Framework vs Symfony
Soutenance Zend Framework vs SymfonyVincent Composieux
 
php2 : formulaire-session-PDO
php2 : formulaire-session-PDOphp2 : formulaire-session-PDO
php2 : formulaire-session-PDOAbdoulaye Dieng
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2Hugo Hamon
 
Symfony 2 : chapitre 1 - Présentation Générale
Symfony 2 : chapitre 1 - Présentation GénéraleSymfony 2 : chapitre 1 - Présentation Générale
Symfony 2 : chapitre 1 - Présentation GénéraleAbdelkader Rhouati
 
Laravel yet another framework
Laravel  yet another frameworkLaravel  yet another framework
Laravel yet another frameworkLAHAXE Arnaud
 
BordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets JavaBordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets JavaCamblor Frédéric
 
Drupal 8, symfony
Drupal 8, symfonyDrupal 8, symfony
Drupal 8, symfonyjeUXdiCode
 
Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Engineor
 
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...Alexandre Touret
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantHugo Hamon
 
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniterAtsé François-Xavier KOBON
 
Rich Desktop Applications
Rich Desktop ApplicationsRich Desktop Applications
Rich Desktop Applicationsgoldoraf
 
Cours php -partie 1.pdf
Cours php -partie 1.pdfCours php -partie 1.pdf
Cours php -partie 1.pdfssuserc46a93
 
Authentification sociale en angular 1.pptx
Authentification sociale en angular 1.pptxAuthentification sociale en angular 1.pptx
Authentification sociale en angular 1.pptxMickael ROLO
 

Similaire à SOLID : les principes à l’origine du succès de Symfony et de vos applications (20)

Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec Symfony
 
Soutenance Zend Framework vs Symfony
Soutenance Zend Framework vs SymfonySoutenance Zend Framework vs Symfony
Soutenance Zend Framework vs Symfony
 
php2 : formulaire-session-PDO
php2 : formulaire-session-PDOphp2 : formulaire-session-PDO
php2 : formulaire-session-PDO
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
 
Introduction à Symfony
Introduction à SymfonyIntroduction à Symfony
Introduction à Symfony
 
Présentation symfony drupal
Présentation symfony drupalPrésentation symfony drupal
Présentation symfony drupal
 
Rapport tp3 j2ee
Rapport tp3 j2eeRapport tp3 j2ee
Rapport tp3 j2ee
 
Symfony 2 : chapitre 1 - Présentation Générale
Symfony 2 : chapitre 1 - Présentation GénéraleSymfony 2 : chapitre 1 - Présentation Générale
Symfony 2 : chapitre 1 - Présentation Générale
 
Laravel yet another framework
Laravel  yet another frameworkLaravel  yet another framework
Laravel yet another framework
 
BordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets JavaBordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets Java
 
Playing With PHP 5.3
Playing With PHP 5.3Playing With PHP 5.3
Playing With PHP 5.3
 
Drupal 8, symfony
Drupal 8, symfonyDrupal 8, symfony
Drupal 8, symfony
 
Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !Open close principle, on a dit étendre, pas extends !
Open close principle, on a dit étendre, pas extends !
 
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
Checklist pour concevoir une application dans le cloud.10 conseils à l'attent...
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
 
Rich Desktop Applications
Rich Desktop ApplicationsRich Desktop Applications
Rich Desktop Applications
 
Cours php -partie 1.pdf
Cours php -partie 1.pdfCours php -partie 1.pdf
Cours php -partie 1.pdf
 
Authentification sociale en angular 1.pptx
Authentification sociale en angular 1.pptxAuthentification sociale en angular 1.pptx
Authentification sociale en angular 1.pptx
 
Spring MVC
Spring MVCSpring MVC
Spring MVC
 

Plus de Vladyslav Riabchenko

Modèle de domaine riche dans une application métier complexe un exemple pratique
Modèle de domaine riche dans une application métier complexe un exemple pratiqueModèle de domaine riche dans une application métier complexe un exemple pratique
Modèle de domaine riche dans une application métier complexe un exemple pratiqueVladyslav Riabchenko
 
SOLID: the core principles of success of the Symfony web framework and of you...
SOLID: the core principles of success of the Symfony web framework and of you...SOLID: the core principles of success of the Symfony web framework and of you...
SOLID: the core principles of success of the Symfony web framework and of you...Vladyslav Riabchenko
 
Sécurisation de vos applications web à l’aide du composant Security de Symfony
Sécurisation de vos applications web  à l’aide du composant Security de SymfonySécurisation de vos applications web  à l’aide du composant Security de Symfony
Sécurisation de vos applications web à l’aide du composant Security de SymfonyVladyslav Riabchenko
 
Sécurisation de vos applications web à l’aide du composant Security de Symfony
Sécurisation de vos applications web à l’aide du composant Security de SymfonySécurisation de vos applications web à l’aide du composant Security de Symfony
Sécurisation de vos applications web à l’aide du composant Security de SymfonyVladyslav Riabchenko
 
Versionning sémantique et Composer
Versionning sémantique et ComposerVersionning sémantique et Composer
Versionning sémantique et ComposerVladyslav Riabchenko
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Vladyslav Riabchenko
 
Les patrons de conception du composant Form
Les patrons de conception du composant FormLes patrons de conception du composant Form
Les patrons de conception du composant FormVladyslav Riabchenko
 

Plus de Vladyslav Riabchenko (7)

Modèle de domaine riche dans une application métier complexe un exemple pratique
Modèle de domaine riche dans une application métier complexe un exemple pratiqueModèle de domaine riche dans une application métier complexe un exemple pratique
Modèle de domaine riche dans une application métier complexe un exemple pratique
 
SOLID: the core principles of success of the Symfony web framework and of you...
SOLID: the core principles of success of the Symfony web framework and of you...SOLID: the core principles of success of the Symfony web framework and of you...
SOLID: the core principles of success of the Symfony web framework and of you...
 
Sécurisation de vos applications web à l’aide du composant Security de Symfony
Sécurisation de vos applications web  à l’aide du composant Security de SymfonySécurisation de vos applications web  à l’aide du composant Security de Symfony
Sécurisation de vos applications web à l’aide du composant Security de Symfony
 
Sécurisation de vos applications web à l’aide du composant Security de Symfony
Sécurisation de vos applications web à l’aide du composant Security de SymfonySécurisation de vos applications web à l’aide du composant Security de Symfony
Sécurisation de vos applications web à l’aide du composant Security de Symfony
 
Versionning sémantique et Composer
Versionning sémantique et ComposerVersionning sémantique et Composer
Versionning sémantique et Composer
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3
 
Les patrons de conception du composant Form
Les patrons de conception du composant FormLes patrons de conception du composant Form
Les patrons de conception du composant Form
 

SOLID : les principes à l’origine du succès de Symfony et de vos applications

  • 1. SOLID : LES PRINCIPES À L’ORIGINE DU SUCCÈS DE SYMFONY ET DE VOS APPLICATIONS
  • 2. https://vria.eu contact@vria.eu https://twitter.com/RiaVlad RIABCHENKO Vladyslav 5+ ans full stack web-développeur Certifié Symfony Architecte technique à Webnet
  • 3. Symfony SOLID Responsabilité unique Ouvert / fermé Substitution de Liskov Ségrégation des interfaces Inversion de dépendances Plan 3 1. 2. S. O. L. I. D.
  • 5. Symfony 2. Framework PHP pour projets web 1. Ensemble de composants PHP MVC Pattern Model View Requête HTTP Routage Contrôleur Réponse HTTP 5
  • 6. Symfony HttpKernel DependencyInjection HttpFoundation Routing EventDispatcher Cœur du framework qui gère le cycle de requête-réponse HTTP Couche orientée objet aux spécifications HTTP Mapper les requêtes aux variables (contrôleur, etc.) Médiateur permettant aux composants découplés de communiquer à l’aide d’événements Conteneur de service qui instancie des services en se basant sur la configuration et injecte leurs dépendances et 45 autres, y compris Security, Form, Console, Cache, Asset, Validator, Serializer, etc. 6
  • 7. Symfony FrameworkBundle Configure les composants Symfony et les colle ensemble. Il enregistre les services et les listeners d'événements. Les bundles sont des plugins réutilisables qui fournissent des services, des routes, des contrôleurs, des templates, etc. Your code Fournit des routes, des contrôleurs, des services, une logique métier et des templates adaptés à vos besoins. doctrine/orm DBAL et ORM pour communiquer avec des bases de données. twig/twig Moteur de template. 7
  • 9. SOLID – Responsabilité unique – Ouvert / fermé – Substitution de Liskov – Ségrégation des interfaces – Inversion des dépendances Réutilisable Flexible Évolutif Compréhensible Fragile Dupliqué Visqueux Complexe sans raison SOLID aide à créer le code qui est … et à éviter le code qui est S O L I D 9
  • 11. class ReportService { public function createReport($data) { // working with report manager at domain layer } public function getLastThreeReportsByAuthor($author) { // working with database at ORM or DBAL layer } public function searchBy($criteria) { // working with database at ORM or DBAL layer } public function export(Report $report) { // working with filesystem at by means of PHP functions } } Une classe ne devrait avoir qu'une seule responsabilité. La responsabilité est une raison de modifier la classe. Single responsibility principle 11
  • 12. // working with database at ORM and/or DBAL layer class ReportRepository { public function getLastThreeReportsByAuthor($author) { ... } public function searchBy($criteria) { ... } } // working with report manager at domain layer (business logic) class ReportManager { public function createReport($data) { ... } } // working with filesystem and pdf, excel, csv, etc. class ReportExporter { public function export(Report $report) { ... } } Manager Repository Exporter Single responsibility principle 12
  • 13. Feature : Stocker les utilisateurs dans la base de données Feature : Stocker les commandes dans la base de données Feature : Authentifier des utilisateurs (formulaire de connexion, HTTP, peu importe …), stocker les informations d'identification dans la session et authentifier chaque requête ultérieure Feature : Lors de la création de la commande, affecter automatiquement cette commande à un utilisateur connecté Single responsibility principle 13
  • 14. SecurityContext Stocke le token d’utilisateur setToken($token), getToken() Vérifie l’autorisation isGranted('attr', $sub) AuthenticationProvider Authentifie le token UserProvider Récupère ou rafraîchit l'utilisateur EntityManager Toutes les interactions avec la base de données, ORM OrderListener Notre listener qui modifie la commande avant qu'il ne soit inséré L’injection du service SecurityContext dans n’importe quel listener d’EntityManager crée une dépendance circulaire. Single responsibility principle 14
  • 15. Single responsibility principle La solution est diviser SecurityContext en AuthorizationChecker et TokenStorage. AuthorizationChecker AuthenticationProvider UserProvider EntityManager OrderListener TokenStorage getToken() setToken($token) isGranted('attr', $sub) 15
  • 17. Les entités doivent être ouvertes à l’extension, mais fermées à la modification. Ouvert à l’extension: • Altérer ou ajouter un comportement • Étendre une entité avec de nouvelles propriétés Fermé à la modification: • Adapter une entité sans modifier son code source • Doter une entité d’une interface claire et stable Open/closed principle 17
  • 18. Techniques pour rester en conformité avec le principe ouvert / fermé : • Abstraction / Héritage / Polymorphisme • Injection de dépendance • Patrons de conception. Par exemple, ceux du GoF : • Abstract Factory, Factory Method, Builder, Prototype, • Bridge, Decorator, Proxy, • Command, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor. Open/closed principle 18 • …
  • 19. SymfonyComponentHttpKernel App // public/index.php use AppKernel; use SymfonyComponentHttpFoundationRequest; $kernel = new Kernel($env, $debug); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); HttpKernel - dispatcher + handle($request): Response - container - httpKernel Kernel + handle($request) + registerBundles() + configureRoutes() Kernel + registerBundles() + configureRoutes() Toutes les requêtes HTTP arrivent sur le front controller. Open/closed principle 19
  • 20. Open/closed principle Le traitement « requête-réponse » est ouvert à l’extension grâce aux événements levés à chaque étape. Request Response resolve controller REQUEST resolve arguments call controller CONTROLLER CONTROLLER_ARGUMENTS Response? RESPONSE FINISH_REQUEST Response exists TERMINATE VIEW Exception EXCEPTION 20
  • 22. Les objets peuvent être remplacés par des instances de leurs sous-types sans altérer l'exactitude du programme. LSP décrit une héritage comportemental – sémantique plutôt que purement syntaxique. Liskov substitution principle 22
  • 23. Rectangle Carré est un rectangle à quatre côtés égaux. - width - height + setWidth($width) + setHeight($height) + getArea() + setWidth($width) + setHeight($height) Square function client(Rectangle $rect) { $rect->setHeight(8); $rect->setWidth(3); assert($rect->area() == 24); } Le code client va échouer si on passe un objet de type Square class Square extends Rectangle { public function setWidth($width) { $this->width = $width; $this->height = $width; } public function setHeight($height) { $this->height = $height; $this->width = $height; } } Liskov substitution principle 23
  • 24. • Préconditions ne peuvent pas être renforcées dans une sous-classe • Postconditions ne peuvent pas être affaiblies dans une sous-classe • Invariants doivent être préservée dans un sous-type LSP suggère des conditions comportementales similaires à celles de programmation par contrat : Rectangle Précondition: width > 0 Postcondition: $this->width == $width Invariant: $this->height reste inchangé Précondition: width > 0 Postcondition: $this->width == $width Invariant: $this->height reste inchangé Invariant: $this->width == $this->height - width - height + setWidth($width) + setHeight($height) + getArea() + setWidth($width) + setHeight($height) Square Liskov substitution principle 24
  • 25. Autorisation – vérification des droits d'accès/privilèges de l'utilisateur authentifié. Dans Symfony, l'autorisation est basée sur : • Token : les informations d'authentification de l'utilisateur (rôles, …), • Attributs : droits/privilèges à vérifier (ROLE_ADMIN, EDIT, …), • Objet optionnel : tout objet pour lequel il faut contrôler les droits. $authorizationChecker->isGranted('ROLE_ADMIN'); $authorizationChecker->isGranted('EDIT’, $comment); $authorizationChecker->isGranted(['VIEW', 'MANAGE'], $order); Liskov substitution principle 25
  • 26. Liskov substitution principle - voters : VoterInterface[] + decide($token, $attributes, $object) AuthorizationChecker - tokenStorage - accessDecisionManager + isGranted($attributes, $object) AccessDecisionManager + vote($token, $subject, $attributes) VoterInterface isGranted renvoie vrai/faux. Il délègue la décision à AccessDecisionManager::decide. decide demande à tous les voters de voter et prend la décision finale. vote doit renvoyer une de ces valeurs : ACCESS_GRANTED, ACCESS_ABSTAIN or ACCESS_DENIED. 26
  • 27. DoctrineORM Doctrine est une bibliothèque PHP axée sur le stockage données et « object mapping ». Instance d’Article id: 17 author: Author(id=3, name=Marie) createdAt: DateTime(2018-10-01) text: "Salut PHP Forum! Ajour…" Instance d’Author id: 3 name: Marie articles: [Article(id=17, …)] article id author_id created_at text 16 2 2018-05-21 In thi… 17 17 2018-10-01 Hi sec… … author id name 2 Albert 3 Marie 4 Isaac … 27 Liskov substitution principle
  • 28. Doctrine déclenche une série d'événements au cours de la vie des entités stockées : prePersist et postPersist, preUpdate et postUpdate, preRemove et postRemove, etc. use DoctrineORMEventLifecycleEventArgs; use DoctrineORMMapping as ORM; class Article { private $createdAt; private $updatedAt; private $createdBy; private $updatedBy; /** @ORMPrePersist() */ public function prePersist(LifecycleEventArgs $event) { $this->createdAt = new DateTime(); } /** @ORMPreUpdate() */ public function preUpdate(LifecycleEventArgs $event) { $article = $event->getEntity(); $article->setUpdatedAt(new DateTime()); } } Précondition: $event->getEntity() est une instance d’Article 28 Liskov substitution principle
  • 29. use AppEntityArticle; use DoctrineORMEventLifecycleEventArgs; class ArticleLifecycleListener { /** @var AppEntity|Author */ private $user; public function prePersist(LifecycleEventArgs $event) { $article = $event->getEntity(); if ($article instanceof Article) { $article->setCreatedBy($this->user); } } public function preUpdate(LifecycleEventArgs $event) { $article = $event->getEntity(); if ($article instanceof Article) { $article->setUpdatedBy($this->user); } } } Précondition: $event->getEntity() est n’importe quelle entité Les listeners-services ont accès à d'autres services via l'injection de dépendances : 29 Liskov substitution principle
  • 30. Principe de ségrégation des interfaces
  • 31. De nombreuses interfaces spécifiques au client sont préférables à une grande interface général. Interface segregation principle 31 Aucun client ne devrait être obligé de dépendre de méthodes qu'il n'utilise pas.
  • 32. Conteneur de services Configuration: yaml, xml, php Pour chaque service : - id - FQCN - dépendances - … - Instancie l'objet de service à la demande - Instancie ses dépendances - Injecte des dépendances en service - Renvoie et stocke le service - Renvoie la même instance pour des demandes consécutives “Compilation” Container gère les services qui sont des objets utiles. Interface segregation principle 32
  • 33. PsrContainer Récupérer des services ContainerInterface + get($id): mixed + has($id): bool SymfonyComponentDependencyInjection ContainerInterface + set($id, $service) + initialized($id): bool + getParameter($name): mixed Container - services - parameterBag - aliases + compile() Configurer les services et les paramètres Compiler le conteneur (init, cache) (Code client) (Extensions) (Kernel) Interface segregation principle 33
  • 34. Routes configuration Url matcher '_route’ => string 'blog_list' '_controller' => string 'AppControllerBlog::list' 'page’ => string '2' 'category’ => string 'php-forum' Url generator '/blog/php-forum' '/blog/php7/4' $matcher->match('/blog/php-forum/2'); $generator->generate('blog_list', ['category' => 'php-forum']); $generator->generate('blog_list', ['category' => 'php7', 'page' => 4]); # config/routes.yaml blog_list: # nom de route path: /blog/{category}/{page} # path pattern controller: AppControllerBlog::list # contrôleur à exécuter requirements: # contraintes category: '[a-z0-9-_]+' page: 'd+' defaults: # valeurs par défaut page: 1 Interface segregation principle 34
  • 35. SymfonyComponentRouting Interface segregation principle UrlMatcherInterface + match($pathinfo): array UrlGeneratorInterface + generate ($name, $parameters, $referenceType): string RouterInterface + getRouteCollection(): RouteCollection Router - collection: RouteCollection - options: array - context Contient la configuration de toutes les routes. 35
  • 36. Principe d'inversion des dépendances
  • 37. Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient dépendre d’abstractions. Les abstractions ne doivent pas dépendre des détails. Les détails devraient dépendre des abstractions. Dependency inversion principle 37
  • 38. Framework namespace Monolog; class Logger { public function log($message) { echo $message; } } namespace Framework; use MonologLogger; class Kernel { private $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function handle() { $this->logger->log('...'); // ... } } Monolog Kernel Logger Dependency inversion principle 38
  • 39. namespace Framework; class Kernel { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } } namespace Monolog; use FrameworkLoggerInterface; class Logger implements LoggerInterface { public function log($message) { echo $message; } } namespace Framework; interface LoggerInterface { public function log($message); } Framework Monolog Kernel LoggerLoggerInterface Dependency inversion principle 39
  • 41. Dependency inversion principle PsrLog SymfonyHTTPKernel Monolog Kernel Logger LoggerInterface PSR – PHP Standards Recommendations FIG – Framework Interoperability Group SymfonyRouting Router SymfonySecurity Handlers ... ... ... 41
  • 42. Dependency inversion principle Symfony utilise l’injection de dépendances et les interfaces quasiment partout SymfonyForm SymfonyValidator ACMEValidator FormInterface Form ExtensionValidator ValidatorExtension ValidatorInterface Validator Validator - validator: ValidatorInterface FormExtensionInterface 42