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

Understanding Dependency Injection in Symfony

Understanding Dependency Injection in Symfony

The service container – or dependency injection container – is the core concept in the heart of the Symfony framework. It allows us to properly model the logic of our business, building decoupled services and helping our projects grow in a natural and elegant way. Often left out in a first approximation to Symfony, dependency injection is a key topic that needs to be mastered to fully unleash the framework’s potential.

Victoria Quirante

May 30, 2017
Tweet

More Decks by Victoria Quirante

Other Decks in Programming

Transcript

  1. Understanding Dependency
    Injection in Symfony
    Victoria Quirante

    View full-size slide

  2. I work at Limenius
    We build tailor-made projects with
    Symfony and React
    SF is a solid, mature framework that
    fosters high quality agile development
    Having a good understanding of DI is
    key for mastering the framework
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  3. GOALS
    What are we aiming for
    https://www.flickr.com/photos/deapeajay/1589466335

    View full-size slide

  4. Goals
    1. Clarify the terminology
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  5. Goals
    1. Clarify the terminology
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  6. Goals
    1. Clarify the terminology
    2. Understand what DI is used for
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  7. Goals
    1. Clarify the terminology
    2. Understand what DI is used for
    Victoria Quirante
    @vicqr
    [email protected]
    And what are the benefits

    View full-size slide

  8. Goals
    1. Clarify the terminology
    2. Understand what DI is used for
    3. Learn how Symfony uses it
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  9. Goals
    1. Clarify the terminology
    2. Understand what DI is used for
    3. Learn how Symfony uses it
    Victoria Quirante
    @vicqr
    [email protected]
    And how to do it well

    View full-size slide

  10. Goals
    1. Clarify the terminology
    2. Understand what DI is used for
    3. Learn how Symfony uses it
    Victoria Quirante
    @vicqr
    [email protected]
    Let’s go!

    View full-size slide

  11. SOME THEORY
    What is what
    https://www.flickr.com/photos/timetrax/376152628

    View full-size slide

  12. Martin Fowler
    Robert C. Martin
    Coauthored the Agile Manifesto
    Named the “first five principles”
    (SOLID)
    Popularized terms like “inversion of
    control” and “dependency injection”
    ...

    View full-size slide

  13. Martin Fowler
    Robert C. Martin
    Coauthored the Agile Manifesto
    Named the “first five principles”
    (SOLID)
    Popularized terms like “inversion of
    control” and “dependency injection”
    ...
    They thought quite a bit about how to write
    better code

    View full-size slide

  14. The background
    Most of these concepts come from the early 2000s
    It is all about how to write better code
    More reusable, readable, testable code
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  15. The background
    Most of these concepts come from the early 2000s
    It is all about how to write better code
    More reusable, readable, testable code
    Victoria Quirante
    @vicqr
    [email protected]
    “Inversion of Control Containers and the Dependency Injection pattern”
    https://martinfowler.com/articles/injection.html
    Good reading

    View full-size slide

  16. Inversion of control
    Victoria Quirante
    @vicqr
    [email protected]
    Traditional procedure programming
    Library 1
    Your
    custom
    code
    Library 2
    Library 3
    Library 4
    Your custom code calls some reusable libraries

    View full-size slide

  17. Inversion of control
    Victoria Quirante
    @vicqr
    [email protected]
    Traditional procedure programming Modern frameworks
    Library 1
    Your
    custom
    code
    Library 2
    Library 3
    Library 4
    The framework calls your custom code
    Framework
    Custom
    service 1
    Custom
    service 2
    Custom
    service 3
    Custom
    service 4
    Your custom code calls some reusable libraries

    View full-size slide

  18. Inversion of control and dependency injection
    Inversion of control is a broad concept
    DI is a specific form of IoC that solves a concrete problem
    Victoria Quirante
    @vicqr
    [email protected]
    Inversion of control
    (broad concept)
    DI = Inversion
    of how you plug
    components
    together

    View full-size slide

  19. Inversion of control and dependency injection
    Inversion of control is a broad concept
    DI is a specific form of IoC that solves a concrete problem
    DI is about how to assemble the components
    Victoria Quirante
    @vicqr
    [email protected]
    Inversion of control
    (broad concept)
    DI = Inversion
    of how you plug
    components
    together

    View full-size slide

  20. The problem: how to assemble
    DI is a (good) way to assemble the different components
    Victoria Quirante
    @vicqr
    [email protected]
    How to assemble
    different components
    Dependency
    Injection
    pattern

    View full-size slide

  21. The problem: how to assemble
    DI is a (good) way to assemble the different components
    Using a service locator is another possible solution
    Victoria Quirante
    @vicqr
    [email protected]
    How to assemble
    different components
    Dependency
    injection
    pattern
    Service
    locator
    pattern

    View full-size slide

  22. The problem: how to assemble
    DI is a (good) way to assemble the different components
    Using a service locator is another possible solution
    Both solutions try to decouple dependencies
    Victoria Quirante
    @vicqr
    [email protected]
    How to assemble
    different components
    Dependency
    injection
    pattern
    Service
    locator
    pattern

    View full-size slide

  23. Why is it so important to decouple?
    We don’t want to change the client code whenever we have to
    change the dependency or its configuration
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  24. Assembling dependencies
    Victoria Quirante
    @vicqr
    [email protected]
    Some code
    Coupled services

    View full-size slide

  25. Assembling dependencies
    Victoria Quirante
    @vicqr
    [email protected]
    Some code
    Some
    dependency
    created right
    here
    Coupled services

    View full-size slide

  26. Assembling dependencies
    Victoria Quirante
    @vicqr
    [email protected]
    Some code
    Some
    dependency
    created right
    here
    Coupled services Services decoupled with SL Services decoupled with DI

    View full-size slide

  27. Assembling dependencies
    Victoria Quirante
    @vicqr
    [email protected]
    Some code
    Some
    dependency
    created right
    here
    Coupled services Services decoupled with SL
    Some
    code
    Some
    dependency
    The code asks for the
    dependency
    Services decoupled with DI

    View full-size slide

  28. Assembling dependencies
    Victoria Quirante
    @vicqr
    [email protected]
    Some code
    Some
    dependency
    created right
    here
    Coupled services Services decoupled with SL Services decoupled with DI
    Some
    code
    Some
    dependency
    The code asks for the
    dependency
    Some
    code
    Some
    dependency
    The dependency gets
    injected

    View full-size slide

  29. Dependency injection
    You don’t create the dependencies inside your object
    Instead, you inject the dependencies in you object
    Victoria Quirante
    @vicqr
    [email protected]
    It is a way to decouple your services

    View full-size slide

  30. Service locator
    You don’t create the dependencies inside your object
    Instead, your object asks for the dependencies to the service locator
    Victoria Quirante
    @vicqr
    [email protected]
    It is also a way to decouple your services

    View full-size slide

  31. Service locator: pattern or antipattern?
    Some say that it is an antipattern (the locator itself is a coupled dependency)
    And that is more difficult to test
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  32. Service locator: pattern or antipattern?
    Some say that it is an antipattern (the locator itself is a coupled dependency)
    And that is more difficult to test
    Victoria Quirante
    @vicqr
    [email protected]
    Others say that only if you do it wrong

    View full-size slide

  33. «A common reason people give for preferring dependency injection is that it makes
    testing easier. [...] I suspect this observation comes from projects where people don't
    make the effort to ensure that their service locator can be easily substituted.»
    Martin Fowler

    View full-size slide

  34. «The choice between Service Locator and Dependency Injection is less important
    than the principle of separating service configuration from the use of services within
    an application.»
    Martin Fowler
    «A common reason people give for preferring dependency injection is that it makes
    testing easier. [...] I suspect this observation comes from projects where people don't
    make the effort to ensure that their service locator can be easily substituted.»
    Martin Fowler

    View full-size slide

  35. Dependency injection VS Service locator
    Service locator:
    - Easier to understand
    Dependency injection:
    - Easier to see what dependencies you have
    - You have access only to the dependencies that you need
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  36. DI supports the dependency inversion principle
    S - Single Responsibility
    O - Open / closed
    L - Liskov substitution
    I - Interface segregation
    D - Dependency inversion
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  37. DI supports the dependency inversion principle
    A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
    B. Abstractions should not depend on details. Details should depend on abstractions.
    S - Single Responsibility
    O - Open / closed
    L - Liskov substitution
    I - Interface segregation
    D - Dependency inversion
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  38. DI supports the dependency inversion principle
    A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
    B. Abstractions should not depend on details. Details should depend on abstractions.
    S - Single Responsibility
    O - Open / closed
    L - Liskov substitution
    I - Interface segregation
    D - Dependency inversion
    Victoria Quirante
    @vicqr
    [email protected]
    The client code fully delegates the
    responsibility of providing the
    dependencies to the injector

    View full-size slide

  39. Summarizing benefits of DI
    Victoria Quirante
    @vicqr
    [email protected]
    It helps decoupling
    services

    View full-size slide

  40. Summarizing benefits of DI
    Better code
    That follows SOLID
    And is more reusable, testable, readable
    Victoria Quirante
    @vicqr
    [email protected]
    It helps decoupling
    services

    View full-size slide

  41. The learning curve
    DI is simple, but there is a learning curve
    Thinking on a decoupled-fashion is not straightforward at the beginning
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  42. DI IN SYMFONY
    Understanding the environment
    https://www.flickr.com/photos/leshaines123/9258192037

    View full-size slide

  43. General schema of Symfony application
    Twig templates
    Controllers
    Template 1 Template 2 Template 3
    Controller 1 Controller 2 Controller 3
    Repositories
    Entities

    View full-size slide

  44. General schema of Symfony application
    Twig templates
    Controllers
    Template 1 Template 2 Template 3
    Controller 1 Controller 2 Controller 3
    Repositories
    Entities

    View full-size slide

  45. General schema of Symfony application
    Twig templates
    Controllers
    Template 1 Template 2 Template 3
    Controller 1 Controller 2 Controller 3
    Repositories
    Entities

    View full-size slide

  46. General schema of Symfony application
    Twig templates
    Controllers
    Template 1 Template 2 Template 3
    Controller 1 Controller 2 Controller 3
    Repositories
    Entities

    View full-size slide

  47. General schema of Symfony application
    Twig templates
    Controllers
    Template 1 Template 2 Template 3
    Controller 1 Controller 2 Controller 3
    Repositories
    Entities

    View full-size slide

  48. General schema of Symfony application
    Victoria Quirante
    @vicqr
    [email protected]
    Twig templates
    Controllers
    Services
    Template 1 Template 2 Template 3
    Controller 1 Controller 2 Controller 3
    Service 1 Service 2
    Service 3
    Service 4 Service 5
    Repositories
    Entities
    Good part of
    your business
    logic goes here

    View full-size slide

  49. Services
    An object that does something
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  50. Services
    An object that does something
    A class that implements a concrete functionality
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  51. Services
    An object that does something
    A class that implements a concrete functionality
    Victoria Quirante
    @vicqr
    [email protected]
    That sounds quite broad...

    View full-size slide

  52. Services in Symfony
    - Symfony components as services: Swiftmailer, Validator...
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  53. Services in Symfony
    - Symfony components as services: Swiftmailer, Validator...
    - Many bundles provide other services
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  54. Services in Symfony
    - Symfony components as services: Swiftmailer, Validator...
    - Many bundles provide other services
    - You can create your own
    Victoria Quirante
    @vicqr
    [email protected]
    Very flexible

    View full-size slide

  55. Services in Symfony
    - Symfony components as services: Swiftmailer, Validator...
    - Many bundles provide other services
    - You can create your own
    Victoria Quirante
    @vicqr
    [email protected]
    It is really important to decouple
    Very flexible

    View full-size slide

  56. Coupled services
    class Invoicer
    {
    public function sendInvoice()
    {
    // ...
    $mailer = new Mailer();
    // ...
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  57. Decoupled services
    class Invoicer
    {
    public function sendInvoice()
    {
    // ...
    $mailer = new Mailer();
    // ...
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    public function __construct($mailer)
    {
    $this->mailer = $mailer;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    // ...
    }
    }

    View full-size slide

  58. Decoupled services
    class Invoicer
    {
    public function sendInvoice()
    {
    // ...
    $mailer = new Mailer();
    // ...
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    public function __construct($mailer)
    {
    $this->mailer = $mailer;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    // ...
    }
    }

    View full-size slide

  59. Decoupled services
    class Invoicer
    {
    public function sendInvoice()
    {
    // ...
    $mailer = new Mailer();
    // ...
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    public function __construct($mailer)
    {
    $this->mailer = $mailer;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    // ...
    }
    }

    View full-size slide

  60. Types of DI
    - Constructor injection
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  61. Types of DI
    - Constructor injection
    - Setter injection -> good for optional dependencies
    - There are others: interface injection, property injection...
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/doc/current/service_container/injection_types.html

    View full-size slide

  62. THE SERVICE CONTAINER
    The heart of the matter
    https://www.flickr.com/photos/glynlowe/10039742285

    View full-size slide

  63. The Service Container
    Victoria Quirante
    @vicqr
    [email protected]
    It is an object that knows how to instantiate and configure objects
    It needs info about the constructor arguments and the relations between objects

    View full-size slide

  64. Do we always need a Service Container?
    No, we can implement DI without having a container
    But it is useful when we have lots of objects and dependencies
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  65. Listing available services
    php bin/console debug:container
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  66. Listing available services
    php bin/console debug:container
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  67. Lazy-loaded
    The container does not instantiate any service unless you ask for it
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  68. Calling one service from the container
    public function myAction()
    {
    // ...
    // the container will instantiate a new FortuneCookieGenerator()
    $fortuneGenerator = $this->container->get('limenius.fortune_cookie_generator');
    $message = $fortuneGenerator->getFortuneCookieMessage();
    // ...
    }
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  69. Calling one service from the container
    public function myAction()
    {
    // ...
    // the container will instantiate a new FortuneCookieGenerator()
    $fortuneGenerator = $this->container->get('limenius.fortune_cookie_generator');
    $message = $fortuneGenerator->getFortuneCookieMessage();
    // ...
    }
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  70. But wait… is this not a service locator?
    Yes, the Service Container can be used as a service locator
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  71. But wait… is this not a service locator?
    Yes, the Service Container can be used as a service locator
    Victoria Quirante
    @vicqr
    [email protected]
    It is actually used as such in the Controllers

    View full-size slide

  72. Controllers are ContainerAware!
    Is this not a bad practice? (difficult to test, etc.)
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  73. Controllers are ContainerAware!
    Is this not a bad practice? (difficult to test, etc.)
    Generally it is considered a bad practice to pass the container
    Controllers are a special case (if you want them to be)
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  74. Controllers are ContainerAware!
    Is this not a bad practice? (difficult to test, etc.)
    Generally it is considered a bad practice to pass the container
    Controllers are a special case (if you want them to be)
    - It can actually be more performant
    - It is also easier to understand at the beginning
    Victoria Quirante
    @vicqr
    [email protected]
    https://stackoverflow.com/questions/26304755/dependancy-injecton-or-service-locator-symfony

    View full-size slide

  75. Controllers are ContainerAware!
    Is this not a bad practice? (difficult to test, etc.)
    Generally it is considered a bad practice to pass the container
    Controllers are a special case (if you want them to be)
    - It can actually be more performant
    - It is also easier to understand at the beginning
    Victoria Quirante
    @vicqr
    [email protected]
    But remember: don’t put
    logic in your controllers
    https://stackoverflow.com/questions/26304755/dependancy-injecton-or-service-locator-symfony

    View full-size slide

  76. Bad practice: pass the container as a dependency
    - You can’t see the actual dependencies of the service
    - The service has access to too many things
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  77. CREATING YOUR SERVICES
    Into the real stuff
    https://www.flickr.com/photos/tabor-roeder/5611139185

    View full-size slide

  78. Step 1: Create the service
    class FortuneGenerator
    {
    public function getFortuneCookieMessage()
    {
    $messages = [
    'Aspire to achieve; you are almost there',
    'It is time for you to explore new interests',
    'The secret of getting ahead is getting started',
    ];
    $index = array_rand($messages);
    return $messages[$index];
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  79. Step 2: Tell the container how to instantiate it
    # app/config/services.yml
    services:
    limenius.fortune_cookie_generator:
    class: Limenius\AppBundle\Fortune\FortuneGenerator
    arguments: []
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  80. Step 2: Tell the container how to instantiate it
    # app/config/services.yml
    services:
    limenius.fortune_cookie_generator:
    class: Limenius\AppBundle\Fortune\FortuneGenerator
    arguments: []
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  81. Step 2: Tell the container how to instantiate it
    # app/config/services.yml
    services:
    limenius.fortune_cookie_generator:
    class: Limenius\AppBundle\Fortune\FortuneGenerator
    arguments: []
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  82. Step 3: Injecting services in other services
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    public function __construct($mailer)
    {
    $this->mailer = $mailer;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($message);
    // ...
    }
    }

    View full-size slide

  83. Step 3: Injecting services in other services
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    private $fortuneGenerator;
    public function __construct($mailer, $fortuneGenerator)
    {
    $this->mailer = $mailer;
    $this->fortuneGenerator = $fortuneGenerator;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    $this->fortuneGenerator->getFortuneCookieMessage();
    }
    }
    Constructor arguments

    View full-size slide

  84. Step 3: Injecting services in other services
    # app/config/services.xml






    Victoria Quirante
    @vicqr
    [email protected]
    We can create this configuration in XML, YML, PHP...

    View full-size slide

  85. Step 3: Injecting services in other services
    # app/config/services.xml






    Victoria Quirante
    @vicqr
    [email protected]
    We can create this configuration in XML, YML, PHP...

    View full-size slide

  86. Injecting parameters
    # app/config/services.xml





    %enable_unlucky_quotes%

    Victoria Quirante
    @vicqr
    [email protected]
    The container also holds configuration parameters,
    declared in parameters.yml

    View full-size slide

  87. Optional dependencies via setter injection
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    private $fortuneGenerator;
    public function __construct($mailer, $fortuneGenerator)
    {
    $this->mailer = $mailer;
    $this->fortuneGenerator = $fortuneGenerator;
    }
    }

    View full-size slide

  88. Optional dependencies via setter injection
    Victoria Quirante
    @vicqr
    [email protected]
    class Invoicer
    {
    private $mailer;
    private $fortuneGenerator;
    public function __construct($mailer)
    {
    $this->mailer = $mailer;
    }
    public function setFortuneGenerator($fortuneGenerator)
    {
    $this->fortuneGenerator = $fortuneGenerator;
    }
    }

    View full-size slide

  89. Optional dependencies via setter injection
    Victoria Quirante
    @vicqr
    [email protected]
    # app/config/services.xml




    View full-size slide

  90. Optional dependencies via setter injection
    Victoria Quirante
    @vicqr
    [email protected]
    # app/config/services.xml







    http://symfony.com/doc/current/service_container/calls.html

    View full-size slide

  91. Good practices when creating your services
    - Services should do only one thing
    - Inject only the dependencies that you need
    - Use calls for optional dependencies
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  92. ADVANCED USE
    Working with complex services
    https://www.flickr.com/photos/colinsite/2480309642

    View full-size slide

  93. Parent services
    services:
    limenius.base_doctrine_repository:
    arguments: ['@doctrine.entity_manager']
    Victoria Quirante
    @vicqr
    [email protected]
    Useful when you have many
    services using the same
    dependencies

    View full-size slide

  94. Parent services
    services:
    limenius.base_doctrine_repository:
    abstract: true
    arguments: ['@doctrine.entity_manager']
    Victoria Quirante
    @vicqr
    [email protected]
    Useful when you have many
    services using the same
    dependencies

    View full-size slide

  95. Parent services
    services:
    limenius.base_doctrine_repository:
    abstract: true
    arguments: ['@doctrine.entity_manager']
    limenius.chinese_wisdom_repository:
    class: Limenius\AppBundle\Repository\ChineseWisdomRepository
    parent: limenius.base_doctrine_repository
    Victoria Quirante
    @vicqr
    [email protected]
    Useful when you have many
    services using the same
    dependencies

    View full-size slide

  96. Parent services
    services:
    limenius.base_doctrine_repository:
    abstract: true
    arguments: ['@doctrine.entity_manager']
    limenius.chinese_wisdom_repository:
    class: Limenius\AppBundle\Repository\ChineseWisdomRepository
    parent: limenius.base_doctrine_repository
    Victoria Quirante
    @vicqr
    [email protected]
    Useful when you have many
    services using the same
    dependencies

    View full-size slide

  97. Parent services
    services:
    limenius.base_doctrine_repository:
    abstract: true
    arguments: ['@doctrine.entity_manager']
    limenius.chinese_wisdom_repository:
    class: Limenius\AppBundle\Repository\ChineseWisdomRepository
    parent: limenius.base_doctrine_repository
    Victoria Quirante
    @vicqr
    [email protected]
    Useful when you have many
    services using the same
    dependencies
    http://symfony.com/doc/current/service_container/parent_services.html

    View full-size slide

  98. Factories
    class FortuneGeneratorFactory
    {
    public static function createFortuneGenerator()
    {
    $fortuneGenerator = new FortuneGenerator();
    // ...
    return $fortuneGenerator;
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    Useful when you want to
    create complex objects
    The container will call a
    method on the factory,
    instead of directly
    instantiating the class

    View full-size slide

  99. Factories
    services:
    limenius.fortune_generator:
    class: Limenius\AppBundle\Fortune\FortuneGenerator
    factory: ['Limenius\AppBundle\Fortune\FortuneGeneratorFactory', createFortuneGenerator]
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/doc/current/service_container/factories.html

    View full-size slide

  100. Example: Injecting repositories
    # app/config/services.xml



    factory-service="doctrine.orm.entity_manager" factory-method="getRepository">
    Limenius\DietoBundle\Entity\ChineseWisdom

    Victoria Quirante
    @vicqr
    [email protected]
    We can instantiate a single repository instead of passing the whole entity manager

    View full-size slide

  101. Example: Injecting repositories
    # app/config/services.xml



    factory-service="doctrine.orm.entity_manager" factory-method="getRepository">
    Limenius\DietoBundle\Entity\ChineseWisdom

    Victoria Quirante
    @vicqr
    [email protected]
    We can instantiate a single repository instead of passing the whole entity manager

    View full-size slide

  102. Service tags
    # app/config/services.yml
    services:
    # ...
    admin.fortune_cookie:
    class: Limenius\AppBundle\Admin\FortuneCookieAdmin
    arguments: [~, Limenius\AppBundle\Entity\FortuneCookie, ~]
    tags:
    - { name: sonata.admin, manager_type: orm, label: Fortune Cookies }
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/doc/current/service_container/tags.html
    For example,
    SonataAdminBundle uses
    them to identify the Admins

    View full-size slide

  103. Service tags
    # app/config/services.yml
    services:
    # ...
    admin.fortune_cookie:
    class: Limenius\AppBundle\Admin\FortuneCookieAdmin
    arguments: [~, Limenius\AppBundle\Entity\FortuneCookie, ~]
    tags:
    - { name: sonata.admin, manager_type: orm, label: Fortune Cookies }
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/doc/current/service_container/tags.html
    For example,
    SonataAdminBundle uses
    them to identify the Admins

    View full-size slide

  104. Compiler passes
    class MyCompilerPass implements CompilerPassInterface
    {
    public function process(ContainerBuilder $container)
    {
    ...
    // find all service IDs with the sonata.admin tag
    $taggedServices = $container->findTaggedServiceIds('sonata.admin');
    foreach ($taggedServices as $id => $tags) {
    // do something
    }
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    You want to execute some
    custom code during the
    container compilation

    View full-size slide

  105. Compiler passes
    class MyCompilerPass implements CompilerPassInterface
    {
    public function process(ContainerBuilder $container)
    {
    ...
    // find all service IDs with the sonata.admin tag
    $taggedServices = $container->findTaggedServiceIds('sonata.admin');
    foreach ($taggedServices as $id => $tags) {
    // do something
    }
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    You want to execute some
    custom code during the
    container compilation

    View full-size slide

  106. SF 3 FEATURES
    What’s new
    https://www.flickr.com/photos/samdogs/3781283815

    View full-size slide

  107. Symfony releases
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  108. Autowiring
    services:
    limenius.invoicer:
    class: Limenius\AppBundle\Payments\Invoicer
    arguments: ['@mailer', '@limenius.fortune_generator']
    limenius.fortune_generator:
    class: Limenius\AppBundle\Fortune\FortuneGenerator
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  109. Autowiring
    services:
    limenius.invoicer:
    class: Limenius\AppBundle\Payments\Invoicer
    arguments: ['@mailer', '@limenius.fortune_generator']
    limenius.fortune_generator:
    class: Limenius\AppBundle\Fortune\FortuneGenerator
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  110. Autowiring
    services:
    limenius.invoicer:
    class: Limenius\AppBundle\Payments\Invoicer
    autowire: true
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  111. Autowiring
    class Invoicer
    {
    private $mailer;
    private $fortuneGenerator;
    public function __construct($mailer, $fortuneGenerator)
    {
    $this->mailer = $mailer;
    $this->fortuneGenerator = $fortuneGenerator;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    $this->fortuneGenerator->getFortune();
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  112. Autowiring
    class Invoicer
    {
    private $mailer;
    private $fortuneGenerator;
    public function __construct(MailerInterface $mailer, FortuneGenerator $fortuneGenerator)
    {
    $this->mailer = $mailer;
    $this->fortuneGenerator = $fortuneGenerator;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    $this->fortuneGenerator->getFortune();
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    It only works if you write the
    typehints

    View full-size slide

  113. Autowiring
    class Invoicer
    {
    private $mailer;
    private $fortuneGenerator;
    public function __construct(MailerInterface $mailer, FortuneGenerator $fortuneGenerator)
    {
    $this->mailer = $mailer;
    $this->fortuneGenerator = $fortuneGenerator;
    }
    public function sendInvoice()
    {
    // ...
    $this->mailer->send($email);
    $this->fortuneGenerator->getFortune();
    }
    }
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/doc/current/service_container/autowiring.html
    It only works if you write the
    typehints

    View full-size slide

  114. Simpler configuration
    Short syntax
    services:
    limenius.invoicer:
    class: Limenius\AppBundle\Payments\Invoicer
    autowire: true
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/blog/new-in-symfony-3-3-simpler-service-configuration

    View full-size slide

  115. Simpler configuration
    Short syntax
    services:
    limenius.invoicer:
    class: Limenius\AppBundle\Payments\Invoicer
    autowire: true
    Limenius\AppBundle\Payments\Invoicer:
    autowire: true
    Victoria Quirante
    @vicqr
    [email protected]
    The id of the service is
    considered to be the class

    View full-size slide

  116. Simpler configuration
    Default service configuration
    services:
    _defaults:
    autowire: true
    Victoria Quirante
    @vicqr
    [email protected]
    Applies to all services
    defined in the file

    View full-size slide

  117. Simpler configuration
    Default service configuration
    services:
    _defaults:
    autowire: true
    Interface-based service configuration
    services:
    _instanceof:
    Twig_ExtensionInterface:
    tags: ['twig.extension']
    Victoria Quirante
    @vicqr
    [email protected]
    Applies to all services
    defined in the file
    Applies to all services
    implementing the interface

    View full-size slide

  118. Autoconfiguration
    services:
    _defaults:
    autowire: true
    _instanceof:
    Symfony\Component\Security\Core\Authorization\Voter\VoterInterface:
    tags: [security.voter]
    AppBundle\Security\PostVoter: ~
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  119. Autoconfiguration
    services:
    _defaults:
    autowire: true
    _instanceof:
    Symfony\Component\Security\Core\Authorization\Voter\VoterInterface:
    tags: [security.voter]
    AppBundle\Security\PostVoter: ~
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  120. Autoconfiguration
    services:
    _defaults:
    autowire: true
    autoconfigure: true
    _instanceof:
    Symfony\Component\Security\Core\Authorization\Voter\VoterInterface:
    tags: [security.voter]
    AppBundle\Security\PostVoter: ~
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  121. Autoconfiguration
    services:
    _defaults:
    autowire: true
    autoconfigure: true
    _instanceof:
    Symfony\Component\Security\Core\Authorization\Voter\VoterInterface:
    tags: [security.voter]
    AppBundle\Security\PostVoter: ~
    Victoria Quirante
    @vicqr
    [email protected]
    https://symfony.com/blog/new-in-symfony-3-3-service-autoconfiguration
    Like an automated
    version of _instanceof

    View full-size slide

  122. PSR-4 based service discovery
    services:
    App\:
    resource: '../../src/{Controller, Command}'
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/blog/new-in-symfony-3-3-psr-4-based-service-discovery
    Looks in the directories, infers
    the PSR-4 class names and
    registers the services

    View full-size slide

  123. PSR-4 based service discovery
    services:
    App\:
    resource: '../../src/{Controller, Command}'
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/blog/new-in-symfony-3-3-psr-4-based-service-discovery
    Looks in the directories, infers
    the PSR-4 class names and
    registers the services

    View full-size slide

  124. Service locators
    - For some reason, you want to have dependencies available that you are not going to use
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  125. Service locators
    - For some reason, you want to have dependencies available that you are not going to use
    - Possible solutions:
    - Injecting dependencies that you are not going to use
    - Injecting the whole container
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  126. Service locators
    - For some reason, you want to have dependencies available that you are not going to use
    - Possible solutions:
    - Injecting dependencies that you are not going to use Instantiating objects that you don’t need
    - Injecting the whole container
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  127. Service locators
    - For some reason, you want to have dependencies available that you are not going to use
    - Possible solutions:
    - Injecting dependencies that you are not going to use Instantiating objects that you don’t need
    - Injecting the whole container Too broad access, actual dependencies hidden
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  128. Service locators
    - For some reason, you want to have dependencies available that you are not going to use
    - Possible solutions:
    - Injecting dependencies that you are not going to use Instantiating objects that you don’t need
    - Injecting the whole container Too broad access, actual dependencies hidden
    You can create a service locator (a container that contains just the services that you want,
    not all of them) and inject it with DI
    Victoria Quirante
    @vicqr
    [email protected]
    http://symfony.com/blog/new-in-symfony-3-3-service-locators

    View full-size slide

  129. SF 4 & FLEX
    What’s next
    https://www.flickr.com/photos/imagesnewman/33023955620

    View full-size slide

  130. Symfony 4 - Compose your application
    It will be released in November 2017
    They wanted to automate bundle installation/configuration
    It makes as easy to create projects with lots or few dependencies
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  131. «As a developer, I want to start small, without too many dependencies. But I also
    want to be able to grow my application as I see fit. From a micro-framework style app
    to a gigantic monolith. Your choice. The framework should not get in the way.»
    Fabien Potencier

    View full-size slide

  132. «As a developer, I want to start small, without too many dependencies. But I also
    want to be able to grow my application as I see fit. From a micro-framework style app
    to a gigantic monolith. Your choice. The framework should not get in the way.»
    Fabien Potencier
    «Symfony Flex is all about making it simple and easy to create any Symfony applications, from
    the most simple micro-style project to the more complex ones with dozens of dependencies. It
    automates adding and removing bundles. It takes care of giving you sensible defaults. It helps
    discovering good bundles.»
    Fabien Potencier

    View full-size slide

  133. Symfony Flex - Automation to the max
    It is a composer plugin that comes with Symfony 4
    The idea is automation to the max
    Moving towards zero configuration time
    It will also “promote” a curated list of bundles
    Victoria Quirante
    @vicqr
    [email protected]
    https://medium.com/@fabpot/symfony-4-a-small-screencast-cf6511823f

    View full-size slide

  134. FINAL THOUGHTS
    What should I remember
    https://www.flickr.com/photos/dewalick/15842170328

    View full-size slide

  135. Final thoughts (i)
    Dependency injection is a
    very good way of decoupling your services
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  136. Final thoughts (ii)
    With SF you have a lot of freedom designing your services
    (where your business logic is)
    Using DI properly is essential
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  137. Final thoughts (iii)
    SF is moving towards making default configuration 100% straightforward
    But this does not mean that we don’t need to understand what is
    going on
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide

  138. Thanks!
    Victoria Quirante
    @vicqr
    [email protected]

    View full-size slide