Drupal is changing a lot in 8.x, and one of those major changes is adding the Drupal Dependency Container. What is that exactly?
Explain Yourself
- Dependency injection is a design pattern used to dynamically load service objects, such as a mail delivery service.
- Normally an object decides what service classes it will use – it will instantiate an object of a given class, then use it. In dependency injection the object will call the injection container which will provide it suitable classes depending on runtime configuration.
- Sometimes called ‘Inversion of control’
- The injector is often called a container.
Why all the fuss?
- Allows selection from multiple potential interfaces at runtime
- Creates highly pluggable systems – easily switch out caching backends for example.
- Great for testing – no need to bootstrap or live connections to external services, just give the subsystem a stub implementation. Components can be tested in isolation.
How does it work?
- Specify the interface for the dependency
- Let the container object select the implementation
Types of Injection
- Constructor injection – most common, pass in service object via constructor.
- Setter injection – good for optional dependencies
- Property injection – set public attributes directly.
Drupal’s DIC Implementation
One of the first things drupal_handle_request() does is instantiate an object of class DrupalKernel, which is extended from Symfony’s HttpKernel class Kernel.
Getting a service from the container:
$request = drupal_container()->get('request'); $path = $request->attributes->get('system_path');
To create a new service we implement the Bundle class:
<?php // This file should be located at: my_module/lib/Drupal/my_module/MyModuleBundle.php /** * @file * Definition of Drupal\my_module\MyModuleBundle.php. */ namespace Drupal\my_module; use \Symfony\Component\HttpKernel\Bundle\Bundle; use \Symfony\Component\DependencyInjection\ContainerBuilder; // This line is only needed if actually using the Reference class as below. use \Symfony\Component\DependencyInjection\Reference; /** * The bundle for my_module.module. */ class MyModuleBundle extends Bundle { public function build(ContainerBuilder $container) { // This registers the specified class to be lazy-instantiated when // mymodule.some_service is requested from the container, with a constructor // parameter of the container itself. $container->register('my_module.some_service', 'Drupal\mymodule\SomeClassHere') ->addArgument(new Reference('service_container')); } } ?>
You can see the core implementation of this in lib/Drupal/Core/CoreBundle.php. Some of the services registered include:
- Configuration system
- Database connection
- Queue system
- Path alias manager
- Entity manager
- HTTP Kernel
- Language manager
- Twig
Thats a pretty basic overview of Dependency Injection and how it is implemented in Drupal. Lots more information can be found in the links below.
References
- Wikipedia is always a good page to start
- This is the article
- The drupal.org issue where Dependency Injection was committed
- Change Record for DIC in Drupal
- Documentation for Symfony’s Dependency Injection Component
- Symfony’s dependency injector on GitHub
- http://www.theserverside.com/news/1321158/A-beginners-guide-to-Dependency-Injection
Dependency injection is a great approach in programming and it can also be applied into other programming languages.
Thanks for the article.