SlideShare une entreprise Scribd logo
1  sur  43
SOLID: the core principles of success
of the Symfony web framework
and of your applications
Software Engineering Conference Russia 2018
October 12-13
Moscow
RIABCHENKO Vladyslav
https://vria.eu
contact@vria.eu
https://twitter.com/RiaVlad
RIABCHENKO Vladyslav
5+ years full stack web-developer
Symfony certified developer and contributor
Technical architect at Webnet (France)
Symfony 3
1. Symfony
2. SOLID
3. Single responsibility principle
4. Open/closed principle
5. Liskov substitution principle
6. Interface segregation principle
7. Dependency inversion principle
Plan
Symfony framework
Symfony 5
2. PHP framework for web projects
1. Set of reusable PHP components
MVC Pattern
Model View
HTTP Request Routing Controller HTTP Response
Symfony 6
HttpKernel
DependencyInjection
HttpFoundation
Routing
EventDispatcher
Heart of framework that manages HTTP request-response cycle
Object-oriented layer for request, response, session, etc.
Maps requests to variables (controller, path parameters)
Mediator that allows decoupled components to communicate by
dispatching events
Service container that instantiates service objects out of
configuration and injects their dependencies
and 45 others including Security, Form, Console, Cache, Asset, Validator, Serializer, etc.
Symfony 7
FrameworkBundle
Configures Symfony components and glues them in web app. It
registers services and event listeners.
Bundles are reusable plugins that provide services, routes, controllers, templates, etc.
Your code
Provides routes, controllers, services, business logic, templates
for your purpose.
doctrine/orm DBAL and ORM libraries to communicate with databases.
twig/twig Template engine.
SOLID principles
SOLID 9
– Single Responsibility Principle
– Open/Closed Principle
– Liskov Substitution Principle
– Interface Segregation Principle
– Dependency Inversion Principle
Reusable
Flexible
Maintainable
Understandable
Fragile
Duplicated
Viscose
Unreasonably complex
SOLID helps to design a system that is … and avoid a system that is
S
O
L
I
D
Single responsibility principle
Single responsibility principle 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
}
}
A class should have only a single responsibility. Responsibility is a reason to change.
Single responsibility principle
// 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)
{ ... }
}
// working with database at ORM and/or DBAL layer
class ReportRepository
{
public function getLastThreeReportsByAuthor($author)
{ ... }
public function searchBy($criteria)
{ ... }
}
Manager
Exporter
Repository
12
Single responsibility principle 13
Feature : Store users in database
Feature : Store orders in database
Feature : Authenticate users against database (login form, HTTP auth, whatever…)
Feature : On creation of order assign a currentrly connected user to it.
Store user credentials in session and authenticate users at latter requests
Single responsibility principle 14
SecurityContext
Stores a user token setToken($token), getToken()
Checks if a current user authorization isGranted('attr', $sub)
AuthenticationProvider Authenticates a token
UserProvider Retrieves or refreshes user from database
EntityManager All interaction with database at ORM and DBAL levels
OrderListener Your listener that modifies order before it gets inserted
Injecting SecurityContext service in any EntityManager’s listener
created a circular dependency.
Single responsibility principle 15
Solution is splitting SecurityContext into AuthorizationChecker and TokenStorage
AuthorizationChecker
AuthenticationProvider
UserProvider
EntityManager
OrderListener
TokenStorage
getToken()
setToken($token)
isGranted('attr', $sub)
Open/closed principle
Open/closed principle
Entities should be open for extension, but closed for modification.
17
Open for extension:
• Alter or add behavior
• Extend an entity with new properties
Closed for modification:
• Adapt entity without modifying its source code
• Provide an entity with clear and stable interface
Open/closed principle 18
Techniques to stay in compliance with the open/closed principle:
• Abstraction / Inheritance / Polymorphism
• Dependency injection
• Single responsibility principle
• Design patterns. For example, those of GoF:
• Abstract Factory, Factory Method, Builder, Prototype,
• Bridge, Decorator, Proxy,
• Command, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor.
SymfonyComponentHttpKernel
App
Open/closed principle 19
// 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()
All HTTP requests are treated by front controller.
Open/closed principle 20
Request-Response cycle is open for extension thanks to events dispatched at every step.
Request
Response
resolve
controller
REQUEST
resolve
arguments
call
controller
CONTROLLER CONTROLLER_ARGUMENTS
Response
RESPONSE FINISH_REQUEST
Response
exists
TERMINATE
VIEW
Exception EXCEPTION
Liskov substitution principle
Liskov substitution principle
Objects should be replaceable with instances of their subtypes
without altering the correctness of the program.
22
LSP describes behavioral subtyping –
semantic rather than merely syntactic relation.
Liskov substitution principle 23
Rectangle
Square is a regular rectangle with four equal sides.
- 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);
}
Client will fail when you pass Square object
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 24
• Preconditions cannot be strengthened in a subtype
• Postconditions cannot be weakened in a subtype
• Invariants of the supertype must be preserved in a subtype
LSP suggests behavioral conditions resembling those of design by contract methodology:
Rectangle Precondition: width is integer > 0
Postcondition: $this->width equals $width
Invariant: $this->height remains unchanged
Precondition: width is integer > 0
Postcondition: $this->width equals $width
Invariant: $this->height remains unchanged
Invariant: $this->width equals $this->height
- width
- height
+ setWidth($width)
+ setHeight($height)
+ getArea()
+ setWidth($width)
+ setHeight($height)
Square
Liskov substitution principle 25
Authorization – verifying access rights/privileges of currently authenticated user.
In Symfony authorization is based on:
• Token: the user’s authentication information (roles, etc.),
• Attributes: rights/privileges to verify the access to,
• Object: Any object for which access control needs to be checked.
$authorizationChecker->isGranted('ROLE_ADMIN');
$authorizationChecker->isGranted('EDIT’, $comment);
$authorizationChecker->isGranted(['VIEW', 'MANAGE'], $order);
Liskov substitution principle 26
- voters : VoterInterface[]
+ decide($token, $attributes, $object)
AuthorizationChecker
- tokenStorage
- accessDecisionManager
+ isGranted($attributes, $object)
AccessDecisionManager
+ vote($token, $subject, $attributes)
VoterInterface
isGranted returns true/false. It delegates
decision to AccessDecisionManager::decide.
decide asks all voters to vote and returns
final decision.
vote must return one of these values :
ACCESS_GRANTED, ACCESS_ABSTAIN or ACCESS_DENIED.
DoctrineORM
Liskov substitution principle 27
Doctrine is several PHP libraries focused on database storage and object mapping.
Instance of Article
id: 17
author: Author(id=3, name=Marie)
createdAt: DateTime(2018-10-01)
text: "Hi Secrus! Today we…"
Instance of 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
…
Liskov substitution principle 28
Doctrine triggers a bunch of events during the life-time of stored entities:
prePersist and postPersist, preUpdate and postUpdate, preRemove and postRemove.
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());
}
}
Precondition: $event->getEntity()
is an instance of Article
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);
}
}
}
Liskov substitution principle 29
Precondition: $event->getEntity()
is an instance of any entity
Doctrine listeners as services have access to other services via dependency injection :
Interface segregation principle
Interface segregation principle 31
Many client-specific interfaces are better than one general-purpose interface.
No client should be forced to depend on methods it does not use.
Interface segregation principle 32
Service container
Configuraion:
yaml, xml, php
For each service:
- id
- class name
- dependencies
- …
- Instantiate service object on demand
- Instantiate its dependencies
- Inject dependencies into service
- Store and return the service
- Return the same instance on
consecutive demands
“Compilation”
Container manages services which are any useful objects.
PsrContainer
Interface segregation principle 33
Fetch services ContainerInterface
+ get($id): mixed
+ has($id): bool
SymfonyComponentDependencyInjection
ContainerInterface
+ set($id, $service)
+ initialized($id): bool
+ getParameter($name): mixed
Container
- services
- parameterBag
- aliases
+ compile()
Configure services, parameters
Compile container (init, cache)
(Any client code)
(Extensions)
(Kernel)
Interface segregation principle 34
Routes configuration
Url matcher
'_route’ => string 'blog_list'
'_controller' => string 'AppControllerBlog::list'
'page’ => string '2'
'category’ => string 'secr-conference'
Url generator
'/blog/secr-conference'
'/blog/secr/2'
$matcher->match('/blog/secr-conference/2');
$generator->generate('blog_list', ['category' => 'secr-conference']);
$generator->generate('blog_list', ['category' => 'secr', 'page' => 2]);
# config/routes.yaml
blog_list: # route name
path: /blog/{category}/{page} # path pattern
controller: AppControllerBlog::list # controller to execute
requirements: # param constraints
category: '[a-z0-9-_]+'
page: 'd+'
defaults: # param default values
page: 1
SymfonyComponentRouting
Interface segregation principle 35
UrlMatcherInterface
+ match($pathinfo): array
UrlGeneratorInterface
+ generate
($name, $parameters, $referenceType): string
RouterInterface
+ getRouteCollection(): RouteCollection
Router
- collection: RouteCollection
- options: array
- context
Contains the configuration
of all known routes.
Dependency inversion principle
Dependency inversion principle 37
High-level modules should not depend on low-level modules.
Both should depend on abstractions.
Abstractions should not depend on details.
Details should depend on abstractions.
Framework
Dependency inversion principle 38
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 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
AbstractLogger
Dependency inversion principle 40
More flexible solution
Framework
Monolog
Kernel
Logger
LoggerInterface
Dependency inversion principle 41
PsrLog
SymfonyHTTPKernel
Monolog
Kernel
Logger
LoggerInterface
PSR – PHP Standards Recommendations by
FIG – Framework Interoperability Group
SymfonyRouting
Router
SymfonySecurity
Handlers ...
...
...
Dependency inversion principle 42
Symfony uses interfaces and dependency injection everywhere.
SymfonyForm
SymfonyValidator
ACMEValidator
FormInterface
Form
ExtensionValidator
ValidatorExtension
ValidatorInterface
Validator
Validator
- validator: ValidatorInterface
FormExtensionInterface
Thank you!
https://vria.eu
contact@vria.eu
https://twitter.com/RiaVlad
https://webnet.fr

Contenu connexe

Tendances

DDD on example of Symfony (SfCampUA14)
DDD on example of Symfony (SfCampUA14)DDD on example of Symfony (SfCampUA14)
DDD on example of Symfony (SfCampUA14)
Oleg Zinchenko
 
EclipseCon 2010 tutorial: Understanding git at Eclipse
EclipseCon 2010 tutorial: Understanding git at EclipseEclipseCon 2010 tutorial: Understanding git at Eclipse
EclipseCon 2010 tutorial: Understanding git at Eclipse
msohn
 

Tendances (20)

SOLID principles
SOLID principlesSOLID principles
SOLID principles
 
Solid principles
Solid principlesSolid principles
Solid principles
 
PSR-7 and PSR-15, why can't you ignore them
PSR-7 and PSR-15, why can't you ignore themPSR-7 and PSR-15, why can't you ignore them
PSR-7 and PSR-15, why can't you ignore them
 
Laravel Introduction
Laravel IntroductionLaravel Introduction
Laravel Introduction
 
01 Php Introduction
01 Php Introduction01 Php Introduction
01 Php Introduction
 
REST API 디자인 개요
REST API 디자인 개요REST API 디자인 개요
REST API 디자인 개요
 
Design functional solutions in Java, a practical example
Design functional solutions in Java, a practical exampleDesign functional solutions in Java, a practical example
Design functional solutions in Java, a practical example
 
Git
GitGit
Git
 
Solid Principles
Solid PrinciplesSolid Principles
Solid Principles
 
Clean architecture with ddd layering in php
Clean architecture with ddd layering in phpClean architecture with ddd layering in php
Clean architecture with ddd layering in php
 
Solid Principles
Solid PrinciplesSolid Principles
Solid Principles
 
Build your own CDN with Varnish - Confoo 2022
Build your own CDN with Varnish - Confoo 2022Build your own CDN with Varnish - Confoo 2022
Build your own CDN with Varnish - Confoo 2022
 
Php operators
Php operatorsPhp operators
Php operators
 
Design principles - SOLID
Design principles - SOLIDDesign principles - SOLID
Design principles - SOLID
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
 
DDD on example of Symfony (SfCampUA14)
DDD on example of Symfony (SfCampUA14)DDD on example of Symfony (SfCampUA14)
DDD on example of Symfony (SfCampUA14)
 
Jenkins CI
Jenkins CIJenkins CI
Jenkins CI
 
Cross-domain requests with CORS
Cross-domain requests with CORSCross-domain requests with CORS
Cross-domain requests with CORS
 
EclipseCon 2010 tutorial: Understanding git at Eclipse
EclipseCon 2010 tutorial: Understanding git at EclipseEclipseCon 2010 tutorial: Understanding git at Eclipse
EclipseCon 2010 tutorial: Understanding git at Eclipse
 

Similaire à SOLID: the core principles of success of the Symfony web framework and of your applications

Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
patter
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
fiyuer
 
Developing your first application using FI-WARE
Developing your first application using FI-WAREDeveloping your first application using FI-WARE
Developing your first application using FI-WARE
Fermin Galan
 

Similaire à SOLID: the core principles of success of the Symfony web framework and of your applications (20)

Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Creating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 ComponentsCreating your own framework on top of Symfony2 Components
Creating your own framework on top of Symfony2 Components
 
Laravel for Web Artisans
Laravel for Web ArtisansLaravel for Web Artisans
Laravel for Web Artisans
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
Hexagonal architecture
Hexagonal architectureHexagonal architecture
Hexagonal architecture
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 
Hexagonal architecture in PHP
Hexagonal architecture in PHPHexagonal architecture in PHP
Hexagonal architecture in PHP
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 
Developing your first application using FI-WARE
Developing your first application using FI-WAREDeveloping your first application using FI-WARE
Developing your first application using FI-WARE
 
Introduction to Research Automation with Globus
Introduction to Research Automation with GlobusIntroduction to Research Automation with Globus
Introduction to Research Automation with Globus
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
Introduction to CodeIgniter
Introduction to CodeIgniterIntroduction to CodeIgniter
Introduction to CodeIgniter
 
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravel
 
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry PiGrâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
 

Plus de Vladyslav Riabchenko

Plus de Vladyslav Riabchenko (8)

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 : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applicationsSOLID : les principes à l’origine du succès de Symfony et de vos applications
SOLID : les principes à l’origine du succès de Symfony et de vos applications
 
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
 
Git
GitGit
Git
 
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
 

Dernier

%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 

Dernier (20)

Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT  - Elevating Productivity in Today's Agile EnvironmentHarnessing ChatGPT  - Elevating Productivity in Today's Agile Environment
Harnessing ChatGPT - Elevating Productivity in Today's Agile Environment
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 

SOLID: the core principles of success of the Symfony web framework and of your applications

  • 1. SOLID: the core principles of success of the Symfony web framework and of your applications Software Engineering Conference Russia 2018 October 12-13 Moscow RIABCHENKO Vladyslav
  • 2. https://vria.eu contact@vria.eu https://twitter.com/RiaVlad RIABCHENKO Vladyslav 5+ years full stack web-developer Symfony certified developer and contributor Technical architect at Webnet (France)
  • 3. Symfony 3 1. Symfony 2. SOLID 3. Single responsibility principle 4. Open/closed principle 5. Liskov substitution principle 6. Interface segregation principle 7. Dependency inversion principle Plan
  • 5. Symfony 5 2. PHP framework for web projects 1. Set of reusable PHP components MVC Pattern Model View HTTP Request Routing Controller HTTP Response
  • 6. Symfony 6 HttpKernel DependencyInjection HttpFoundation Routing EventDispatcher Heart of framework that manages HTTP request-response cycle Object-oriented layer for request, response, session, etc. Maps requests to variables (controller, path parameters) Mediator that allows decoupled components to communicate by dispatching events Service container that instantiates service objects out of configuration and injects their dependencies and 45 others including Security, Form, Console, Cache, Asset, Validator, Serializer, etc.
  • 7. Symfony 7 FrameworkBundle Configures Symfony components and glues them in web app. It registers services and event listeners. Bundles are reusable plugins that provide services, routes, controllers, templates, etc. Your code Provides routes, controllers, services, business logic, templates for your purpose. doctrine/orm DBAL and ORM libraries to communicate with databases. twig/twig Template engine.
  • 9. SOLID 9 – Single Responsibility Principle – Open/Closed Principle – Liskov Substitution Principle – Interface Segregation Principle – Dependency Inversion Principle Reusable Flexible Maintainable Understandable Fragile Duplicated Viscose Unreasonably complex SOLID helps to design a system that is … and avoid a system that is S O L I D
  • 11. Single responsibility principle 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 } } A class should have only a single responsibility. Responsibility is a reason to change.
  • 12. Single responsibility principle // 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) { ... } } // working with database at ORM and/or DBAL layer class ReportRepository { public function getLastThreeReportsByAuthor($author) { ... } public function searchBy($criteria) { ... } } Manager Exporter Repository 12
  • 13. Single responsibility principle 13 Feature : Store users in database Feature : Store orders in database Feature : Authenticate users against database (login form, HTTP auth, whatever…) Feature : On creation of order assign a currentrly connected user to it. Store user credentials in session and authenticate users at latter requests
  • 14. Single responsibility principle 14 SecurityContext Stores a user token setToken($token), getToken() Checks if a current user authorization isGranted('attr', $sub) AuthenticationProvider Authenticates a token UserProvider Retrieves or refreshes user from database EntityManager All interaction with database at ORM and DBAL levels OrderListener Your listener that modifies order before it gets inserted Injecting SecurityContext service in any EntityManager’s listener created a circular dependency.
  • 15. Single responsibility principle 15 Solution is splitting SecurityContext into AuthorizationChecker and TokenStorage AuthorizationChecker AuthenticationProvider UserProvider EntityManager OrderListener TokenStorage getToken() setToken($token) isGranted('attr', $sub)
  • 17. Open/closed principle Entities should be open for extension, but closed for modification. 17 Open for extension: • Alter or add behavior • Extend an entity with new properties Closed for modification: • Adapt entity without modifying its source code • Provide an entity with clear and stable interface
  • 18. Open/closed principle 18 Techniques to stay in compliance with the open/closed principle: • Abstraction / Inheritance / Polymorphism • Dependency injection • Single responsibility principle • Design patterns. For example, those of GoF: • Abstract Factory, Factory Method, Builder, Prototype, • Bridge, Decorator, Proxy, • Command, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor.
  • 19. SymfonyComponentHttpKernel App Open/closed principle 19 // 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() All HTTP requests are treated by front controller.
  • 20. Open/closed principle 20 Request-Response cycle is open for extension thanks to events dispatched at every step. Request Response resolve controller REQUEST resolve arguments call controller CONTROLLER CONTROLLER_ARGUMENTS Response RESPONSE FINISH_REQUEST Response exists TERMINATE VIEW Exception EXCEPTION
  • 22. Liskov substitution principle Objects should be replaceable with instances of their subtypes without altering the correctness of the program. 22 LSP describes behavioral subtyping – semantic rather than merely syntactic relation.
  • 23. Liskov substitution principle 23 Rectangle Square is a regular rectangle with four equal sides. - 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); } Client will fail when you pass Square object class Square extends Rectangle { public function setWidth($width) { $this->width = $width; $this->height = $width; } public function setHeight($height) { $this->height = $height; $this->width = $height; } }
  • 24. Liskov substitution principle 24 • Preconditions cannot be strengthened in a subtype • Postconditions cannot be weakened in a subtype • Invariants of the supertype must be preserved in a subtype LSP suggests behavioral conditions resembling those of design by contract methodology: Rectangle Precondition: width is integer > 0 Postcondition: $this->width equals $width Invariant: $this->height remains unchanged Precondition: width is integer > 0 Postcondition: $this->width equals $width Invariant: $this->height remains unchanged Invariant: $this->width equals $this->height - width - height + setWidth($width) + setHeight($height) + getArea() + setWidth($width) + setHeight($height) Square
  • 25. Liskov substitution principle 25 Authorization – verifying access rights/privileges of currently authenticated user. In Symfony authorization is based on: • Token: the user’s authentication information (roles, etc.), • Attributes: rights/privileges to verify the access to, • Object: Any object for which access control needs to be checked. $authorizationChecker->isGranted('ROLE_ADMIN'); $authorizationChecker->isGranted('EDIT’, $comment); $authorizationChecker->isGranted(['VIEW', 'MANAGE'], $order);
  • 26. Liskov substitution principle 26 - voters : VoterInterface[] + decide($token, $attributes, $object) AuthorizationChecker - tokenStorage - accessDecisionManager + isGranted($attributes, $object) AccessDecisionManager + vote($token, $subject, $attributes) VoterInterface isGranted returns true/false. It delegates decision to AccessDecisionManager::decide. decide asks all voters to vote and returns final decision. vote must return one of these values : ACCESS_GRANTED, ACCESS_ABSTAIN or ACCESS_DENIED.
  • 27. DoctrineORM Liskov substitution principle 27 Doctrine is several PHP libraries focused on database storage and object mapping. Instance of Article id: 17 author: Author(id=3, name=Marie) createdAt: DateTime(2018-10-01) text: "Hi Secrus! Today we…" Instance of 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 …
  • 28. Liskov substitution principle 28 Doctrine triggers a bunch of events during the life-time of stored entities: prePersist and postPersist, preUpdate and postUpdate, preRemove and postRemove. 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()); } } Precondition: $event->getEntity() is an instance of Article
  • 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); } } } Liskov substitution principle 29 Precondition: $event->getEntity() is an instance of any entity Doctrine listeners as services have access to other services via dependency injection :
  • 31. Interface segregation principle 31 Many client-specific interfaces are better than one general-purpose interface. No client should be forced to depend on methods it does not use.
  • 32. Interface segregation principle 32 Service container Configuraion: yaml, xml, php For each service: - id - class name - dependencies - … - Instantiate service object on demand - Instantiate its dependencies - Inject dependencies into service - Store and return the service - Return the same instance on consecutive demands “Compilation” Container manages services which are any useful objects.
  • 33. PsrContainer Interface segregation principle 33 Fetch services ContainerInterface + get($id): mixed + has($id): bool SymfonyComponentDependencyInjection ContainerInterface + set($id, $service) + initialized($id): bool + getParameter($name): mixed Container - services - parameterBag - aliases + compile() Configure services, parameters Compile container (init, cache) (Any client code) (Extensions) (Kernel)
  • 34. Interface segregation principle 34 Routes configuration Url matcher '_route’ => string 'blog_list' '_controller' => string 'AppControllerBlog::list' 'page’ => string '2' 'category’ => string 'secr-conference' Url generator '/blog/secr-conference' '/blog/secr/2' $matcher->match('/blog/secr-conference/2'); $generator->generate('blog_list', ['category' => 'secr-conference']); $generator->generate('blog_list', ['category' => 'secr', 'page' => 2]); # config/routes.yaml blog_list: # route name path: /blog/{category}/{page} # path pattern controller: AppControllerBlog::list # controller to execute requirements: # param constraints category: '[a-z0-9-_]+' page: 'd+' defaults: # param default values page: 1
  • 35. SymfonyComponentRouting Interface segregation principle 35 UrlMatcherInterface + match($pathinfo): array UrlGeneratorInterface + generate ($name, $parameters, $referenceType): string RouterInterface + getRouteCollection(): RouteCollection Router - collection: RouteCollection - options: array - context Contains the configuration of all known routes.
  • 37. Dependency inversion principle 37 High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
  • 38. Framework Dependency inversion principle 38 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
  • 39. Dependency inversion principle 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
  • 40. AbstractLogger Dependency inversion principle 40 More flexible solution Framework Monolog Kernel Logger LoggerInterface
  • 41. Dependency inversion principle 41 PsrLog SymfonyHTTPKernel Monolog Kernel Logger LoggerInterface PSR – PHP Standards Recommendations by FIG – Framework Interoperability Group SymfonyRouting Router SymfonySecurity Handlers ... ... ...
  • 42. Dependency inversion principle 42 Symfony uses interfaces and dependency injection everywhere. SymfonyForm SymfonyValidator ACMEValidator FormInterface Form ExtensionValidator ValidatorExtension ValidatorInterface Validator Validator - validator: ValidatorInterface FormExtensionInterface