SlideShare a Scribd company logo
1 of 84
Download to read offline
Dependency Injection in Drupal 8
Intro
● Rudimentary understanding of OOP assumed
● Big changes in D8
● Not enough time to explain ALL THE THINGS
but I'll provide a list of resources for a deeper
dive into DI
Agenda
● DI as a design pattern
● DI from a framework perspective
● Symfony-style DI
● DI in Drupal 8
Agenda
● DI as a design pattern
● DI from a framework perspective
● Symfony-style DI
● DI in Drupal 8
Why?
How?
Why Dependency Injection?
Goal: we want to write code
that is...
✔Clutter-free
✔Reusable
✔Testable
Doing It Wrong
1. An example in procedural code
function my_module_func($val1, $val2) {
module_load_include('module_x', 'inc');
$val1 = module_x_process_val($val1);
return $val1 + $val2;
}
function my_module_func($val1, $val2) {
module_load_include('module_x', 'inc');
$val1 = module_x_process_val($val1);
return $val1 + $val2;
}
✗ Clutter-free
✗ Reusable
✗ Testable
Doing It Wrong
1. An example in procedural code
2. An example in Object Oriented code
class Notifier {
private $mailer;
public function __construct() {
$this->mailer = new Mailer();
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
class Notifier {
private $mailer;
public function __construct() {
$this->mailer = new Mailer('sendmail');
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
class Notifier {
private $mailer;
public function __construct(Mailer $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
class Notifier {
private $mailer;
public function __construct(Mailer $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
$mailer = new Mailer();
$notifier = new Notifier($mailer);
Goal: we want to write code
that is...
✔Clutter-free
✔Reusable
✔Testable
Goal: we want to write code
that is...
✔Clutter-free
✔Reusable
✔Testable
Ignorant
The less your code knows, the more
reusable it is.
class Notifier {
private $mailer;
public function __construct(Mailer $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
$mailer = new Mailer();
$notifier = new Notifier($mailer);
class Notifier {
private $mailer;
public function
__construct(MailerInterface $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
$mailer = new SpecialMailer();
$notifier = new Notifier($mailer);
class Notifier {
private $mailer;
public function
__construct(MailerInterface $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
$mailer = new SpecialMailer();
$notifier = new Notifier($mailer);
Constructor Injection
Dependency Injection
Declaratively express dependencies in the
class definition rather than instantiating them
in the class itself.
Constructor Injection is not
the only form of DI
Setter Injection
class Notifier {
private $mailer;
public function
setMailer(MailerInterface $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($msg);
}
}
$mailer = new Mailer();
$notifier = new Notifier();
$notifier->setMailer($mailer);
class Notifier {
private $mailer;
public function
setMailer(MailerInterface $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($msg);
}
}
$mailer = new Mailer();
$notifier = new Notifier();
$notifier->setMailer($mailer);
Setter Injection
Interface Injection
Like setter injection, except there is an
interface for each dependency's setter
method.
Very verbose
Not very common
Dependency Injection
==
Inversion of Control
“Don't call us,
we'll call you!”
(The Hollywood Principle)
class Notifier {
private $mailer;
public function
__construct(MailerInterface $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
$mailer = new Mailer();
$notifier = new Notifier($mailer);
class Notifier {
private $mailer;
public function
__construct(MailerInterface $m) {
$this->mailer = $m;
}
public function notify() {
...
$this->mailer->send($from, $to, $msg);
...
}
}
$mailer = new Mailer();
$notifier = new Notifier($mailer);?
Where does injection happen?
Where does injection happen?
➔ Manual injection
➔ Use a factory
➔ Use a container / injector
Using DI in a Framework
Dependency Injector
==
Dependency Injection Container (DIC)
==
IoC Container
==
Service Container
The Service Container
➔ Assumes responsibility for constructing
object graphs (i.e. instantiating your
classes with their dependencies)
➔ Uses configuration data to know how to
do this
➔ Allows infrastructure logic to be kept
separate from application logic
Objects as Services
A service is an object that provides some kind of
globally useful functionality
Examples of Services
➔ Cache Backend
➔ Logger
➔ Mailer
➔ URL Generator
Examples of Non-Services
➔ Product
➔ Blog post
➔ Email message
Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
Sample configuration
<services...>
<service id=”notifier” class=”Notifier”>
<constructor-arg ref=”emailer” />
</service>
<service id=”emailer” class=”Mailer”>
<constructor-arg ref=”spell_checker” />
</service>
<service id=”spell_checker”
class=”SpellChecker” />
</services>
How does it work?
➔ Service keys map to service definitions
➔ Definitions specify which class to
instantiate and what its dependencies
are
➔ Dependencies are specified as
references to other services (using
service keys)
➔ Keys are unique per object graph
➔ $container->getService('some_service')
Service Keys
Each key corresponds to a unique object graph, e.g.
'english_mailer' corresponds to
new Mailer(new EnglishSpellchecker())
'french_mailer' corresponds to
new Mailer(new FrenchSpellchecker())
Container Configuration
➔ Via an API
➔ Using XML
➔ Using YAML
Scope
The scope of a service is the context under which
the service key refers to the same instance.
Common Scopes
Container scope (aka Singleton scope)
The container returns the same instance every time
a client requests that service
Prototype scope (aka no scope)
The container returns a new instance every time a
client requests that service
Request scope
Every request for the service within the context of
an HTTP request will get the same instance.
Service Locator vs. DI
class SomeClass {
public function __construct(Locator $sl) {
$this->myDep = $sl->get('some_service');
}
}
In DI, calls like
$container->get('some_service')
should only happen at the entry point to the
application
Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
Service Locator
Service Locator
Getting wired in is not just about
configuration, it's about how the
application works with the
container.
Symfony's Dependency Injection
Component
Symfony's DI Component
➔ Service keys are strings, e.g. 'some_service'
➔ Service definitions, in addition to specifying
which class to instantiate and what
constructor arguments to pass in, allow you to
specify additional methods to call on the
object after instantiation
Symfony's DI Component
➔ Default scope: container
➔ Can be configured in PHP, XML or YAML
➔ Can be “compiled” down to plain PHP
Some Symfony Terminology
“Compiling” the container
It's too expensive to parse configuration on
every request.
Parse once and put the result into a PHP class
that hardcodes a method for each service.
“Compiling” the container
Class service_container extends Container {
/**
* Gets the 'example' service.
*/
protected function getExampleService()
{
return $this->services['example'] = new
SomeNamespaceSomeClass();
}
}
“Synthetic” Services
A synthetic service is one that is not instantiated
by the container – the container just gets told
about it so it can then treat it as a service when
anything has a dependency on it.
Bundles
Bundles are Symfony's answer to plugins or
modules, i.e. prepackaged sets of functionality
implementing a particular feature, e.g. a blog.
Bundles need to be able to interact with the
container so they provide a class implementing
the BundleInterace which allows them to do so.
Compiler passes
Compiler passes give you an opportunity to
manipulate other service definitions that have
been registered with the service container.
Use them to:
● Specify a different class for a given service id
● Process “tagged” services
Tagged Services
You can add tags to your services when you
define them. This flags them for some kind of
special processing (in a compiler pass).
For example, this mechanism is used to register
event subscribers (services tagged with
'event_subscriber') to Symfony's event
dispatcher
Symfony's Event Dispatcher
plays an important role in
container wiring
Symfony's Event Dispatcher
➔ Dispatcher dispatches events such as
Kernel::Request
➔ Can be used to dispatch any kind of custom
event
➔ Event listeners are registered to the
dispatcher and notified when an event fires
➔ Event subscribers are classes that provide
multiple event listeners for different events
Symfony's Event Dispatcher
➔ A compiler pass registers all subscribers to
the dispatcher, using their service IDs
➔ The dispatcher holds a reference to the
service container
➔ Can therefore instantiate “subscriber
services” with their dependencies
class RegisterKernelListenersPass implements
CompilerPassInterface {
public function process(ContainerBuilder $container) {
$definition = $container
->getDefinition('event_dispatcher');
$services = $container
->findTaggedServiceIds('event_subscriber');
foreach ($services as $id => $attributes) {
$definition->addMethodCall('addSubscriberService',
array($id, $class));
}
}
}
A compiler pass iterates over the
tagged services
class CoreBundle extends Bundle {
public function build(ContainerBuilder $container)
{
...
// Compiler pass for event subscribers.
$container->addCompilerPass(new
RegisterKernelListenersPass());
...
}
}
Register the compiler pass
Dependency Injection in Drupal 8
Some D8 Services
➔ The default DB connection ('database')
➔ The module handler ('module_handler')
➔ The HTTP request object ('request')
Services:
database:
class: DrupalCoreDatabaseConnection
factory_class: DrupalCoreDatabaseDatabase
factory_method: getConnection
arguments: [default]
path.alias_whitelist:
class: DrupalCorePathAliasWhitelist
tags:
- { name: needs_destruction }
language_manager:
class: DrupalCoreLanguageLanguageManager
path.alias_manager:
class: DrupalCorePathAliasManager
arguments: ['@database',
'@path.alias_whitelist', '@language_manager']
class AliasManager implements AliasManagerInterface {
...
public function __construct(Connection $connection,
AliasWhitelist $whitelist, LanguageManager
$language_manager) {
$this->connection = $connection;
$this->languageManager = $language_manager;
$this->whitelist = $whitelist;
}
...
}
AliasManager's Constructor
2 ways you can use core's
services
1. From procedural code, using a helper
(essentially a service locator)
2. Write OO code and get wired into the
container
Drupal's Application Flow
Get wired in as an event
subscriber
Services:
...
path_subscriber:
class: DrupalCoreEventSubscriberPathSubscriber
tags:
- { name: event_subscriber }
...
Tagged Services
How to get your controller
wired in?
Controllers as Services?
➔ Controllers have dependencies on services
➔ Whether they should be directly wired into
the container is a hotly debated topic in the
Symfony community
➔ Recommended way in D8 is not to make
controllers themselves services but to
implement a special interface that has a
factory method which accepts the container
➔ See book module for an example!
Don't inject the container!
Ever.
(Unless you absolutely must)
Where does it all happen?
➔ The Drupal Kernel:
core/lib/Drupal/Core/DrupalKernel.php
➔ Services are defined in:
core/core.services.yml
➔ Compiler passes get added in:
core/lib/Drupal/Core/CoreBundle.php
➔ Compiler pass classes live here:
core/lib/Drupal/Core/DependencyInjection/
Compiler/...
What about modules?
➔ Services are defined in:
mymodule/mymodule.services.yml
➔ Compiler passes get added in:
mymodule/lib/Drupal/mymodule/MymoduleB
undle.php
➔ All classes, including compiler pass classes,
must live in
mymodule/lib/Drupal/mymodule/
Easy testability with DI and
PHPUnit
PHPUnit Awesomeness
// Create a language manager stub.
$language_manager = $this
->getMock('DrupalCoreLanguageLanguageManager');
$language_manager->expects($this->any())
->method('getLanguage')
->will($this->returnValue((object) array(
'langcode' => 'en',
'name' => 'English')));
PHPUnit Awesomeness
// Create an alias manager stub.
$alias_manager = $this
->getMockBuilder('DrupalCorePathAliasManager')
->disableOriginalConstructor()
->getMock();
$alias_manager->expects($this->any())
->method('getSystemPath')
->will($this->returnValueMap(array(
'foo' => 'user/1',
'bar' => 'node/1',
)));
Resources
These slides and a list of resources on DI and
its use in Symfony and Drupal are available at
http://katbailey.github.io/
Questions?

More Related Content

What's hot

What's hot (13)

Data types
Data typesData types
Data types
 
Tokens in C++
Tokens in C++Tokens in C++
Tokens in C++
 
Select case
Select caseSelect case
Select case
 
Introduction to array and string
Introduction to array and stringIntroduction to array and string
Introduction to array and string
 
TrackBar and TreeView
TrackBar and TreeViewTrackBar and TreeView
TrackBar and TreeView
 
Understanding Box UI Elements
Understanding Box UI ElementsUnderstanding Box UI Elements
Understanding Box UI Elements
 
C++ Pointers And References
C++ Pointers And ReferencesC++ Pointers And References
C++ Pointers And References
 
Decision Making and Branching in C
Decision Making and Branching  in CDecision Making and Branching  in C
Decision Making and Branching in C
 
Introduction to visual basic programming
Introduction to visual basic programmingIntroduction to visual basic programming
Introduction to visual basic programming
 
Strings
StringsStrings
Strings
 
C Programming: Structure and Union
C Programming: Structure and UnionC Programming: Structure and Union
C Programming: Structure and Union
 
Hibernate ppt
Hibernate pptHibernate ppt
Hibernate ppt
 
Java Concurrency by Example
Java Concurrency by ExampleJava Concurrency by Example
Java Concurrency by Example
 

Similar to Dependency Injection in Drupal 8

Dependency injection in CakePHP
Dependency injection in CakePHPDependency injection in CakePHP
Dependency injection in CakePHPmarkstory
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Dependency injection in Drupal 8 : DrupalCon NOLA
Dependency injection in Drupal 8 : DrupalCon NOLADependency injection in Drupal 8 : DrupalCon NOLA
Dependency injection in Drupal 8 : DrupalCon NOLAAshwini Kumar
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDiego Lewin
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
Dependency Injection and Pimple
Dependency Injection and PimpleDependency Injection and Pimple
Dependency Injection and PimpleDQNEO
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014Matthias Noback
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service ManagerChris Tankersley
 
A Series of Fortunate Events - PHP Benelux Conference 2015
A Series of Fortunate Events - PHP Benelux Conference 2015A Series of Fortunate Events - PHP Benelux Conference 2015
A Series of Fortunate Events - PHP Benelux Conference 2015Matthias Noback
 
Angular presentation
Angular presentationAngular presentation
Angular presentationMatus Szabo
 
Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)guiwoda
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...go_oh
 

Similar to Dependency Injection in Drupal 8 (20)

Dependency injection in CakePHP
Dependency injection in CakePHPDependency injection in CakePHP
Dependency injection in CakePHP
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Dependency injection in Drupal 8 : DrupalCon NOLA
Dependency injection in Drupal 8 : DrupalCon NOLADependency injection in Drupal 8 : DrupalCon NOLA
Dependency injection in Drupal 8 : DrupalCon NOLA
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony Container
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Dependency Injection and Pimple
Dependency Injection and PimpleDependency Injection and Pimple
Dependency Injection and Pimple
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
 
Into the ZF2 Service Manager
Into the ZF2 Service ManagerInto the ZF2 Service Manager
Into the ZF2 Service Manager
 
AngularJS
AngularJSAngularJS
AngularJS
 
A Series of Fortunate Events - PHP Benelux Conference 2015
A Series of Fortunate Events - PHP Benelux Conference 2015A Series of Fortunate Events - PHP Benelux Conference 2015
A Series of Fortunate Events - PHP Benelux Conference 2015
 
Angular presentation
Angular presentationAngular presentation
Angular presentation
 
Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)
 
Design patterns in PHP
Design patterns in PHPDesign patterns in PHP
Design patterns in PHP
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
 

Recently uploaded

Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 

Recently uploaded (20)

Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 

Dependency Injection in Drupal 8

  • 2. Intro ● Rudimentary understanding of OOP assumed ● Big changes in D8 ● Not enough time to explain ALL THE THINGS but I'll provide a list of resources for a deeper dive into DI
  • 3. Agenda ● DI as a design pattern ● DI from a framework perspective ● Symfony-style DI ● DI in Drupal 8
  • 4. Agenda ● DI as a design pattern ● DI from a framework perspective ● Symfony-style DI ● DI in Drupal 8 Why? How?
  • 6. Goal: we want to write code that is... ✔Clutter-free ✔Reusable ✔Testable
  • 7. Doing It Wrong 1. An example in procedural code
  • 8. function my_module_func($val1, $val2) { module_load_include('module_x', 'inc'); $val1 = module_x_process_val($val1); return $val1 + $val2; }
  • 9. function my_module_func($val1, $val2) { module_load_include('module_x', 'inc'); $val1 = module_x_process_val($val1); return $val1 + $val2; } ✗ Clutter-free ✗ Reusable ✗ Testable
  • 10. Doing It Wrong 1. An example in procedural code 2. An example in Object Oriented code
  • 11. class Notifier { private $mailer; public function __construct() { $this->mailer = new Mailer(); } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } }
  • 12. class Notifier { private $mailer; public function __construct() { $this->mailer = new Mailer('sendmail'); } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } }
  • 13. class Notifier { private $mailer; public function __construct(Mailer $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } }
  • 14. class Notifier { private $mailer; public function __construct(Mailer $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } } $mailer = new Mailer(); $notifier = new Notifier($mailer);
  • 15. Goal: we want to write code that is... ✔Clutter-free ✔Reusable ✔Testable
  • 16. Goal: we want to write code that is... ✔Clutter-free ✔Reusable ✔Testable Ignorant
  • 17. The less your code knows, the more reusable it is.
  • 18. class Notifier { private $mailer; public function __construct(Mailer $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } } $mailer = new Mailer(); $notifier = new Notifier($mailer);
  • 19. class Notifier { private $mailer; public function __construct(MailerInterface $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } } $mailer = new SpecialMailer(); $notifier = new Notifier($mailer);
  • 20. class Notifier { private $mailer; public function __construct(MailerInterface $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } } $mailer = new SpecialMailer(); $notifier = new Notifier($mailer); Constructor Injection
  • 21. Dependency Injection Declaratively express dependencies in the class definition rather than instantiating them in the class itself.
  • 22. Constructor Injection is not the only form of DI
  • 24. class Notifier { private $mailer; public function setMailer(MailerInterface $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($msg); } } $mailer = new Mailer(); $notifier = new Notifier(); $notifier->setMailer($mailer);
  • 25. class Notifier { private $mailer; public function setMailer(MailerInterface $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($msg); } } $mailer = new Mailer(); $notifier = new Notifier(); $notifier->setMailer($mailer); Setter Injection
  • 26. Interface Injection Like setter injection, except there is an interface for each dependency's setter method. Very verbose Not very common
  • 28.
  • 29.
  • 30. “Don't call us, we'll call you!” (The Hollywood Principle)
  • 31. class Notifier { private $mailer; public function __construct(MailerInterface $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } } $mailer = new Mailer(); $notifier = new Notifier($mailer);
  • 32. class Notifier { private $mailer; public function __construct(MailerInterface $m) { $this->mailer = $m; } public function notify() { ... $this->mailer->send($from, $to, $msg); ... } } $mailer = new Mailer(); $notifier = new Notifier($mailer);?
  • 34. Where does injection happen? ➔ Manual injection ➔ Use a factory ➔ Use a container / injector
  • 35. Using DI in a Framework Dependency Injector == Dependency Injection Container (DIC) == IoC Container == Service Container
  • 36. The Service Container ➔ Assumes responsibility for constructing object graphs (i.e. instantiating your classes with their dependencies) ➔ Uses configuration data to know how to do this ➔ Allows infrastructure logic to be kept separate from application logic
  • 37. Objects as Services A service is an object that provides some kind of globally useful functionality
  • 38. Examples of Services ➔ Cache Backend ➔ Logger ➔ Mailer ➔ URL Generator
  • 39. Examples of Non-Services ➔ Product ➔ Blog post ➔ Email message
  • 40. Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
  • 41. Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
  • 42. Sample configuration <services...> <service id=”notifier” class=”Notifier”> <constructor-arg ref=”emailer” /> </service> <service id=”emailer” class=”Mailer”> <constructor-arg ref=”spell_checker” /> </service> <service id=”spell_checker” class=”SpellChecker” /> </services>
  • 43. How does it work? ➔ Service keys map to service definitions ➔ Definitions specify which class to instantiate and what its dependencies are ➔ Dependencies are specified as references to other services (using service keys) ➔ Keys are unique per object graph ➔ $container->getService('some_service')
  • 44. Service Keys Each key corresponds to a unique object graph, e.g. 'english_mailer' corresponds to new Mailer(new EnglishSpellchecker()) 'french_mailer' corresponds to new Mailer(new FrenchSpellchecker())
  • 45. Container Configuration ➔ Via an API ➔ Using XML ➔ Using YAML
  • 46. Scope The scope of a service is the context under which the service key refers to the same instance.
  • 47. Common Scopes Container scope (aka Singleton scope) The container returns the same instance every time a client requests that service Prototype scope (aka no scope) The container returns a new instance every time a client requests that service Request scope Every request for the service within the context of an HTTP request will get the same instance.
  • 48. Service Locator vs. DI class SomeClass { public function __construct(Locator $sl) { $this->myDep = $sl->get('some_service'); } } In DI, calls like $container->get('some_service') should only happen at the entry point to the application
  • 49. Source: Dependency Injection by Dhanji R. Prasanna, published by Manning
  • 50. Source: Dependency Injection by Dhanji R. Prasanna, published by Manning Service Locator Service Locator
  • 51. Getting wired in is not just about configuration, it's about how the application works with the container.
  • 53. Symfony's DI Component ➔ Service keys are strings, e.g. 'some_service' ➔ Service definitions, in addition to specifying which class to instantiate and what constructor arguments to pass in, allow you to specify additional methods to call on the object after instantiation
  • 54. Symfony's DI Component ➔ Default scope: container ➔ Can be configured in PHP, XML or YAML ➔ Can be “compiled” down to plain PHP
  • 56. “Compiling” the container It's too expensive to parse configuration on every request. Parse once and put the result into a PHP class that hardcodes a method for each service.
  • 57. “Compiling” the container Class service_container extends Container { /** * Gets the 'example' service. */ protected function getExampleService() { return $this->services['example'] = new SomeNamespaceSomeClass(); } }
  • 58. “Synthetic” Services A synthetic service is one that is not instantiated by the container – the container just gets told about it so it can then treat it as a service when anything has a dependency on it.
  • 59. Bundles Bundles are Symfony's answer to plugins or modules, i.e. prepackaged sets of functionality implementing a particular feature, e.g. a blog. Bundles need to be able to interact with the container so they provide a class implementing the BundleInterace which allows them to do so.
  • 60. Compiler passes Compiler passes give you an opportunity to manipulate other service definitions that have been registered with the service container. Use them to: ● Specify a different class for a given service id ● Process “tagged” services
  • 61. Tagged Services You can add tags to your services when you define them. This flags them for some kind of special processing (in a compiler pass). For example, this mechanism is used to register event subscribers (services tagged with 'event_subscriber') to Symfony's event dispatcher
  • 62. Symfony's Event Dispatcher plays an important role in container wiring
  • 63. Symfony's Event Dispatcher ➔ Dispatcher dispatches events such as Kernel::Request ➔ Can be used to dispatch any kind of custom event ➔ Event listeners are registered to the dispatcher and notified when an event fires ➔ Event subscribers are classes that provide multiple event listeners for different events
  • 64. Symfony's Event Dispatcher ➔ A compiler pass registers all subscribers to the dispatcher, using their service IDs ➔ The dispatcher holds a reference to the service container ➔ Can therefore instantiate “subscriber services” with their dependencies
  • 65. class RegisterKernelListenersPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $definition = $container ->getDefinition('event_dispatcher'); $services = $container ->findTaggedServiceIds('event_subscriber'); foreach ($services as $id => $attributes) { $definition->addMethodCall('addSubscriberService', array($id, $class)); } } } A compiler pass iterates over the tagged services
  • 66. class CoreBundle extends Bundle { public function build(ContainerBuilder $container) { ... // Compiler pass for event subscribers. $container->addCompilerPass(new RegisterKernelListenersPass()); ... } } Register the compiler pass
  • 68. Some D8 Services ➔ The default DB connection ('database') ➔ The module handler ('module_handler') ➔ The HTTP request object ('request')
  • 69. Services: database: class: DrupalCoreDatabaseConnection factory_class: DrupalCoreDatabaseDatabase factory_method: getConnection arguments: [default] path.alias_whitelist: class: DrupalCorePathAliasWhitelist tags: - { name: needs_destruction } language_manager: class: DrupalCoreLanguageLanguageManager path.alias_manager: class: DrupalCorePathAliasManager arguments: ['@database', '@path.alias_whitelist', '@language_manager']
  • 70. class AliasManager implements AliasManagerInterface { ... public function __construct(Connection $connection, AliasWhitelist $whitelist, LanguageManager $language_manager) { $this->connection = $connection; $this->languageManager = $language_manager; $this->whitelist = $whitelist; } ... } AliasManager's Constructor
  • 71. 2 ways you can use core's services 1. From procedural code, using a helper (essentially a service locator) 2. Write OO code and get wired into the container
  • 73. Get wired in as an event subscriber
  • 75. How to get your controller wired in?
  • 76. Controllers as Services? ➔ Controllers have dependencies on services ➔ Whether they should be directly wired into the container is a hotly debated topic in the Symfony community ➔ Recommended way in D8 is not to make controllers themselves services but to implement a special interface that has a factory method which accepts the container ➔ See book module for an example!
  • 77. Don't inject the container! Ever. (Unless you absolutely must)
  • 78. Where does it all happen? ➔ The Drupal Kernel: core/lib/Drupal/Core/DrupalKernel.php ➔ Services are defined in: core/core.services.yml ➔ Compiler passes get added in: core/lib/Drupal/Core/CoreBundle.php ➔ Compiler pass classes live here: core/lib/Drupal/Core/DependencyInjection/ Compiler/...
  • 79. What about modules? ➔ Services are defined in: mymodule/mymodule.services.yml ➔ Compiler passes get added in: mymodule/lib/Drupal/mymodule/MymoduleB undle.php ➔ All classes, including compiler pass classes, must live in mymodule/lib/Drupal/mymodule/
  • 80. Easy testability with DI and PHPUnit
  • 81. PHPUnit Awesomeness // Create a language manager stub. $language_manager = $this ->getMock('DrupalCoreLanguageLanguageManager'); $language_manager->expects($this->any()) ->method('getLanguage') ->will($this->returnValue((object) array( 'langcode' => 'en', 'name' => 'English')));
  • 82. PHPUnit Awesomeness // Create an alias manager stub. $alias_manager = $this ->getMockBuilder('DrupalCorePathAliasManager') ->disableOriginalConstructor() ->getMock(); $alias_manager->expects($this->any()) ->method('getSystemPath') ->will($this->returnValueMap(array( 'foo' => 'user/1', 'bar' => 'node/1', )));
  • 83. Resources These slides and a list of resources on DI and its use in Symfony and Drupal are available at http://katbailey.github.io/