Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Software design patterns in the Symfony world

dknx01
August 01, 2019

Software design patterns in the Symfony world

dknx01

August 01, 2019
Tweet

More Decks by dknx01

Other Decks in Programming

Transcript

  1. About me Erik Witthauer PHP developer for > 10 years

    Twitter: ewnx01 Web aka: dknx01 Speakerdeck: speackerdeck.com/dknx01 work: FTI
  2. 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
  3. Creational pattern responsible for encapsulating the producing and assembling of

    objects • Abstract Factory • Builder • Factory Method • Prototype • Singleton
  4. Structual pattern organize classes in a way to separate their

    implementations from their interfaces • Adapter • Bridge • Composite • Decorator • Facade • Proxy
  5. Behavioral pattern organize objects to make them collaborate together while

    reducing their coupling • Chain of Responsibility • Command • Interpreter • Iterator • Mediator • Memento • Observer • State • Strategy
  6. Pros • Communication • Code Testability • Maintainability • Loose

    Coupling • ... • Hard to Teach • Hard to Learn • Hard to Apply • Entry Barrier • ... Cons
  7. 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
  8. • 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
  9. 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();
  10. 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); } }
  11. 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)
  12. 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); }
  13. 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 }
  14. 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
  15. 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); } }
  16. 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
  17. 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'"]
  18. 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
  19. 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); } } }
  20. Mediator pattern - EventDispatcher class OrderService { public function recordPayment(Payment

    $payment): void { // ... if ($order->isFullyPaid()) { $this->dispatcher->dispatch('order.paid', new OrderEvent($order)); } // … } }
  21. End