SlideShare une entreprise Scribd logo
Open Close Principle,
on a dit étendre, pas extends !
Meetup AFUP, 12/02/2019, @tdutrion
Qui suis-je ?
Directeur technique chez Darkmira (on recrute)
Développeur back/consultant freelance (Engineor)
Organisateur (ScotlandPHP, DarkmiraTour Brasil,
AFUP Lorraine, Association Zend Francophone,
DijonTech)
Grand fan de PHP et son écosystème
Avant tout ingénieur logiciel adèpte de systèmes
legacy ! (fan de defensive programming)
Open Closed principle
Principe ouvert / fermé
Principes SOLID
Responsabilité unique (single responsibility)
Ouvert / fermé (open / closed)
Substitution de Liskov (Liskov substitution)
Ségrégation des interfaces (interface segregation)
Inversion des dépendances (dependency
inversion)
Open Close Principle
une classe doit être ouverte à l'extension, mais
fermée à la modi cation
“
“
« Ouverte » signi e qu'elle a la capacité d'être
étendue.
« Fermée » signi e qu'elle ne peut être modi ée
que par extension, sans modi cation de son code
source.
“
“
Oui mais comment ?
Avertissement :
Pour suivre les parties suivantes, le principe de
responsabilité unique est considéré comme acquis.
Use cases / exemples
logs
email
négociation de type de réponse
ajout de conditions métier
Approche naïve (~1988)
Bertrand Meyer : Héritage
Une classe non nale est extensible, car on peut en
hériter.
class AireCalculateur
{
public function carre(Carre $carre): float
{
return pow($carre->tailleCote());
}
public function cercle(Cercle $cercle): float
{
return pow($cercle->radius()) *pi();
}
// ...
// Autres formes
// ...
}
Héritage
surcharge de méthode
abstraction
abstract class Forme {
public abstract aire(): float;
}
class AireCalculateur
{
public function calcul(Forme $forme): float
{
return $forme->aire();
}
}
Abstraction
class Carre
{
private $tailleCote;
public function aire(): float
{
return pow($this->tailleCote);
}
}
class Cercle
{
private $radius;
public function aire(): float
{
return pow($this->radius) * pi();
}
}
Composition
Ajout business : nous devons maintenant calculer
l'aire de choses dans deux contextes différents.
Par exemple :
géométrie (ci-dessus)
métier (par exemple aire de surface au sol d'un
pneu de voiture)
L'héritage devient étrange...
Qu'avons nous appris depuis?
Design patterns
decorator
observer
visitor
speci cation
strategy
Decorator
class MonRepository
{
public function get(Uuid $identifier): MonEntite
{
// whatever
// return [MonEntite]
}
}
$repo = new MonRepository();
$repo->get($monEntite); // pas de logs
le client a besoin de logs sur un repository“ “
class MonLoggerRepository extends MonRepository
{
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function get(Uuid $identifier): MonEntite
{
$this->logger->debug('faut mettre un truc là');
$instance = parent::get($identifier);
$this->logger->debug('ça devient verbeux');
return $instance;
}
}
$repo = new MonLoggerRepository();
$repo->get($identifier); // log
class MonLoggerRepository extends MonRepository
{
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function get(Uuid $identifier): MonEntite
{
$this->logger->debug('faut mettre un truc là');
$instance = parent::get($identifier);
$this->logger->debug('ça devient verbeux');
return $instance;
}
}
$repo = new MonLoggerRepository();
$repo->save($monEntite); // log
interface MonRepository
{
public function get(Uuid $identifier): MonEntite;
}
final class MonImplementationRepository
implements MonRepository
{
public function get(Uuid $identifier): MonEntite
{
return new MonEntite;
}
}
final class MonLoggerRepository
implements MonRepository
{
public function __construct(
LoggerInterface $logger,
MonRepository $repository
) {
$this->logger = $logger;
$this->repository = $repository;
}
public function get(Uuid $identifier): MonEntite
{
$this->logger->debug('faut mettre un truc là');
$instance = $this->repository->get($identifier);
$this->logger->debug('ça devient verbeux');
return $instance;
}
}
Ajoutons un cache :
final class MonCacheRepository implements MonRepository
{
public function __construct(CacheInterface $cache, MonReposi
$this->cache = $cache;
$this->repository = $repository;
}
public function get(Uuid $identifier): MonEntite
{
if ($this->cache->has(self::CACHE_KEY)) {
return $this->cache->get(self::CACHE_KEY);
}
$instance = $this->repository->get($identifier);
$this->cache->set(self::CACHE_KEY, $instance);
return $instance;
}
}
Utilisation
// $cache =
// $logger =
$repo = new MonCacheRepository(
MonLoggerRepository(
MonImplementationRepository(), $logger
), $cache
);
// $cache =
// $logger =
$repo = new MonLoggerRepository(
$logger, MonCacheRepository(
$cache, MonImplementationRepository()
)
);
Simpli ons
Dépendances :
interface CacheInterface
{
public function get(string $cle): MonEntite;
public function has(): bool;
public function set(MonEntite $entite, string $cle): void
}
interface LoggerInterface
{
public function debug(string $details): void;
}
$container = [
MonRepository::class => function($container) {
return $container[MonLoggerRepository::class]($container
},
MonLoggerRepository::class => function($container) {
return new MonLoggerRepository(
$container[LoggerInterface::class]($container),
$container[MonCacheRepository::class]($container)
);
},
MonCacheRepository::class => function($container) {
return new MonCacheRepository(
$container[CacheInterface::class]($container),
$container[MonImplementationRepository::class]($cont
);
},
MonImplementationRepository::class => function($container)
return new MonImplementationRepository();
},
// to be continued
CacheInterface::class => function($container) {
return new class implements CacheInterface {
public function get(string $cle): MonEntite
{
return new MonEntite;
}
public function has(): bool { return false; }
public function set(MonEntite $entite, string $cle)
};
},
LoggerInterface::class => function($container) {
return new class implements LoggerInterface {
public function debug(string $details): void
{
}
};
},
];
Appel complet
$factory = $container[MonRepository::class];
$repo = $factory($container);
var_dump($repo);
reportez-vous au D de SOLID pour simpli er (ici
MonRepository )
“
“
Tout le monde fait du SF maintenant
Demo time!
composer create-project symfony/skeleton
composer req twig
...
AppRepositoryMonRepository:
alias: AppRepositoryMonImplementationRepository
AppRepositoryMonLoggerRepository:
decorates: AppRepositoryMonImplementationRepository
Avec les deux :
AppRepositoryMonRepository:
alias: AppRepositoryMonImplementationRepository
AppRepositoryMonLoggerRepository:
decorates: AppRepositoryMonImplementationRepository
arguments: [
'@AppLoggerInterface',
'@AppRepositoryMonLoggerRepository.inner'
]
AppRepositoryMonCacheRepository:
decorates: AppRepositoryMonImplementationRepository
arguments: [
'@AppCacheInterface',
'@AppRepositoryMonCacheRepository.inner'
]
Bonus :
decoration_priority: 1
Observer
En Symfony : les evènements
(vous connaissez plus hein )
final class MonImplementationRepository
{
private $dispatcher;
public function __construct(
EventDispatcherInterface $dispatcher
) {
$this->dispatcher = $dispatcher;
}
public function get(Uuid $identifier): MonEntite
{
$this->dispatcher->dispatch('mon_super_event.pre',
$value = new MonEntite;
$this->dispatcher->dispatch('mon_super_event.post',
return $value;
}
}
final class RepositoryGetListener
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function demo(MonSuperEvent $event)
{
$this->logger->debug("Quelqu'un a récup un truc");
}
}
AppListenerRepositoryGetListener:
tags:
- name: kernel.event_listener
event: mon_super_event.pre
method: demo
Cadeau : event dans un decorator
final class MonEventRepository implements MonRepository
{
private $repository;
private $dispatcher;
public function __construct(EventDispatcherInterface $dispat
{
$this->repository = $repository;
$this->dispatcher = $dispatcher;
}
public function get(Uuid $identifier): MonEntite
{
$this->dispatcher->dispatch('mon_super_event.pre',
$instance = $this->repository->get($identifier);
$this->dispatcher->dispatch('mon_super_event.post',
return $instance;
Open close principle, on a dit étendre, pas extends !

Contenu connexe

Tendances

La première partie de la présentation PHP
La première partie de la présentation PHPLa première partie de la présentation PHP
La première partie de la présentation PHP
Club Scientifique de l'ESI - CSE
 
.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP
Abdoulaye Dieng
 
Programmation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulationProgrammation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulation
ECAM Brussels Engineering School
 
Introduction à Python
Introduction à PythonIntroduction à Python
Introduction à Python
Abdoulaye Dieng
 
PHP5 et les fichiers
PHP5 et les fichiersPHP5 et les fichiers
PHP5 et les fichiers
Jean-Marie Renouard
 
Gestion de formulaires en PHP
Gestion de formulaires en PHPGestion de formulaires en PHP
Gestion de formulaires en PHP
Jean-Marie Renouard
 
Partie 5: Mémoire Dynamique — Programmation orientée objet en C++
Partie 5: Mémoire Dynamique — Programmation orientée objet en C++Partie 5: Mémoire Dynamique — Programmation orientée objet en C++
Partie 5: Mémoire Dynamique — Programmation orientée objet en C++
Fabio Hernandez
 
Cours php
Cours phpCours php
Cours php
csskaled
 
Réutilisabilité du code PHP
Réutilisabilité du code PHPRéutilisabilité du code PHP
Réutilisabilité du code PHP
Nicolas Le Nardou
 
Client base de données en PHP5
Client base de données en PHP5Client base de données en PHP5
Client base de données en PHP5
Jean-Marie Renouard
 
PHP 1 - Apprendre les bases
PHP 1 - Apprendre les basesPHP 1 - Apprendre les bases
PHP 1 - Apprendre les bases
Pierre Faure
 
Python For Data Science - French Course
Python For Data Science - French CoursePython For Data Science - French Course
Python For Data Science - French Course
Haytam EL YOUSSFI
 
[FR] Injection de dépendances, Containers & PHP-DI
[FR] Injection de dépendances, Containers & PHP-DI[FR] Injection de dépendances, Containers & PHP-DI
[FR] Injection de dépendances, Containers & PHP-DI
matthieunapoli
 
Partie 10: Classes Génériques — Programmation orientée objet en C++
Partie 10: Classes Génériques — Programmation orientée objet en C++Partie 10: Classes Génériques — Programmation orientée objet en C++
Partie 10: Classes Génériques — Programmation orientée objet en C++
Fabio Hernandez
 
C++11 en 12 exemples simples
C++11 en 12 exemples simplesC++11 en 12 exemples simples
C++11 en 12 exemples simples
Pethrvs
 
Le client HTTP PHP5
Le client HTTP PHP5Le client HTTP PHP5
Le client HTTP PHP5
Jean-Marie Renouard
 

Tendances (17)

La première partie de la présentation PHP
La première partie de la présentation PHPLa première partie de la présentation PHP
La première partie de la présentation PHP
 
.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP.php1 : les fondamentaux du PHP
.php1 : les fondamentaux du PHP
 
Programmation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulationProgrammation orientée objet : Object, classe et encapsulation
Programmation orientée objet : Object, classe et encapsulation
 
Introduction à Python
Introduction à PythonIntroduction à Python
Introduction à Python
 
PHP5 et les fichiers
PHP5 et les fichiersPHP5 et les fichiers
PHP5 et les fichiers
 
Gestion de formulaires en PHP
Gestion de formulaires en PHPGestion de formulaires en PHP
Gestion de formulaires en PHP
 
Partie 5: Mémoire Dynamique — Programmation orientée objet en C++
Partie 5: Mémoire Dynamique — Programmation orientée objet en C++Partie 5: Mémoire Dynamique — Programmation orientée objet en C++
Partie 5: Mémoire Dynamique — Programmation orientée objet en C++
 
Cours php
Cours phpCours php
Cours php
 
Réutilisabilité du code PHP
Réutilisabilité du code PHPRéutilisabilité du code PHP
Réutilisabilité du code PHP
 
Client base de données en PHP5
Client base de données en PHP5Client base de données en PHP5
Client base de données en PHP5
 
PHP 1 - Apprendre les bases
PHP 1 - Apprendre les basesPHP 1 - Apprendre les bases
PHP 1 - Apprendre les bases
 
Python For Data Science - French Course
Python For Data Science - French CoursePython For Data Science - French Course
Python For Data Science - French Course
 
Cours php
Cours phpCours php
Cours php
 
[FR] Injection de dépendances, Containers & PHP-DI
[FR] Injection de dépendances, Containers & PHP-DI[FR] Injection de dépendances, Containers & PHP-DI
[FR] Injection de dépendances, Containers & PHP-DI
 
Partie 10: Classes Génériques — Programmation orientée objet en C++
Partie 10: Classes Génériques — Programmation orientée objet en C++Partie 10: Classes Génériques — Programmation orientée objet en C++
Partie 10: Classes Génériques — Programmation orientée objet en C++
 
C++11 en 12 exemples simples
C++11 en 12 exemples simplesC++11 en 12 exemples simples
C++11 en 12 exemples simples
 
Le client HTTP PHP5
Le client HTTP PHP5Le client HTTP PHP5
Le client HTTP PHP5
 

Similaire à Open close principle, on a dit étendre, pas extends !

Patterns and OOP in PHP
Patterns and OOP in PHPPatterns and OOP in PHP
Patterns and OOP in PHPjulien pauli
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logiciellecyrilgandon
 
Notions de base de JavaScript
Notions de base de JavaScriptNotions de base de JavaScript
Notions de base de JavaScript
Kristen Le Liboux
 
Function oop - bonnes pratiques ms tech days
Function   oop - bonnes pratiques ms tech daysFunction   oop - bonnes pratiques ms tech days
Function oop - bonnes pratiques ms tech daysJean-Pierre Vincent
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScript
Microsoft Technet France
 
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-PDO
Abdoulaye Dieng
 
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
Vladyslav Riabchenko
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
Valtech
 
programmation orienté objet c++
programmation orienté objet c++programmation orienté objet c++
programmation orienté objet c++
coursuniv
 
Php 7.4 2020-01-28 - afup
Php 7.4   2020-01-28 - afupPhp 7.4   2020-01-28 - afup
Php 7.4 2020-01-28 - afup
Julien Vinber
 
De legacy à symfony
De legacy à symfonyDe legacy à symfony
De legacy à symfony
Etienne Lachance
 
Php4 Mysql
Php4 MysqlPhp4 Mysql
Php4 Mysql
HamdiBaklouti
 
Quelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application webQuelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application web
5pidou
 
PHP 7 et Symfony 3
PHP 7 et Symfony 3PHP 7 et Symfony 3
PHP 7 et Symfony 3
Eddy RICHARD
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jquery
neuros
 
Présentation de DBAL en PHP (Nantes)
Présentation de DBAL en PHP (Nantes)Présentation de DBAL en PHP (Nantes)
Présentation de DBAL en PHP (Nantes)
Mickael Perraud
 

Similaire à Open close principle, on a dit étendre, pas extends ! (20)

Patterns and OOP in PHP
Patterns and OOP in PHPPatterns and OOP in PHP
Patterns and OOP in PHP
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logicielle
 
Notions de base de JavaScript
Notions de base de JavaScriptNotions de base de JavaScript
Notions de base de JavaScript
 
Function oop - bonnes pratiques ms tech days
Function   oop - bonnes pratiques ms tech daysFunction   oop - bonnes pratiques ms tech days
Function oop - bonnes pratiques ms tech days
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScript
 
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
 
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
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
 
programmation orienté objet c++
programmation orienté objet c++programmation orienté objet c++
programmation orienté objet c++
 
Php 7.4 2020-01-28 - afup
Php 7.4   2020-01-28 - afupPhp 7.4   2020-01-28 - afup
Php 7.4 2020-01-28 - afup
 
De legacy à symfony
De legacy à symfonyDe legacy à symfony
De legacy à symfony
 
Php4 Mysql
Php4 MysqlPhp4 Mysql
Php4 Mysql
 
Presentation JPA
Presentation JPAPresentation JPA
Presentation JPA
 
Quelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application webQuelle place pour le framework Rails dans le développement d'application web
Quelle place pour le framework Rails dans le développement d'application web
 
PHP 7 et Symfony 3
PHP 7 et Symfony 3PHP 7 et Symfony 3
PHP 7 et Symfony 3
 
PHP5 et Zend Framework
PHP5 et Zend FrameworkPHP5 et Zend Framework
PHP5 et Zend Framework
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jquery
 
Présentation de DBAL en PHP (Nantes)
Présentation de DBAL en PHP (Nantes)Présentation de DBAL en PHP (Nantes)
Présentation de DBAL en PHP (Nantes)
 
Hello mongo
Hello mongoHello mongo
Hello mongo
 

Plus de Engineor

AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack Encore
Engineor
 
Acceptance testing in php with Codeception - Techmeetup Edinburgh
Acceptance testing in php with Codeception - Techmeetup EdinburghAcceptance testing in php with Codeception - Techmeetup Edinburgh
Acceptance testing in php with Codeception - Techmeetup Edinburgh
Engineor
 
Codeception: introduction to php testing (v2 - Aberdeen php)
Codeception: introduction to php testing (v2 - Aberdeen php)Codeception: introduction to php testing (v2 - Aberdeen php)
Codeception: introduction to php testing (v2 - Aberdeen php)
Engineor
 
Apigility introduction v2 (glasgow php)
Apigility introduction v2 (glasgow php)Apigility introduction v2 (glasgow php)
Apigility introduction v2 (glasgow php)
Engineor
 
Introduction to Apigility
Introduction to ApigilityIntroduction to Apigility
Introduction to Apigility
Engineor
 
Codeception: introduction to php testing
Codeception: introduction to php testingCodeception: introduction to php testing
Codeception: introduction to php testing
Engineor
 

Plus de Engineor (6)

AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack Encore
 
Acceptance testing in php with Codeception - Techmeetup Edinburgh
Acceptance testing in php with Codeception - Techmeetup EdinburghAcceptance testing in php with Codeception - Techmeetup Edinburgh
Acceptance testing in php with Codeception - Techmeetup Edinburgh
 
Codeception: introduction to php testing (v2 - Aberdeen php)
Codeception: introduction to php testing (v2 - Aberdeen php)Codeception: introduction to php testing (v2 - Aberdeen php)
Codeception: introduction to php testing (v2 - Aberdeen php)
 
Apigility introduction v2 (glasgow php)
Apigility introduction v2 (glasgow php)Apigility introduction v2 (glasgow php)
Apigility introduction v2 (glasgow php)
 
Introduction to Apigility
Introduction to ApigilityIntroduction to Apigility
Introduction to Apigility
 
Codeception: introduction to php testing
Codeception: introduction to php testingCodeception: introduction to php testing
Codeception: introduction to php testing
 

Open close principle, on a dit étendre, pas extends !

  • 1. Open Close Principle, on a dit étendre, pas extends ! Meetup AFUP, 12/02/2019, @tdutrion
  • 2. Qui suis-je ? Directeur technique chez Darkmira (on recrute) Développeur back/consultant freelance (Engineor) Organisateur (ScotlandPHP, DarkmiraTour Brasil, AFUP Lorraine, Association Zend Francophone, DijonTech) Grand fan de PHP et son écosystème Avant tout ingénieur logiciel adèpte de systèmes legacy ! (fan de defensive programming)
  • 4. Principes SOLID Responsabilité unique (single responsibility) Ouvert / fermé (open / closed) Substitution de Liskov (Liskov substitution) Ségrégation des interfaces (interface segregation) Inversion des dépendances (dependency inversion)
  • 5. Open Close Principle une classe doit être ouverte à l'extension, mais fermée à la modi cation “ “ « Ouverte » signi e qu'elle a la capacité d'être étendue. « Fermée » signi e qu'elle ne peut être modi ée que par extension, sans modi cation de son code source. “ “
  • 7. Avertissement : Pour suivre les parties suivantes, le principe de responsabilité unique est considéré comme acquis.
  • 8. Use cases / exemples logs email négociation de type de réponse ajout de conditions métier
  • 9. Approche naïve (~1988) Bertrand Meyer : Héritage Une classe non nale est extensible, car on peut en hériter.
  • 10. class AireCalculateur { public function carre(Carre $carre): float { return pow($carre->tailleCote()); } public function cercle(Cercle $cercle): float { return pow($cercle->radius()) *pi(); } // ... // Autres formes // ... }
  • 11. Héritage surcharge de méthode abstraction abstract class Forme { public abstract aire(): float; } class AireCalculateur { public function calcul(Forme $forme): float { return $forme->aire(); } }
  • 12. Abstraction class Carre { private $tailleCote; public function aire(): float { return pow($this->tailleCote); } } class Cercle { private $radius; public function aire(): float { return pow($this->radius) * pi(); } }
  • 13. Composition Ajout business : nous devons maintenant calculer l'aire de choses dans deux contextes différents. Par exemple : géométrie (ci-dessus) métier (par exemple aire de surface au sol d'un pneu de voiture) L'héritage devient étrange...
  • 16. Decorator class MonRepository { public function get(Uuid $identifier): MonEntite { // whatever // return [MonEntite] } } $repo = new MonRepository(); $repo->get($monEntite); // pas de logs le client a besoin de logs sur un repository“ “
  • 17. class MonLoggerRepository extends MonRepository { public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function get(Uuid $identifier): MonEntite { $this->logger->debug('faut mettre un truc là'); $instance = parent::get($identifier); $this->logger->debug('ça devient verbeux'); return $instance; } } $repo = new MonLoggerRepository(); $repo->get($identifier); // log
  • 18.
  • 19. class MonLoggerRepository extends MonRepository { public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function get(Uuid $identifier): MonEntite { $this->logger->debug('faut mettre un truc là'); $instance = parent::get($identifier); $this->logger->debug('ça devient verbeux'); return $instance; } } $repo = new MonLoggerRepository(); $repo->save($monEntite); // log
  • 20.
  • 21.
  • 22. interface MonRepository { public function get(Uuid $identifier): MonEntite; } final class MonImplementationRepository implements MonRepository { public function get(Uuid $identifier): MonEntite { return new MonEntite; } }
  • 23. final class MonLoggerRepository implements MonRepository { public function __construct( LoggerInterface $logger, MonRepository $repository ) { $this->logger = $logger; $this->repository = $repository; } public function get(Uuid $identifier): MonEntite { $this->logger->debug('faut mettre un truc là'); $instance = $this->repository->get($identifier); $this->logger->debug('ça devient verbeux'); return $instance; } }
  • 24. Ajoutons un cache : final class MonCacheRepository implements MonRepository { public function __construct(CacheInterface $cache, MonReposi $this->cache = $cache; $this->repository = $repository; } public function get(Uuid $identifier): MonEntite { if ($this->cache->has(self::CACHE_KEY)) { return $this->cache->get(self::CACHE_KEY); } $instance = $this->repository->get($identifier); $this->cache->set(self::CACHE_KEY, $instance); return $instance; } }
  • 25. Utilisation // $cache = // $logger = $repo = new MonCacheRepository( MonLoggerRepository( MonImplementationRepository(), $logger ), $cache ); // $cache = // $logger = $repo = new MonLoggerRepository( $logger, MonCacheRepository( $cache, MonImplementationRepository() ) );
  • 26. Simpli ons Dépendances : interface CacheInterface { public function get(string $cle): MonEntite; public function has(): bool; public function set(MonEntite $entite, string $cle): void } interface LoggerInterface { public function debug(string $details): void; }
  • 27. $container = [ MonRepository::class => function($container) { return $container[MonLoggerRepository::class]($container }, MonLoggerRepository::class => function($container) { return new MonLoggerRepository( $container[LoggerInterface::class]($container), $container[MonCacheRepository::class]($container) ); }, MonCacheRepository::class => function($container) { return new MonCacheRepository( $container[CacheInterface::class]($container), $container[MonImplementationRepository::class]($cont ); }, MonImplementationRepository::class => function($container) return new MonImplementationRepository(); }, // to be continued
  • 28. CacheInterface::class => function($container) { return new class implements CacheInterface { public function get(string $cle): MonEntite { return new MonEntite; } public function has(): bool { return false; } public function set(MonEntite $entite, string $cle) }; }, LoggerInterface::class => function($container) { return new class implements LoggerInterface { public function debug(string $details): void { } }; }, ];
  • 29. Appel complet $factory = $container[MonRepository::class]; $repo = $factory($container); var_dump($repo); reportez-vous au D de SOLID pour simpli er (ici MonRepository ) “ “
  • 30. Tout le monde fait du SF maintenant
  • 31.
  • 32. Demo time! composer create-project symfony/skeleton composer req twig ... AppRepositoryMonRepository: alias: AppRepositoryMonImplementationRepository AppRepositoryMonLoggerRepository: decorates: AppRepositoryMonImplementationRepository
  • 33. Avec les deux : AppRepositoryMonRepository: alias: AppRepositoryMonImplementationRepository AppRepositoryMonLoggerRepository: decorates: AppRepositoryMonImplementationRepository arguments: [ '@AppLoggerInterface', '@AppRepositoryMonLoggerRepository.inner' ] AppRepositoryMonCacheRepository: decorates: AppRepositoryMonImplementationRepository arguments: [ '@AppCacheInterface', '@AppRepositoryMonCacheRepository.inner' ]
  • 36.
  • 37. En Symfony : les evènements (vous connaissez plus hein )
  • 38. final class MonImplementationRepository { private $dispatcher; public function __construct( EventDispatcherInterface $dispatcher ) { $this->dispatcher = $dispatcher; } public function get(Uuid $identifier): MonEntite { $this->dispatcher->dispatch('mon_super_event.pre', $value = new MonEntite; $this->dispatcher->dispatch('mon_super_event.post', return $value; } }
  • 39. final class RepositoryGetListener { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function demo(MonSuperEvent $event) { $this->logger->debug("Quelqu'un a récup un truc"); } } AppListenerRepositoryGetListener: tags: - name: kernel.event_listener event: mon_super_event.pre method: demo
  • 40. Cadeau : event dans un decorator final class MonEventRepository implements MonRepository { private $repository; private $dispatcher; public function __construct(EventDispatcherInterface $dispat { $this->repository = $repository; $this->dispatcher = $dispatcher; } public function get(Uuid $identifier): MonEntite { $this->dispatcher->dispatch('mon_super_event.pre', $instance = $this->repository->get($identifier); $this->dispatcher->dispatch('mon_super_event.post', return $instance;