Slide 1

Slide 1 text

Understanding Dependency Injection in Symfony Victoria Quirante

Slide 2

Slide 2 text

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]

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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!

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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]

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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]

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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]

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

«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

Slide 34

Slide 34 text

«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

Slide 35

Slide 35 text

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]

Slide 36

Slide 36 text

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]

Slide 37

Slide 37 text

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]

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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]

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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); // ... } }

Slide 58

Slide 58 text

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); // ... } }

Slide 59

Slide 59 text

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); // ... } }

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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]

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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]

Slide 69

Slide 69 text

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]

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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]

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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]

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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]

Slide 79

Slide 79 text

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]

Slide 80

Slide 80 text

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]

Slide 81

Slide 81 text

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]

Slide 82

Slide 82 text

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); // ... } }

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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...

Slide 85

Slide 85 text

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...

Slide 86

Slide 86 text

Injecting parameters # app/config/services.xml %enable_unlucky_quotes% Victoria Quirante @vicqr [email protected] The container also holds configuration parameters, declared in parameters.yml

Slide 87

Slide 87 text

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; } }

Slide 88

Slide 88 text

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; } }

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

Optional dependencies via setter injection Victoria Quirante @vicqr [email protected] # app/config/services.xml http://symfony.com/doc/current/service_container/calls.html

Slide 91

Slide 91 text

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]

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

Example: Injecting repositories # app/config/services.xml Limenius\DietoBundle\Entity\ChineseWisdom Victoria Quirante @vicqr [email protected] We can instantiate a single repository instead of passing the whole entity manager

Slide 101

Slide 101 text

Example: Injecting repositories # app/config/services.xml Limenius\DietoBundle\Entity\ChineseWisdom Victoria Quirante @vicqr [email protected] We can instantiate a single repository instead of passing the whole entity manager

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

Symfony releases Victoria Quirante @vicqr [email protected]

Slide 108

Slide 108 text

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]

Slide 109

Slide 109 text

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]

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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]

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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]

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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]

Slide 126

Slide 126 text

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]

Slide 127

Slide 127 text

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]

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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]

Slide 131

Slide 131 text

«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

Slide 132

Slide 132 text

«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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

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

Slide 135

Slide 135 text

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

Slide 136

Slide 136 text

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]

Slide 137

Slide 137 text

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]

Slide 138

Slide 138 text

Thanks! Victoria Quirante @vicqr [email protected]