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. Understanding Dependency Injection in Symfony Victoria Quirante

  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
  3. GOALS What are we aiming for https://www.flickr.com/photos/deapeajay/1589466335

  4. Goals 1. Clarify the terminology Victoria Quirante @vicqr victoria@limenius.com

  5. Goals 1. Clarify the terminology Victoria Quirante @vicqr victoria@limenius.com

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

    used for Victoria Quirante @vicqr victoria@limenius.com
  7. Goals 1. Clarify the terminology 2. Understand what DI is

    used for Victoria Quirante @vicqr victoria@limenius.com And what are the benefits
  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
  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
  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!
  11. SOME THEORY What is what https://www.flickr.com/photos/timetrax/376152628

  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” ...
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  24. Assembling dependencies Victoria Quirante @vicqr victoria@limenius.com Some code Coupled services

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

    created right here Coupled services
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  39. Summarizing benefits of DI Victoria Quirante @vicqr victoria@limenius.com It helps

    decoupling services
  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
  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
  42. DI IN SYMFONY Understanding the environment https://www.flickr.com/photos/leshaines123/9258192037

  43. General schema of Symfony application Twig templates Controllers Template 1

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

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

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

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

    Template 2 Template 3 Controller 1 Controller 2 Controller 3 Repositories Entities
  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
  49. Services An object that does something Victoria Quirante @vicqr victoria@limenius.com

  50. Services An object that does something A class that implements

    a concrete functionality Victoria Quirante @vicqr victoria@limenius.com
  51. Services An object that does something A class that implements

    a concrete functionality Victoria Quirante @vicqr victoria@limenius.com That sounds quite broad...
  52. Services in Symfony - Symfony components as services: Swiftmailer, Validator...

    Victoria Quirante @vicqr victoria@limenius.com
  53. Services in Symfony - Symfony components as services: Swiftmailer, Validator...

    - Many bundles provide other services Victoria Quirante @vicqr victoria@limenius.com
  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
  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
  56. Coupled services class Invoicer { public function sendInvoice() { //

    ... $mailer = new Mailer(); // ... } } Victoria Quirante @vicqr victoria@limenius.com
  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); // ... } }
  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); // ... } }
  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); // ... } }
  60. Types of DI - Constructor injection Victoria Quirante @vicqr victoria@limenius.com

  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
  62. THE SERVICE CONTAINER The heart of the matter https://www.flickr.com/photos/glynlowe/10039742285

  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
  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
  65. Listing available services php bin/console debug:container Victoria Quirante @vicqr victoria@limenius.com

  66. Listing available services php bin/console debug:container Victoria Quirante @vicqr victoria@limenius.com

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

    ask for it Victoria Quirante @vicqr victoria@limenius.com
  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
  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
  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
  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
  72. Controllers are ContainerAware! Is this not a bad practice? (difficult

    to test, etc.) Victoria Quirante @vicqr victoria@limenius.com
  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
  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
  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
  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
  77. CREATING YOUR SERVICES Into the real stuff https://www.flickr.com/photos/tabor-roeder/5611139185

  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
  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
  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
  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
  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); // ... } }
  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
  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...
  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...
  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
  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; } }
  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; } }
  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>
  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
  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
  92. ADVANCED USE Working with complex services https://www.flickr.com/photos/colinsite/2480309642

  93. Parent services services: limenius.base_doctrine_repository: arguments: ['@doctrine.entity_manager'] Victoria Quirante @vicqr victoria@limenius.com

    Useful when you have many services using the same dependencies
  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
  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
  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
  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
  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
  99. Factories services: limenius.fortune_generator: class: Limenius\AppBundle\Fortune\FortuneGenerator factory: ['Limenius\AppBundle\Fortune\FortuneGeneratorFactory', createFortuneGenerator] Victoria Quirante

    @vicqr victoria@limenius.com http://symfony.com/doc/current/service_container/factories.html
  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
  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
  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
  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
  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
  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
  106. SF 3 FEATURES What’s new https://www.flickr.com/photos/samdogs/3781283815

  107. Symfony releases Victoria Quirante @vicqr victoria@limenius.com

  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 victoria@limenius.com
  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 victoria@limenius.com
  110. Autowiring services: limenius.invoicer: class: Limenius\AppBundle\Payments\Invoicer autowire: true Victoria Quirante @vicqr

    victoria@limenius.com
  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
  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
  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
  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
  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
  116. Simpler configuration Default service configuration services: _defaults: autowire: true Victoria

    Quirante @vicqr victoria@limenius.com Applies to all services defined in the file
  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
  118. Autoconfiguration services: _defaults: autowire: true _instanceof: Symfony\Component\Security\Core\Authorization\Voter\VoterInterface: tags: [security.voter] AppBundle\Security\PostVoter:

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

    ~ Victoria Quirante @vicqr victoria@limenius.com
  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 victoria@limenius.com
  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
  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
  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
  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
  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
  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
  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
  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
  129. SF 4 & FLEX What’s next https://www.flickr.com/photos/imagesnewman/33023955620

  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
  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
  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
  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
  134. FINAL THOUGHTS What should I remember https://www.flickr.com/photos/dewalick/15842170328

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

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