Slide 1

Slide 1 text

Developer waiting for a talk

Slide 2

Slide 2 text

Design Patterns and where to find them in Symfony Symfony User Group Berlin Erik Witthauer

Slide 3

Slide 3 text

About me Erik Witthauer PHP developer for > 10 years Twitter: ewnx01 Web aka: dknx01 Speakerdeck: speackerdeck.com/dknx01 work: FTI

Slide 4

Slide 4 text

Design pattern

Slide 5

Slide 5 text

A short excursion only

Slide 6

Slide 6 text

Design pattern ● General, reusable solution to a commonly occurring problem within a given context in software design ● A template or description of how to solve a problem, NOT code directly

Slide 7

Slide 7 text

Design pattern

Slide 8

Slide 8 text

Creational pattern responsible for encapsulating the producing and assembling of objects ● Abstract Factory ● Builder ● Factory Method ● Prototype ● Singleton

Slide 9

Slide 9 text

Structual pattern organize classes in a way to separate their implementations from their interfaces ● Adapter ● Bridge ● Composite ● Decorator ● Facade ● Proxy

Slide 10

Slide 10 text

Behavioral pattern organize objects to make them collaborate together while reducing their coupling ● Chain of Responsibility ● Command ● Interpreter ● Iterator ● Mediator ● Memento ● Observer ● State ● Strategy

Slide 11

Slide 11 text

Pros ● Communication ● Code Testability ● Maintainability ● Loose Coupling ● ... ● Hard to Teach ● Hard to Learn ● Hard to Apply ● Entry Barrier ● ... Cons

Slide 12

Slide 12 text

Builder Pattern

Slide 13

Slide 13 text

Builder pattern ● Flexible solution to various object creation of problems ● Separate the construction of a complex object from its representation ● Simplify class creation for classes with complex object(s) ● Same Builder can create different class representations with the same process ● Always creating a valid object, NOT the right object ● Methods names are not predefined, but should be easy to understand

Slide 14

Slide 14 text

● Allows you to vary an objects internal representation ● Encapsulates code for construction and representation ● Provides control over steps of construction process ● Easier reusability of object instantiation ● Requires creating a separate ConcreteBuilder for each different type of object ● Requires the builder classes to be mutable ● Data members of class aren't guaranteed to be initialized ● Dependency injection may be less supported Advantages Disadvantages

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Builder pattern - Doctrine QueryBuilder ● provide a simple way to create a query object from a repository ● Database independent $query = $this->createQueryBuilder('u, p') ->leftJoin('u.profile', 'p') ->where('LOWER(u.emailAddress) = :email') ->andWhere('u.active = :active') ->setParameter('email', mb_strtolower($email)) ->setParameter('active', 1) ->getQuery(); return $query->getOneOrNullResult();

Slide 17

Slide 17 text

Builder pattern - Symfony FormBuilder ● provide a simplier way to create a form instance class RegistrationType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('emailAddress', EmailType::class) ->add('firstName', TextType::class) ->add('lastName', TextType::class) ->add('password', RepeatedType::class, [ 'type' => PasswordType::class, ]) ->add('submit', SubmitType::class); } }

Slide 18

Slide 18 text

Chain of responsibility

Slide 19

Slide 19 text

Chain of responsibility ● Decoupling the sender of a request to its receivers ● It should be possible that more than one receiver can handle a request ● Define a chain of receiver objects having the responsibility, depending on run-time conditions, to either handle a request or forward it to the next receiver on the chain (if any)

Slide 20

Slide 20 text

Chain of responsibility - Symfony voters ● most granular way of checking permissions abstract class Voter implements VoterInterface { abstract protected function supports($attribute, $subject); abstract protected function voteOnAttribute($attribute, $subject, TokenInterface $token); } class PostController extends AbstractController { public function show($id) { // check for "view" access: calls all voters $this->denyAccessUnlessGranted('view', $post); }

Slide 21

Slide 21 text

Chain of responsibility - Symfony voters class PostVoter extends Voter { protected function supports($attribute, $subject) { // only vote on Post objects inside this voter // if the attribute is one we support } protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { // … some logic will be here }

Slide 22

Slide 22 text

Adapter pattern

Slide 23

Slide 23 text

Adapter pattern ● Converts the (incompatible) interface of a class (adaptee) into another interface (target) the client require ● Work through an adapter to work with (reuse) classes that do not have the required interface ● makes two incompatible objects work together without changing their interfaces

Slide 24

Slide 24 text

Adapter pattern

Slide 25

Slide 25 text

Adapter pattern - HttpClient final class HttpClient { public static function create(...): HttpClientInterface { if (\extension_loaded('curl')) { // … return new CurlHttpClient($defaultOptions, $maxHostConnections, $maxPendingPushes); // ... } // native PHP stream return new NativeHttpClient($defaultOptions, $maxHostConnections); } }

Slide 26

Slide 26 text

Interpreter pattern

Slide 27

Slide 27 text

Interpreter pattern ● used to define the grammar for instructions that form part of a language or notation, whilst allowing the grammar to be easily extended

Slide 28

Slide 28 text

Interpreter pattern - Expression language $expressionLanguage = new ExpressionLanguage(); var_dump($expressionLanguage->evaluate('1 + 2')); // displays 3 # config/services.yaml services: # ... App\Mail\MailerConfiguration: ~ App\Mailer: arguments: ["@=service('App\\\\Mail\\\\MailerConfiguration').getMailerMethod()"] App\Mailer: arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]

Slide 29

Slide 29 text

Mediator pattern

Slide 30

Slide 30 text

Mediator pattern ● reduces coupling between classes that communicate with each other. Instead of classes communicating directly, and thus requiring knowledge of their implementation, the classes send messages via a mediator object

Slide 31

Slide 31 text

Mediator pattern - EventDispatcher class EventDispatcher implements EventDispatcherInterface { private $listeners = []; public function addListener(string $eventName, callable $listener, int $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; } } public function dispatch($eventName, Event $event = null) { $event = $event ?: new Event(); if ($listeners = $this->getListeners($eventName)) { $this->doDispatch($listeners, $eventName, $event); } } }

Slide 32

Slide 32 text

Mediator pattern - EventDispatcher class OrderService { public function recordPayment(Payment $payment): void { // ... if ($order->isFullyPaid()) { $this->dispatcher->dispatch('order.paid', new OrderEvent($order)); } // … } }

Slide 33

Slide 33 text

For today

Slide 34

Slide 34 text

Links ● https://en.wikipedia.org/wiki/Software_design_pattern ● https://speakerdeck.com/hhamon/learning-design-patterns-with-symfony ● https://refactoring.guru/design-patterns/

Slide 35

Slide 35 text

Question and talk time

Slide 36

Slide 36 text

End