SlideShare a Scribd company logo
How I started to love what
they call
Design Patterns
@samuelroze
Samuel Roze
Software Enginner @ Inviqa
Founder @ ContinuousPipe.io
4 twitter.com/samuelroze
4 github.com/sroze
4 sroze.io
I started years ago...
I probably wrote that
<?php
include 'header.php';
include 'pages/'. $_GET['page'].'.php';
include 'footer.php';
At some point I used Symfony
class EntityController extends Controller
{
public function myAction($identifier)
{
$entity = $this->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(Entity::class)
->find($identifier);
return $this->render('my-template.html.twig', [
'entity' => $entity,
]);
}
}
Then I updated my entity...
public function myAction(Request $request, $identifier)
{
// ...
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entity = $form->getData();
$doctrine->persist($entity);
$doctrine->flush($entity);
}
}
// ...
}
Then I even sent an email
// ...
if ($form->isValid()) {
$entity = $form->getData();
$doctrine->persist($entity);
$doctrine->flush($entity);
$mailer = $this->getContainer()->get('mailer');
$mailer->send(
// ...
);
}
// ...
And then...
It became unmaintanable
Design Patterns
A general reusable solution
to a commonly occurring
problem within a given
context.
1
Wikipedia
How I started to love design patterns
All the design patterns do
the same thing: control the
information flow.
1
Anthony Ferrara
Let's do some refactoring
class EntityController extends Controller
{
public function myAction(Request $request, $identifier)
{
$entity = $this->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(Entity::class)
->find($identifier);
$form = $this->createForm(EntityFormType::class, $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$entity = $form->getData();
$doctrine->persist($entity);
$doctrine->flush($entity);
$mailer = $this->getContainer()->get('mailer');
$mailer->send(
Swift_Message::newInstance()
->setBody('Hey, something was updated!')
);
}
return $this->render('my-template.html.twig', [
'entity' => $entity,
]);
}
}
Why do we refactor?
4 We want to reuse code
Why do we refactor?
4 We want to reuse code
4 So we delegate the responsibilities
Why do we refactor?
4 We want to reuse code
4 So we delegate the responsibilities
4 And improve the readability
Why do we refactor?
4 We want to reuse code
4 So we delegate the responsibilities
4 And improve the readability
4 And therefore we ensure maintainability
Why do we refactor?
4 We want to reuse code
4 So we delegate the responsibilities
4 And improve the readability
4 And therefore we ensure maintainability
4 By doing so we enable change
Adapter
How I started to love design patterns
Adapter
interface EntityRepository
{
public function find($identifier) : Entity;
public function save(Entity $entity) : Entity;
}
Adapter
final class DoctrineEntityRepository implements EntityRepository
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function find($identifier) : Entity
{
if (null === ($entity = $this->getDoctrineRepository()->find($identifier))) {
throw new EntityNotFound();
}
return $entity;
}
// ...
}
Adapter
final class DoctrineEntityRepository implements EntityRepository
{
// ...
public function save(Entity $entity) : Entity
{
$entity = $this->entityManager->merge($entity);
$this->entityManager->persist($entity);
$this->entityManager->flush($entity);
return $entity;
}
}
class EntityController extends Controller
{
public function myAction(Request $request, $identifier)
{
$entity = $this->getEntityRepository()->find($identifier);
// ...
if ($form->isValid()) {
$this->getEntityRepository()->save($entity);
$mailer = $this->getContainer()->get('mailer');
$mailer->send(
Swift_Message::newInstance()
->setBody('Hey, something was updated!')
);
}
}
}
/** @Route(service="controller.entity") **/
class EntityController
{
public function __construct(EntityRepository $entityRepository, /** ... **/)
{ /** ... **/ }
public function myAction(Request $request, $identifier)
{
$entity = $this->entityRepository->find($identifier);
// ...
if ($form->isValid()) {
$this->entityRepository->save($entity);
$this->mailer->send(
Swift_Message::newInstance()
->setBody('Hey, something was updated!')
);
}
}
}
The XML bit
<service id="entity.repository.doctrine"
class="AppInfrastructureDoctrineEntityRepository">
<argument type="service" id="doctrine.orm.entity_manager" />
</service>
The XML bit
<service id="entity.repository.doctrine"
class="AppInfrastructureDoctrineEntityRepository">
<argument type="service" id="doctrine.orm.entity_manager" />
</service>
<service id="entity.repository" alias="entity.repository.doctrine" />
The XML bit
<service id="entity.repository.doctrine"
class="AppInfrastructureDoctrineEntityRepository">
<argument type="service" id="doctrine.orm.entity_manager" />
</service>
<service id="entity.repository" alias="entity.repository.doctrine" />
<service id="controller.entity"
class="AppBundleControllerEntityController">
<argument type="service" id="entity.repository" />
<argument type="service" id="form.factory" />
<argument type="service" id="mailer" />
</service>
Store the entity in-memory?
final class InMemoryRepositoryEntity implements EntityRepository
{
private $entities = [];
public function find($identifier) : Entity
{
if (!array_key_exists($identifier, $this->entities)) {
throw new EntityNotFound();
}
return $this->entities[$identifier];
}
public function save(Entity $entity) : Entity
{
$this->entities[$entity->getIdentifier()] = $entity;
return $entity;
}
}
Event Dispatcher
How I started to love design patterns
Dispatching the event
class MyController
{
public function myAction(Request $request, $identifier)
{
// ...
if ($form->isValid()) {
$this->entityRepository->save($entity);
$this->eventDispatcher->dispatch(
EntitySaved::NAME,
new EntitySaved($entity)
);
}
// ...
}
}
An event
class EntitySaved extends Event
{
const NAME = 'entity.saved';
private $entity;
public function __construct(Entity $entity)
{
$this->entity = $entity;
}
public function getEntity() : Entity
{
return $this->entity;
}
}
A listener
final class SendAnEmailWhenEntityIsSaved
{
public function __construct(MailerInterface $mailer)
{ /** ... **/ }
public function onEntitySaved(EntitySaved $event)
{
$this->mailer->send(/** something **/);
}
}
Because we want some XML
<service id="controller.entity"
class="AppBundleControllerEntityController">
<argument type="service" id="entity.repository" />
<argument type="service" id="form.factory" />
<argument type="service" id="event_dispatcher" />
</service>
-
Because we want some XML
<service id="controller.entity"
class="AppBundleControllerEntityController">
<argument type="service" id="entity.repository" />
<argument type="service" id="form.factory" />
<argument type="service" id="event_dispatcher" />
</service>
<service id="entity.listener.send_mail_when_saved"
class="AppEntityListenerSendAnEmailWhenEntityIsSaved">
<argument type="service" id="mailer" />
<tag name="kernel.event_listener" event="entity.saved" />
</service>
What is the point?
4 We can create another listener easily
4 We just have to dispatch this event
Decorator
final class DispatchAnEventWhenEntityIsSaved implements EntityRepository
{
public function __construct(
EntityRepository $decoratedRepository,
EventDispatcherInterface $eventDispatcher
) { /** ... **/ }
public function find($identifier) : Entity
{
return $this->decoratedRepository($identifier);
}
public function save(Entity $entity) : Entity
{
$saved = $this->decoratedRepository->save($entity);
$this->eventDispatcher->dispatch(
EntitySaved::NAME, new EntitySaved($saved)
);
return $saved;
}
}
Decorates the repository
<service id="entity.repository.dispatch_an_event_when_saved"
class="AppEntityRepositoryDispatchAnEventWhenEntityIsSaved"
decorates="entity.repository">
<argument type="service"
id="entity.repository.dispatch_an_event_when_saved.inner" />
<argument type="service" id="event_dispatcher" />
</service>
We just have to save
class MyController
{
public function myAction(Request $request, $identifier)
{
// ...
if ($form->isValid()) {
$this->entityRepository->save($entity);
}
// ...
}
}
Decorates all the things!
What do we have?
4 Flexible entity storage
4 Events dispatched regarding the storage
4 Optional actions on events
4 Easily testable code!
Good practices, design
patterns, they just help us
to enable change
How to apply that...
4 Closes the door!
4 Uses final keyword
4 private properties
4 Create extension points when required
4 Prevent in case of
Maintainability
4 Distinct features in their own namespaces
4 Interfaces's names should reflect their
responsibilities
4 Implementations' names should reflect their
distinction
Thank you!
@samuelroze
continuouspipe.io
https://joind.in/talk/187a4
Ad

More Related Content

What's hot (20)

Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
Leonardo Proietti
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security Play
Kris Wallsmith
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
Jorn Oomen
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Colin O'Dell
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
Kris Wallsmith
 
Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)
Samuel ROZE
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Matters of State
Matters of StateMatters of State
Matters of State
Kris Wallsmith
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
Hugo Hamon
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)
GOG.com dev team
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
Kris Wallsmith
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
Ryan Weaver
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
Артём Курапов
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuery
sergioafp
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
Jakub Zalas
 
Cyclejs introduction
Cyclejs introductionCyclejs introduction
Cyclejs introduction
Arye Lukashevski
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
Leonardo Proietti
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security Play
Kris Wallsmith
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
Jorn Oomen
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Colin O'Dell
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
Kris Wallsmith
 
Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)Symfony Messenger (Symfony Live San Francisco)
Symfony Messenger (Symfony Live San Francisco)
Samuel ROZE
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
Hugo Hamon
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)Event sourcing w PHP (by Piotr Kacała)
Event sourcing w PHP (by Piotr Kacała)
GOG.com dev team
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
Kris Wallsmith
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
Ryan Weaver
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuery
sergioafp
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
Jakub Zalas
 

Viewers also liked (20)

Presentation Bulgaria PHP
Presentation Bulgaria PHPPresentation Bulgaria PHP
Presentation Bulgaria PHP
Alena Holligan
 
Conscious Coupling
Conscious CouplingConscious Coupling
Conscious Coupling
CiaranMcNulty
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016
CiaranMcNulty
 
Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...
Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...
Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...
James Titcumb
 
php[world] 2015 Training - Laravel from the Ground Up
php[world] 2015 Training - Laravel from the Ground Upphp[world] 2015 Training - Laravel from the Ground Up
php[world] 2015 Training - Laravel from the Ground Up
Joe Ferguson
 
Engineer - Mastering the Art of Software
Engineer - Mastering the Art of SoftwareEngineer - Mastering the Art of Software
Engineer - Mastering the Art of Software
Cristiano Diniz da Silva
 
Hack the Future
Hack the FutureHack the Future
Hack the Future
Jason McCreary
 
Create, test, secure, repeat
Create, test, secure, repeatCreate, test, secure, repeat
Create, test, secure, repeat
Michelangelo van Dam
 
Amp your site an intro to accelerated mobile pages
Amp your site  an intro to accelerated mobile pagesAmp your site  an intro to accelerated mobile pages
Amp your site an intro to accelerated mobile pages
Robert McFrazier
 
Zend Framework Foundations
Zend Framework FoundationsZend Framework Foundations
Zend Framework Foundations
Chuck Reeves
 
Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:win Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:win
Joe Ferguson
 
Dip Your Toes in the Sea of Security
Dip Your Toes in the Sea of SecurityDip Your Toes in the Sea of Security
Dip Your Toes in the Sea of Security
James Titcumb
 
Code Coverage for Total Security in Application Migrations
Code Coverage for Total Security in Application MigrationsCode Coverage for Total Security in Application Migrations
Code Coverage for Total Security in Application Migrations
Dana Luther
 
Git Empowered
Git EmpoweredGit Empowered
Git Empowered
Jason McCreary
 
Php extensions
Php extensionsPhp extensions
Php extensions
Elizabeth Smith
 
SunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQLSunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQL
Gabriela Ferrara
 
200K+ reasons security is a must
200K+ reasons security is a must200K+ reasons security is a must
200K+ reasons security is a must
Michelangelo van Dam
 
Modern sql
Modern sqlModern sql
Modern sql
Elizabeth Smith
 
Intermediate OOP in PHP
Intermediate OOP in PHPIntermediate OOP in PHP
Intermediate OOP in PHP
David Stockton
 
PHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix It
PHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix ItPHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix It
PHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix It
Matt Toigo
 
Presentation Bulgaria PHP
Presentation Bulgaria PHPPresentation Bulgaria PHP
Presentation Bulgaria PHP
Alena Holligan
 
Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016Modelling by Example Workshop - PHPNW 2016
Modelling by Example Workshop - PHPNW 2016
CiaranMcNulty
 
Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...
Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...
Adding 1.21 Gigawatts to Applications with RabbitMQ (Bulgaria PHP 2016 - Tuto...
James Titcumb
 
php[world] 2015 Training - Laravel from the Ground Up
php[world] 2015 Training - Laravel from the Ground Upphp[world] 2015 Training - Laravel from the Ground Up
php[world] 2015 Training - Laravel from the Ground Up
Joe Ferguson
 
Amp your site an intro to accelerated mobile pages
Amp your site  an intro to accelerated mobile pagesAmp your site  an intro to accelerated mobile pages
Amp your site an intro to accelerated mobile pages
Robert McFrazier
 
Zend Framework Foundations
Zend Framework FoundationsZend Framework Foundations
Zend Framework Foundations
Chuck Reeves
 
Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:win Console Apps: php artisan forthe:win
Console Apps: php artisan forthe:win
Joe Ferguson
 
Dip Your Toes in the Sea of Security
Dip Your Toes in the Sea of SecurityDip Your Toes in the Sea of Security
Dip Your Toes in the Sea of Security
James Titcumb
 
Code Coverage for Total Security in Application Migrations
Code Coverage for Total Security in Application MigrationsCode Coverage for Total Security in Application Migrations
Code Coverage for Total Security in Application Migrations
Dana Luther
 
SunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQLSunshinePHP 2017 - Making the most out of MySQL
SunshinePHP 2017 - Making the most out of MySQL
Gabriela Ferrara
 
Intermediate OOP in PHP
Intermediate OOP in PHPIntermediate OOP in PHP
Intermediate OOP in PHP
David Stockton
 
PHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix It
PHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix ItPHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix It
PHP World DC 2015 - What Can Go Wrong with Agile Development and How to Fix It
Matt Toigo
 
Ad

Similar to How I started to love design patterns (20)

ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleDrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
Alexander Varwijk
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
Massimiliano Arione
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
velveeta_512
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
Stephan Hochdörfer
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
Lars Jankowfsky
 
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
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
Daniel Knell
 
A resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleA resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangle
Akihito Koriyama
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
Jeroen van Dijk
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
Fabien Potencier
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
Matthias Noback
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
Vrann Tulika
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
Mariusz Kozłowski
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
Fernando Daciuk
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
Ryunosuke SATO
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
Nate Abele
 
Be pragmatic, be SOLID
Be pragmatic, be SOLIDBe pragmatic, be SOLID
Be pragmatic, be SOLID
Krzysztof Menżyk
 
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
PROIDEA
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
Basuke Suzuki
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleDrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
Alexander Varwijk
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
velveeta_512
 
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
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
Daniel Knell
 
A resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleA resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangle
Akihito Koriyama
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
Jeroen van Dijk
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
Fabien Potencier
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
Matthias Noback
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
Vrann Tulika
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
Fernando Daciuk
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
Nate Abele
 
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
4Developers 2015: Be pragmatic, be SOLID - Krzysztof Menżyk
PROIDEA
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
Basuke Suzuki
 
Ad

More from Samuel ROZE (9)

Event streaming: what will go wrong? (Symfony World 2020)
Event streaming: what will go wrong? (Symfony World 2020)Event streaming: what will go wrong? (Symfony World 2020)
Event streaming: what will go wrong? (Symfony World 2020)
Samuel ROZE
 
Living documentation
Living documentationLiving documentation
Living documentation
Samuel ROZE
 
Micro services may not be the best idea
Micro services may not be the best ideaMicro services may not be the best idea
Micro services may not be the best idea
Samuel ROZE
 
Take care of our micro services
Take care of our micro servicesTake care of our micro services
Take care of our micro services
Samuel ROZE
 
(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance
Samuel ROZE
 
Using continuouspipe to speed up our workflows
Using continuouspipe to speed up our workflowsUsing continuouspipe to speed up our workflows
Using continuouspipe to speed up our workflows
Samuel ROZE
 
Behat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than thatBehat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than that
Samuel ROZE
 
Docker orchestration with Kubernetes
Docker orchestration with KubernetesDocker orchestration with Kubernetes
Docker orchestration with Kubernetes
Samuel ROZE
 
Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer
Samuel ROZE
 
Event streaming: what will go wrong? (Symfony World 2020)
Event streaming: what will go wrong? (Symfony World 2020)Event streaming: what will go wrong? (Symfony World 2020)
Event streaming: what will go wrong? (Symfony World 2020)
Samuel ROZE
 
Living documentation
Living documentationLiving documentation
Living documentation
Samuel ROZE
 
Micro services may not be the best idea
Micro services may not be the best ideaMicro services may not be the best idea
Micro services may not be the best idea
Samuel ROZE
 
Take care of our micro services
Take care of our micro servicesTake care of our micro services
Take care of our micro services
Samuel ROZE
 
(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance(micro)services avec Symfony et Tolerance
(micro)services avec Symfony et Tolerance
Samuel ROZE
 
Using continuouspipe to speed up our workflows
Using continuouspipe to speed up our workflowsUsing continuouspipe to speed up our workflows
Using continuouspipe to speed up our workflows
Samuel ROZE
 
Behat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than thatBehat c'est plus que ça | Behat is more than that
Behat c'est plus que ça | Behat is more than that
Samuel ROZE
 
Docker orchestration with Kubernetes
Docker orchestration with KubernetesDocker orchestration with Kubernetes
Docker orchestration with Kubernetes
Samuel ROZE
 
Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer Symfony et serialization avec JMS serializer
Symfony et serialization avec JMS serializer
Samuel ROZE
 

Recently uploaded (20)

Degree_of_Automation.pdf for Instrumentation and industrial specialist
Degree_of_Automation.pdf for  Instrumentation  and industrial specialistDegree_of_Automation.pdf for  Instrumentation  and industrial specialist
Degree_of_Automation.pdf for Instrumentation and industrial specialist
shreyabhosale19
 
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptxExplainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
MahaveerVPandit
 
fluke dealers in bangalore..............
fluke dealers in bangalore..............fluke dealers in bangalore..............
fluke dealers in bangalore..............
Haresh Vaswani
 
Structural Response of Reinforced Self-Compacting Concrete Deep Beam Using Fi...
Structural Response of Reinforced Self-Compacting Concrete Deep Beam Using Fi...Structural Response of Reinforced Self-Compacting Concrete Deep Beam Using Fi...
Structural Response of Reinforced Self-Compacting Concrete Deep Beam Using Fi...
Journal of Soft Computing in Civil Engineering
 
IntroSlides-April-BuildWithAI-VertexAI.pdf
IntroSlides-April-BuildWithAI-VertexAI.pdfIntroSlides-April-BuildWithAI-VertexAI.pdf
IntroSlides-April-BuildWithAI-VertexAI.pdf
Luiz Carneiro
 
Compiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptxCompiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptx
RushaliDeshmukh2
 
DT REPORT by Tech titan GROUP to introduce the subject design Thinking
DT REPORT by Tech titan GROUP to introduce the subject design ThinkingDT REPORT by Tech titan GROUP to introduce the subject design Thinking
DT REPORT by Tech titan GROUP to introduce the subject design Thinking
DhruvChotaliya2
 
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
inmishra17121973
 
Reagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptxReagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptx
AlejandroOdio
 
Introduction to Zoomlion Earthmoving.pptx
Introduction to Zoomlion Earthmoving.pptxIntroduction to Zoomlion Earthmoving.pptx
Introduction to Zoomlion Earthmoving.pptx
AS1920
 
Avnet Silica's PCIM 2025 Highlights Flyer
Avnet Silica's PCIM 2025 Highlights FlyerAvnet Silica's PCIM 2025 Highlights Flyer
Avnet Silica's PCIM 2025 Highlights Flyer
WillDavies22
 
Artificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptxArtificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptx
aditichinar
 
Smart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptxSmart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptx
rushikeshnavghare94
 
Raish Khanji GTU 8th sem Internship Report.pdf
Raish Khanji GTU 8th sem Internship Report.pdfRaish Khanji GTU 8th sem Internship Report.pdf
Raish Khanji GTU 8th sem Internship Report.pdf
RaishKhanji
 
Machine learning project on employee attrition detection using (2).pptx
Machine learning project on employee attrition detection using (2).pptxMachine learning project on employee attrition detection using (2).pptx
Machine learning project on employee attrition detection using (2).pptx
rajeswari89780
 
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdfMAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
ssuser562df4
 
15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...
IJCSES Journal
 
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Journal of Soft Computing in Civil Engineering
 
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITYADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ijscai
 
Level 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical SafetyLevel 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical Safety
JoseAlbertoCariasDel
 
Degree_of_Automation.pdf for Instrumentation and industrial specialist
Degree_of_Automation.pdf for  Instrumentation  and industrial specialistDegree_of_Automation.pdf for  Instrumentation  and industrial specialist
Degree_of_Automation.pdf for Instrumentation and industrial specialist
shreyabhosale19
 
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptxExplainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
MahaveerVPandit
 
fluke dealers in bangalore..............
fluke dealers in bangalore..............fluke dealers in bangalore..............
fluke dealers in bangalore..............
Haresh Vaswani
 
IntroSlides-April-BuildWithAI-VertexAI.pdf
IntroSlides-April-BuildWithAI-VertexAI.pdfIntroSlides-April-BuildWithAI-VertexAI.pdf
IntroSlides-April-BuildWithAI-VertexAI.pdf
Luiz Carneiro
 
Compiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptxCompiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptx
RushaliDeshmukh2
 
DT REPORT by Tech titan GROUP to introduce the subject design Thinking
DT REPORT by Tech titan GROUP to introduce the subject design ThinkingDT REPORT by Tech titan GROUP to introduce the subject design Thinking
DT REPORT by Tech titan GROUP to introduce the subject design Thinking
DhruvChotaliya2
 
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
211421893-M-Tech-CIVIL-Structural-Engineering-pdf.pdf
inmishra17121973
 
Reagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptxReagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptx
AlejandroOdio
 
Introduction to Zoomlion Earthmoving.pptx
Introduction to Zoomlion Earthmoving.pptxIntroduction to Zoomlion Earthmoving.pptx
Introduction to Zoomlion Earthmoving.pptx
AS1920
 
Avnet Silica's PCIM 2025 Highlights Flyer
Avnet Silica's PCIM 2025 Highlights FlyerAvnet Silica's PCIM 2025 Highlights Flyer
Avnet Silica's PCIM 2025 Highlights Flyer
WillDavies22
 
Artificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptxArtificial Intelligence (AI) basics.pptx
Artificial Intelligence (AI) basics.pptx
aditichinar
 
Smart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptxSmart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptx
rushikeshnavghare94
 
Raish Khanji GTU 8th sem Internship Report.pdf
Raish Khanji GTU 8th sem Internship Report.pdfRaish Khanji GTU 8th sem Internship Report.pdf
Raish Khanji GTU 8th sem Internship Report.pdf
RaishKhanji
 
Machine learning project on employee attrition detection using (2).pptx
Machine learning project on employee attrition detection using (2).pptxMachine learning project on employee attrition detection using (2).pptx
Machine learning project on employee attrition detection using (2).pptx
rajeswari89780
 
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdfMAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
ssuser562df4
 
15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...15th International Conference on Computer Science, Engineering and Applicatio...
15th International Conference on Computer Science, Engineering and Applicatio...
IJCSES Journal
 
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITYADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ijscai
 
Level 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical SafetyLevel 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical Safety
JoseAlbertoCariasDel
 

How I started to love design patterns

  • 1. How I started to love what they call Design Patterns @samuelroze
  • 2. Samuel Roze Software Enginner @ Inviqa Founder @ ContinuousPipe.io 4 twitter.com/samuelroze 4 github.com/sroze 4 sroze.io
  • 4. I probably wrote that <?php include 'header.php'; include 'pages/'. $_GET['page'].'.php'; include 'footer.php';
  • 5. At some point I used Symfony class EntityController extends Controller { public function myAction($identifier) { $entity = $this->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository(Entity::class) ->find($identifier); return $this->render('my-template.html.twig', [ 'entity' => $entity, ]); } }
  • 6. Then I updated my entity... public function myAction(Request $request, $identifier) { // ... if ($request->isMethod('POST')) { $form->handleRequest($request); if ($form->isValid()) { $entity = $form->getData(); $doctrine->persist($entity); $doctrine->flush($entity); } } // ... }
  • 7. Then I even sent an email // ... if ($form->isValid()) { $entity = $form->getData(); $doctrine->persist($entity); $doctrine->flush($entity); $mailer = $this->getContainer()->get('mailer'); $mailer->send( // ... ); } // ...
  • 8. And then... It became unmaintanable
  • 10. A general reusable solution to a commonly occurring problem within a given context. 1 Wikipedia
  • 12. All the design patterns do the same thing: control the information flow. 1 Anthony Ferrara
  • 13. Let's do some refactoring class EntityController extends Controller { public function myAction(Request $request, $identifier) { $entity = $this->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository(Entity::class) ->find($identifier); $form = $this->createForm(EntityFormType::class, $entity); $form->handleRequest($request); if ($form->isValid()) { $entity = $form->getData(); $doctrine->persist($entity); $doctrine->flush($entity); $mailer = $this->getContainer()->get('mailer'); $mailer->send( Swift_Message::newInstance() ->setBody('Hey, something was updated!') ); } return $this->render('my-template.html.twig', [ 'entity' => $entity, ]); } }
  • 14. Why do we refactor? 4 We want to reuse code
  • 15. Why do we refactor? 4 We want to reuse code 4 So we delegate the responsibilities
  • 16. Why do we refactor? 4 We want to reuse code 4 So we delegate the responsibilities 4 And improve the readability
  • 17. Why do we refactor? 4 We want to reuse code 4 So we delegate the responsibilities 4 And improve the readability 4 And therefore we ensure maintainability
  • 18. Why do we refactor? 4 We want to reuse code 4 So we delegate the responsibilities 4 And improve the readability 4 And therefore we ensure maintainability 4 By doing so we enable change
  • 21. Adapter interface EntityRepository { public function find($identifier) : Entity; public function save(Entity $entity) : Entity; }
  • 22. Adapter final class DoctrineEntityRepository implements EntityRepository { private $entityManager; public function __construct(EntityManager $entityManager) { $this->entityManager = $entityManager; } public function find($identifier) : Entity { if (null === ($entity = $this->getDoctrineRepository()->find($identifier))) { throw new EntityNotFound(); } return $entity; } // ... }
  • 23. Adapter final class DoctrineEntityRepository implements EntityRepository { // ... public function save(Entity $entity) : Entity { $entity = $this->entityManager->merge($entity); $this->entityManager->persist($entity); $this->entityManager->flush($entity); return $entity; } }
  • 24. class EntityController extends Controller { public function myAction(Request $request, $identifier) { $entity = $this->getEntityRepository()->find($identifier); // ... if ($form->isValid()) { $this->getEntityRepository()->save($entity); $mailer = $this->getContainer()->get('mailer'); $mailer->send( Swift_Message::newInstance() ->setBody('Hey, something was updated!') ); } } }
  • 25. /** @Route(service="controller.entity") **/ class EntityController { public function __construct(EntityRepository $entityRepository, /** ... **/) { /** ... **/ } public function myAction(Request $request, $identifier) { $entity = $this->entityRepository->find($identifier); // ... if ($form->isValid()) { $this->entityRepository->save($entity); $this->mailer->send( Swift_Message::newInstance() ->setBody('Hey, something was updated!') ); } } }
  • 26. The XML bit <service id="entity.repository.doctrine" class="AppInfrastructureDoctrineEntityRepository"> <argument type="service" id="doctrine.orm.entity_manager" /> </service>
  • 27. The XML bit <service id="entity.repository.doctrine" class="AppInfrastructureDoctrineEntityRepository"> <argument type="service" id="doctrine.orm.entity_manager" /> </service> <service id="entity.repository" alias="entity.repository.doctrine" />
  • 28. The XML bit <service id="entity.repository.doctrine" class="AppInfrastructureDoctrineEntityRepository"> <argument type="service" id="doctrine.orm.entity_manager" /> </service> <service id="entity.repository" alias="entity.repository.doctrine" /> <service id="controller.entity" class="AppBundleControllerEntityController"> <argument type="service" id="entity.repository" /> <argument type="service" id="form.factory" /> <argument type="service" id="mailer" /> </service>
  • 29. Store the entity in-memory? final class InMemoryRepositoryEntity implements EntityRepository { private $entities = []; public function find($identifier) : Entity { if (!array_key_exists($identifier, $this->entities)) { throw new EntityNotFound(); } return $this->entities[$identifier]; } public function save(Entity $entity) : Entity { $this->entities[$entity->getIdentifier()] = $entity; return $entity; } }
  • 32. Dispatching the event class MyController { public function myAction(Request $request, $identifier) { // ... if ($form->isValid()) { $this->entityRepository->save($entity); $this->eventDispatcher->dispatch( EntitySaved::NAME, new EntitySaved($entity) ); } // ... } }
  • 33. An event class EntitySaved extends Event { const NAME = 'entity.saved'; private $entity; public function __construct(Entity $entity) { $this->entity = $entity; } public function getEntity() : Entity { return $this->entity; } }
  • 34. A listener final class SendAnEmailWhenEntityIsSaved { public function __construct(MailerInterface $mailer) { /** ... **/ } public function onEntitySaved(EntitySaved $event) { $this->mailer->send(/** something **/); } }
  • 35. Because we want some XML <service id="controller.entity" class="AppBundleControllerEntityController"> <argument type="service" id="entity.repository" /> <argument type="service" id="form.factory" /> <argument type="service" id="event_dispatcher" /> </service> -
  • 36. Because we want some XML <service id="controller.entity" class="AppBundleControllerEntityController"> <argument type="service" id="entity.repository" /> <argument type="service" id="form.factory" /> <argument type="service" id="event_dispatcher" /> </service> <service id="entity.listener.send_mail_when_saved" class="AppEntityListenerSendAnEmailWhenEntityIsSaved"> <argument type="service" id="mailer" /> <tag name="kernel.event_listener" event="entity.saved" /> </service>
  • 37. What is the point? 4 We can create another listener easily 4 We just have to dispatch this event
  • 39. final class DispatchAnEventWhenEntityIsSaved implements EntityRepository { public function __construct( EntityRepository $decoratedRepository, EventDispatcherInterface $eventDispatcher ) { /** ... **/ } public function find($identifier) : Entity { return $this->decoratedRepository($identifier); } public function save(Entity $entity) : Entity { $saved = $this->decoratedRepository->save($entity); $this->eventDispatcher->dispatch( EntitySaved::NAME, new EntitySaved($saved) ); return $saved; } }
  • 40. Decorates the repository <service id="entity.repository.dispatch_an_event_when_saved" class="AppEntityRepositoryDispatchAnEventWhenEntityIsSaved" decorates="entity.repository"> <argument type="service" id="entity.repository.dispatch_an_event_when_saved.inner" /> <argument type="service" id="event_dispatcher" /> </service>
  • 41. We just have to save class MyController { public function myAction(Request $request, $identifier) { // ... if ($form->isValid()) { $this->entityRepository->save($entity); } // ... } }
  • 42. Decorates all the things!
  • 43. What do we have? 4 Flexible entity storage 4 Events dispatched regarding the storage 4 Optional actions on events 4 Easily testable code!
  • 44. Good practices, design patterns, they just help us to enable change
  • 45. How to apply that... 4 Closes the door! 4 Uses final keyword 4 private properties 4 Create extension points when required 4 Prevent in case of
  • 46. Maintainability 4 Distinct features in their own namespaces 4 Interfaces's names should reflect their responsibilities 4 Implementations' names should reflect their distinction