Dependency Injection

&

Services

in

Drupal 8

GOAL

Understand the driving concepts and reasons for using Dependency Injection

Understand the pattern and its usages in Drupal 8 specifically, via the Service Container and specific methods

implements

INVERSION

OF CONTROL

DEPENDENCY INJECTION

is a

DESIGN

PATTERN

enables

LOOSE

COUPLING

DESIGN PATTERN

Reusable solution for common software design problems.

Examples:

  • Singleton
  • Dependency Injection
  • many many others

LOOSE COUPLING

Less

interconnection

Less

knowledge about each other

Less

coordination

is a PRINCIPLE,

which offers

Example of tight coupling

Example of tight coupling

Example of less tight coupling

What happens if SMS notification is needed?

Example of tight coupling

Example of less tight coupling

Loose Coupling

Who is responsible for instantiating the Notifier class?

Custom Code

  • our custom code is responsible for instantiating the Notifier
    class and its dependencies
  • our custom code is responsible for the control of the flow

Framework

  • control is passed to a framework, which is designed to discover our implementations
  • it is also responsible to instantiate and inject the dependencies for our implementations

VS.

Inversion of Control

  • describes a design in which a re-usable library calls the custom code and not the other way around

  • control is passed to a framework, which is designed to discover our implementations
  • it is also responsible to instantiate and inject the dependencies for our implementations

Inversion of Control

Inversion of Control

 in Drupal

Drupal 7

 

The hook system

Drupal 8

 

  • Dependency Injection
  • Event Listener/

    Observer pattern

 

Short Recap

implements

INVERSION

OF CONTROL

DEPENDENCY INJECTION

is a

DESIGN

PATTERN

enables

LOOSE

COUPLING

3 types of Dependency Injection

  • Constructor injection
  • Setter injection
  • Interface injection

Constructor injection

Setter Injection

Interface Injection

In real life applications

Dependency injection involves four roles:

  • the service object(s) to be used (e.g. Email, Sms classes)
  • the client object that is depending on the services it uses (e.g. Notifier class)
  • the interfaces that define how the client may use the services (e.g. Notification interface)
  • the injector, which is responsible for constructing the services and injecting them into the client (a service container of a Framework, in our case the Drupal 8 service container)

Conclusion

"When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn't want you to have. You might even be looking for something we don't even have or which has expired.

What you should be doing is stating a need, "I need something to drink with lunch," and then we will make sure you have something when you sit down to eat."

 

John Munsch, 28 October 2009.

Questions so far?

DI In Drupal 8

D8 Service Container

public static function create()

The Service Container:
Why and what?

Drupal 7

  • Inversion of Control exists
  • Loose Coupling is lacking
  • Too much interdependency when writing custom modules

Drupal 8

  • defines the term "service"
    which is reusable functionality
  • defines its services in configuration
  • uses the Service Container to use a defined service

What is a Service?

What is a Service?

  • one of the four roles in the Dependency Injection pattern
  • in Drupal 8 it's used to decouple reusable functionality and makes these services pluggable and replaceable by registering them with a service container

Service configuration example

services:
  http_kernel:
    class: Stack\StackedHttpKernel
  http_kernel.basic:
    class: Symfony\Component\HttpKernel\HttpKernel
    arguments: ['@event_dispatcher', '@controller_resolver', '@request_stack']

What is a Service Container?

What is a Service Container?

  • it is an array of definitions specified in .services.yml configuration files
  • Drupal 8 compiles the definitions in these files into a single object that contains all the service definitions

The service container

Who is responsible for instantiating our services?

public static function create()

  • ContainerInjectionInterface
  • ContainerFactoryPluginInterface
  • ContainerDeriverInterface

Dependency Injection Example in a
Custom Controller

Example

services:
  module_name.notifier:
    class: Drupal\module_name\Notifier
    arguments: ['']

Example

Container::get

Creates an instance of the service with all the necessary dependencies by calling the Container::createService method.

How does it work?

Execution flow in our example

 public function getInstanceFromDefinition($definition) {
    if ($this->container->has($definition)) {
      $instance = $this->container->get($definition);
    }
    else {
      if (!class_exists($definition)) {
        throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $definition));
      }

      if (is_subclass_of($definition, 'Drupal\Core\DependencyInjection\ContainerInjectionInterface')) {
        $instance = $definition::create($this->container);
      }
      else {
        $instance = new $definition();
      }
    }

    if ($instance instanceof ContainerAwareInterface) {
      $instance->setContainer($this->container);
    }

    return $instance;
  }

Questions?

Bibliography

Thanks!

 

Services and Dependency Injection

By benelori

Services and Dependency Injection

  • 556