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.

281604c1a5357a164f2a9cd6e403b4e3?s=128

Victoria Quirante

May 30, 2017
Tweet

Transcript

  1. 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 victoria@limenius.com
  2. 6.

    Goals 1. Clarify the terminology 2. Understand what DI is

    used for Victoria Quirante @vicqr victoria@limenius.com
  3. 7.

    Goals 1. Clarify the terminology 2. Understand what DI is

    used for Victoria Quirante @vicqr victoria@limenius.com And what are the benefits
  4. 8.

    Goals 1. Clarify the terminology 2. Understand what DI is

    used for 3. Learn how Symfony uses it Victoria Quirante @vicqr victoria@limenius.com
  5. 9.

    Goals 1. Clarify the terminology 2. Understand what DI is

    used for 3. Learn how Symfony uses it Victoria Quirante @vicqr victoria@limenius.com And how to do it well
  6. 10.

    Goals 1. Clarify the terminology 2. Understand what DI is

    used for 3. Learn how Symfony uses it Victoria Quirante @vicqr victoria@limenius.com Let’s go!
  7. 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” ...
  8. 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
  9. 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 victoria@limenius.com
  10. 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 victoria@limenius.com “Inversion of Control Containers and the Dependency Injection pattern” https://martinfowler.com/articles/injection.html Good reading
  11. 16.

    Inversion of control Victoria Quirante @vicqr victoria@limenius.com Traditional procedure programming

    Library 1 Your custom code Library 2 Library 3 Library 4 Your custom code calls some reusable libraries
  12. 17.

    Inversion of control Victoria Quirante @vicqr victoria@limenius.com 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
  13. 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 victoria@limenius.com Inversion of control (broad concept) DI = Inversion of how you plug components together
  14. 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 victoria@limenius.com Inversion of control (broad concept) DI = Inversion of how you plug components together
  15. 20.

    The problem: how to assemble DI is a (good) way

    to assemble the different components Victoria Quirante @vicqr victoria@limenius.com How to assemble different components Dependency Injection pattern
  16. 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 victoria@limenius.com How to assemble different components Dependency injection pattern Service locator pattern
  17. 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 victoria@limenius.com How to assemble different components Dependency injection pattern Service locator pattern
  18. 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 victoria@limenius.com
  19. 26.

    Assembling dependencies Victoria Quirante @vicqr victoria@limenius.com Some code Some dependency

    created right here Coupled services Services decoupled with SL Services decoupled with DI
  20. 27.

    Assembling dependencies Victoria Quirante @vicqr victoria@limenius.com 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
  21. 28.

    Assembling dependencies Victoria Quirante @vicqr victoria@limenius.com 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
  22. 29.

    Dependency injection You don’t create the dependencies inside your object

    Instead, you inject the dependencies in you object Victoria Quirante @vicqr victoria@limenius.com It is a way to decouple your services
  23. 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 victoria@limenius.com It is also a way to decouple your services
  24. 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 victoria@limenius.com
  25. 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 victoria@limenius.com Others say that only if you do it wrong
  26. 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
  27. 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
  28. 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 victoria@limenius.com
  29. 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 victoria@limenius.com
  30. 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 victoria@limenius.com
  31. 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 victoria@limenius.com The client code fully delegates the responsibility of providing the dependencies to the injector
  32. 40.

    Summarizing benefits of DI Better code That follows SOLID And

    is more reusable, testable, readable Victoria Quirante @vicqr victoria@limenius.com It helps decoupling services
  33. 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 victoria@limenius.com
  34. 43.

    General schema of Symfony application Twig templates Controllers Template 1

    Template 2 Template 3 Controller 1 Controller 2 Controller 3 Repositories Entities
  35. 44.

    General schema of Symfony application Twig templates Controllers Template 1

    Template 2 Template 3 Controller 1 Controller 2 Controller 3 Repositories Entities
  36. 45.

    General schema of Symfony application Twig templates Controllers Template 1

    Template 2 Template 3 Controller 1 Controller 2 Controller 3 Repositories Entities
  37. 46.

    General schema of Symfony application Twig templates Controllers Template 1

    Template 2 Template 3 Controller 1 Controller 2 Controller 3 Repositories Entities
  38. 47.

    General schema of Symfony application Twig templates Controllers Template 1

    Template 2 Template 3 Controller 1 Controller 2 Controller 3 Repositories Entities
  39. 48.

    General schema of Symfony application Victoria Quirante @vicqr victoria@limenius.com 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
  40. 50.

    Services An object that does something A class that implements

    a concrete functionality Victoria Quirante @vicqr victoria@limenius.com
  41. 51.

    Services An object that does something A class that implements

    a concrete functionality Victoria Quirante @vicqr victoria@limenius.com That sounds quite broad...
  42. 52.
  43. 53.

    Services in Symfony - Symfony components as services: Swiftmailer, Validator...

    - Many bundles provide other services Victoria Quirante @vicqr victoria@limenius.com
  44. 54.

    Services in Symfony - Symfony components as services: Swiftmailer, Validator...

    - Many bundles provide other services - You can create your own Victoria Quirante @vicqr victoria@limenius.com Very flexible
  45. 55.

    Services in Symfony - Symfony components as services: Swiftmailer, Validator...

    - Many bundles provide other services - You can create your own Victoria Quirante @vicqr victoria@limenius.com It is really important to decouple Very flexible
  46. 56.

    Coupled services class Invoicer { public function sendInvoice() { //

    ... $mailer = new Mailer(); // ... } } Victoria Quirante @vicqr victoria@limenius.com
  47. 57.

    Decoupled services class Invoicer { public function sendInvoice() { //

    ... $mailer = new Mailer(); // ... } } Victoria Quirante @vicqr victoria@limenius.com class Invoicer { private $mailer; public function __construct($mailer) { $this->mailer = $mailer; } public function sendInvoice() { // ... $this->mailer->send($email); // ... } }
  48. 58.

    Decoupled services class Invoicer { public function sendInvoice() { //

    ... $mailer = new Mailer(); // ... } } Victoria Quirante @vicqr victoria@limenius.com class Invoicer { private $mailer; public function __construct($mailer) { $this->mailer = $mailer; } public function sendInvoice() { // ... $this->mailer->send($email); // ... } }
  49. 59.

    Decoupled services class Invoicer { public function sendInvoice() { //

    ... $mailer = new Mailer(); // ... } } Victoria Quirante @vicqr victoria@limenius.com class Invoicer { private $mailer; public function __construct($mailer) { $this->mailer = $mailer; } public function sendInvoice() { // ... $this->mailer->send($email); // ... } }
  50. 61.

    Types of DI - Constructor injection - Setter injection ->

    good for optional dependencies - There are others: interface injection, property injection... Victoria Quirante @vicqr victoria@limenius.com http://symfony.com/doc/current/service_container/injection_types.html
  51. 63.

    The Service Container Victoria Quirante @vicqr victoria@limenius.com It is an

    object that knows how to instantiate and configure objects It needs info about the constructor arguments and the relations between objects
  52. 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 victoria@limenius.com
  53. 67.

    Lazy-loaded The container does not instantiate any service unless you

    ask for it Victoria Quirante @vicqr victoria@limenius.com
  54. 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 victoria@limenius.com
  55. 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 victoria@limenius.com
  56. 70.

    But wait… is this not a service locator? Yes, the

    Service Container can be used as a service locator Victoria Quirante @vicqr victoria@limenius.com
  57. 71.

    But wait… is this not a service locator? Yes, the

    Service Container can be used as a service locator Victoria Quirante @vicqr victoria@limenius.com It is actually used as such in the Controllers
  58. 72.

    Controllers are ContainerAware! Is this not a bad practice? (difficult

    to test, etc.) Victoria Quirante @vicqr victoria@limenius.com
  59. 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 victoria@limenius.com
  60. 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 victoria@limenius.com https://stackoverflow.com/questions/26304755/dependancy-injecton-or-service-locator-symfony
  61. 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 victoria@limenius.com But remember: don’t put logic in your controllers https://stackoverflow.com/questions/26304755/dependancy-injecton-or-service-locator-symfony
  62. 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 victoria@limenius.com
  63. 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 victoria@limenius.com
  64. 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 victoria@limenius.com
  65. 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 victoria@limenius.com
  66. 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 victoria@limenius.com
  67. 82.

    Step 3: Injecting services in other services Victoria Quirante @vicqr

    victoria@limenius.com class Invoicer { private $mailer; public function __construct($mailer) { $this->mailer = $mailer; } public function sendInvoice() { // ... $this->mailer->send($message); // ... } }
  68. 83.

    Step 3: Injecting services in other services Victoria Quirante @vicqr

    victoria@limenius.com 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
  69. 84.

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

    id="limenius.invoicer" class="Limenius\AppBundle\Payments\Invoicer"> <argument type="service" id="mailer"/> <argument type="service" id="limenius.fortune_cookie_generator"/> </service> <service id="limenius.fortune_cookie_generator" class="Limenius\AppBundle\Fortune\FortuneGenerator"> </service> Victoria Quirante @vicqr victoria@limenius.com We can create this configuration in XML, YML, PHP...
  70. 85.

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

    id="limenius.invoicer" class="Limenius\AppBundle\Payments\Invoicer"> <argument type="service" id="mailer"/> <argument type="service" id="limenius.fortune_cookie_generator"/> </service> <service id="limenius.fortune_cookie_generator" class="Limenius\AppBundle\Fortune\FortuneGenerator"> </service> Victoria Quirante @vicqr victoria@limenius.com We can create this configuration in XML, YML, PHP...
  71. 86.

    Injecting parameters # app/config/services.xml <service id="limenius.invoicer" class="Limenius\AppBundle\Payments\Invoicer"> <argument type="service" id="mailer"/>

    <argument type="service" id="limenius.fortune_cookie_generator"/> </service> <service id="limenius.fortune_cookie_generator" class="Limenius\AppBundle\Fortune\FortuneGenerator"> <argument>%enable_unlucky_quotes%</argument> </service> Victoria Quirante @vicqr victoria@limenius.com The container also holds configuration parameters, declared in parameters.yml
  72. 87.

    Optional dependencies via setter injection Victoria Quirante @vicqr victoria@limenius.com class

    Invoicer { private $mailer; private $fortuneGenerator; public function __construct($mailer, $fortuneGenerator) { $this->mailer = $mailer; $this->fortuneGenerator = $fortuneGenerator; } }
  73. 88.

    Optional dependencies via setter injection Victoria Quirante @vicqr victoria@limenius.com class

    Invoicer { private $mailer; private $fortuneGenerator; public function __construct($mailer) { $this->mailer = $mailer; } public function setFortuneGenerator($fortuneGenerator) { $this->fortuneGenerator = $fortuneGenerator; } }
  74. 89.

    Optional dependencies via setter injection Victoria Quirante @vicqr victoria@limenius.com #

    app/config/services.xml <service id="limenius.invoicer" class="Limenius\AppBundle\Payments\Invoicer"> <argument type="service" id="mailer"/> <argument type="service" id="limenius.fortune_cookie_generator"/> </service>
  75. 90.

    Optional dependencies via setter injection Victoria Quirante @vicqr victoria@limenius.com #

    app/config/services.xml <service id="limenius.invoicer" class="Limenius\AppBundle\Payments\Invoicer"> <argument type="service" id="mailer"/> <argument type="service" id="limenius.fortune_cookie_generator"/> <call method="setFortuneGenerator"> <argument type="service" id="limenius.fortune_cookie_generator" /> </call> </service> http://symfony.com/doc/current/service_container/calls.html
  76. 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 victoria@limenius.com
  77. 94.

    Parent services services: limenius.base_doctrine_repository: abstract: true arguments: ['@doctrine.entity_manager'] Victoria Quirante

    @vicqr victoria@limenius.com Useful when you have many services using the same dependencies
  78. 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 victoria@limenius.com Useful when you have many services using the same dependencies
  79. 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 victoria@limenius.com Useful when you have many services using the same dependencies
  80. 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 victoria@limenius.com Useful when you have many services using the same dependencies http://symfony.com/doc/current/service_container/parent_services.html
  81. 98.

    Factories class FortuneGeneratorFactory { public static function createFortuneGenerator() { $fortuneGenerator

    = new FortuneGenerator(); // ... return $fortuneGenerator; } } Victoria Quirante @vicqr victoria@limenius.com Useful when you want to create complex objects The container will call a method on the factory, instead of directly instantiating the class
  82. 100.

    Example: Injecting repositories # app/config/services.xml <service id="limenius.fortune_cookie_generator" class="Limenius\AppBundle\Fortune\FortuneGenerator"> <argument type="service"

    id="limenius.repository.chinese_wisdom"/> </service> <service id="limenius.repository.chinese_wisdom" class="Limenius\DietoBundle\Entity\ChineseWisdomRepository" factory-service="doctrine.orm.entity_manager" factory-method="getRepository"> <argument type="string">Limenius\DietoBundle\Entity\ChineseWisdom</argument> </service> Victoria Quirante @vicqr victoria@limenius.com We can instantiate a single repository instead of passing the whole entity manager
  83. 101.

    Example: Injecting repositories # app/config/services.xml <service id="limenius.fortune_cookie_generator" class="Limenius\AppBundle\Fortune\FortuneGenerator"> <argument type="service"

    id="limenius.repository.chinese_wisdom"/> </service> <service id="limenius.repository.chinese_wisdom" class="Limenius\DietoBundle\Entity\ChineseWisdomRepository" factory-service="doctrine.orm.entity_manager" factory-method="getRepository"> <argument type="string">Limenius\DietoBundle\Entity\ChineseWisdom</argument> </service> Victoria Quirante @vicqr victoria@limenius.com We can instantiate a single repository instead of passing the whole entity manager
  84. 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 victoria@limenius.com http://symfony.com/doc/current/service_container/tags.html For example, SonataAdminBundle uses them to identify the Admins
  85. 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 victoria@limenius.com http://symfony.com/doc/current/service_container/tags.html For example, SonataAdminBundle uses them to identify the Admins
  86. 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 victoria@limenius.com You want to execute some custom code during the container compilation
  87. 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 victoria@limenius.com You want to execute some custom code during the container compilation
  88. 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 victoria@limenius.com
  89. 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 victoria@limenius.com It only works if you write the typehints
  90. 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 victoria@limenius.com http://symfony.com/doc/current/service_container/autowiring.html It only works if you write the typehints
  91. 114.

    Simpler configuration Short syntax services: limenius.invoicer: class: Limenius\AppBundle\Payments\Invoicer autowire: true

    Victoria Quirante @vicqr victoria@limenius.com http://symfony.com/blog/new-in-symfony-3-3-simpler-service-configuration
  92. 115.

    Simpler configuration Short syntax services: limenius.invoicer: class: Limenius\AppBundle\Payments\Invoicer autowire: true

    Limenius\AppBundle\Payments\Invoicer: autowire: true Victoria Quirante @vicqr victoria@limenius.com The id of the service is considered to be the class
  93. 116.

    Simpler configuration Default service configuration services: _defaults: autowire: true Victoria

    Quirante @vicqr victoria@limenius.com Applies to all services defined in the file
  94. 117.

    Simpler configuration Default service configuration services: _defaults: autowire: true Interface-based

    service configuration services: _instanceof: Twig_ExtensionInterface: tags: ['twig.extension'] Victoria Quirante @vicqr victoria@limenius.com Applies to all services defined in the file Applies to all services implementing the interface
  95. 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 victoria@limenius.com https://symfony.com/blog/new-in-symfony-3-3-service-autoconfiguration Like an automated version of _instanceof
  96. 122.

    PSR-4 based service discovery services: App\: resource: '../../src/{Controller, Command}' Victoria

    Quirante @vicqr victoria@limenius.com 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
  97. 123.

    PSR-4 based service discovery services: App\: resource: '../../src/{Controller, Command}' Victoria

    Quirante @vicqr victoria@limenius.com 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
  98. 124.

    Service locators - For some reason, you want to have

    dependencies available that you are not going to use Victoria Quirante @vicqr victoria@limenius.com
  99. 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 victoria@limenius.com
  100. 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 victoria@limenius.com
  101. 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 victoria@limenius.com
  102. 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 victoria@limenius.com http://symfony.com/blog/new-in-symfony-3-3-service-locators
  103. 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 victoria@limenius.com
  104. 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
  105. 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
  106. 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 victoria@limenius.com https://medium.com/@fabpot/symfony-4-a-small-screencast-cf6511823f
  107. 135.

    Final thoughts (i) Dependency injection is a very good way

    of decoupling your services Victoria Quirante @vicqr victoria@limenius.com
  108. 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 victoria@limenius.com
  109. 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 victoria@limenius.com