Dependency Injection In Magento 2

- Magento 2

Dependency injection is a special design pattern for software developed to implement  control inversion and provide a program with the ability to follow the principle of dependency inversion. Spring, Glassfish HK2, Guice, Microsoft Managed Extensibility Framework and other application frameworks support dependency injection.

An injection is the passing of a service to a client (a dependency to a dependent object). The service is made part of the client’s state. The pattern is based on the next fundamental requirement: a service is passed to a client, instead of allowing a client to find the service. It separates the creation of client’s dependencies from its own behavior. As a result, program designs are loosely coupled and able to follow the single responsibility and dependency inversion principles. The opposite approach is implemented in the service locator pattern, which is designed to allow clients to get the information about the system used to find dependencies.

Magento 2 features: Magento 2 Dependency Injection

Everything about Magento 2 on Firebear

Dependency injection consists of four major elements:

  • a service object implementation;
  • a client object depending on a service;
  • an interface, which connects client with a service;
  • an injector object, which injects service into a client ( it can be provider, assembler, container, spring of factory).

Dependency Injection Advantages

  • Dependency injection can be applied to legacy code as a refactoring, because it requires no change in code behavior.
  • It allows a clients to remove all knowledge of a concrete implementation that they need to use.
  • The pattern can be used to externalize configuration details of a system into configuration files. This feature provides the ability to reconfigure the system without recompilation.
  • It also reduces the boilerplate code in different application objects.
  • Dependency injection allows independent development.

Dependency Injection Disadvantages

  • Dependency injection can make code more difficult to read as in case with legacy code.
  • It also requires some extra lines of code for the same behavior.
  • Dependency injection  diminishes encapsulation.

Overview of dependency injection in Magento 2 

Dependency injection became an alternative to the Magento 1.x Mage class. In simple terms, when Module 1 needs an access to some functions of Module 2, Module 1 depends on Module 2, so it consumes the service provided by Module 2. In this situation, Module 1 is called the consumer and Module 2 – the dependent.

A coding principle that is used to reduce code dependencies is a dependency inversion. According to dependency inversion, both high and low-level modules should depend on abstractions. Details also should depend on abstractions, but at the same time, abstractions should not depend upon details.

Links

Magento 2 Documentation – Dependency Injection 

Inchoo – Basics of dependency injection and its usage in Magento 2

Tuts+ – Dependency Injection in PHP

Dependency injection preview

Magento 2 Сonstructor injection

Constructor injection is used for required and optional service dependencies of an object. You should use a proxy patterns for expensive optional dependencies; the good news is they are auto-generated, so no coding is necessary.

A sample proxy (declared in di.xml):

Method injection

Method injection is used for API objects that your object acts on. The following example illustrates how to use this type of injection to declare $menu and $itemFactory as service dependencies, and use $command as the API parameter that your object acts on

Configuration overview

The object manager requires the below configurations:

  • Class definitions. They are used to retrieve types and numbers of class dependencies;
  • Instance configurations. They are used to retrieve how all the objects are instantiated and what is their lifestyle;
  • Abstraction-implementation mappings. They are used to define what implementation should be used upon the request to an interface

app/etc/di/*.xml, <your module dir>/etc/<areaname>/di.xml, and<your module dir>/etc/di.xml are files required to define the  object manager interface preferences, depending on the level. app/code/core/Magento/Backend/etc/adminhtml/di.xml is used to set the interface preferences for the Magento Admin:

To specify whether or not the object is shareable in its di.xml use the following:

All  dependency injection configurations can be validated by config.xsd.

The levels of object manager configurations :

  • (app/etc/di/*.xml) – global across Magento
  • (<your module directory>/etc/di.xml) – the whole module
  • (<your module directory>/etc/<areaname>/di.xml) – configuration for the specific area of a module

Keep in mind, that area configurations override global configurations.

Class definitions

To define information about class dependencies, Magento relies on class constructor signatures. It reads constructors using reflection, and it is strongly recommend to use the Magento definition compiler tool to pre-compile class definitions, if you are going to get better performance. The parameters specified for class types are inherited by their descendant classes.

Type configurations

Type is the scope of the dependency, including all of Magento, module and module area.

Specify types

This is the example of dependency injection by type:

Magento\Core\Model\Session (set explicitly or taken from the name)The example declares the following types:

  • config  – this virtual type extends Magento\Core\Model\Config
  • moduleConfig  – extends Magento\Core\Model\Config
  • Magento\Core\Model\App – the instances of this type retrieve moduleConfig as a dependency

Arguments

Arguments must be injected into a class instance at a time of its creation. Parameter names must match the configured class constructor parameters. The Object Manager defines:

  • Parameter – declared in the constructor signature variable.
  • Argument – value passed to the constructor after the creation of class instance.

In the following example the sample argument creates instances of Magento\Core\Model\Session and the argument $sessionName is set to a value of adminhtml:

Argument definitions

Node format Description Possible values
Object with default lifestyle 

<argument xsi:type=”object”>
{Type_Name}</argument>

Object with specified lifestyle

<argument xsi:type=”object”
shared=”{shared}”>{Type_Name}</argument>

Creates an instance of Type_Name type. Any class, interface, or virtual type name can be passed as Type_Name. 

shared determines the created instance lifestyle.

n/a

 

Node format Description Possible values
Regular string 

<argument xsi:type=”string”>
{someValue}</argument>

Translated string

<argument xsi:type=”string”
translate=”true”>{someValue}</argument>

someValue is passed as a string. All values are passed as a strings.

 

Node format Description Possible values
<argument xsi:type=”boolean”>
{boolValue}</argument>
boolValue value is turned (converted) into bool Look into the following tabl.

 

Input type Input data Interpreted Boolean type
Boolean true true
Boolean false false
String “true” true
String “false” false
String “1” true
String “0” false
Integer 1 true
Integer 0 false

Keep in mind, that all string literals are case-sensitive.

Node format Description Possible values
<argument xsi:type=”number”>
{numericValue}</argument>
numericValue as-is float, integer, or a numeric string.

 

Node format Description Possible values
<argument xsi:type=”init_parameter”>
{Constant::NAME}</argument>
Global argument of an application represented by Constant::NAME is looked up and passed as an argument. Constant the global argumentcontaining name

 

Node format Description Possible values
<argument xsi:type=”const”>
{Constant::NAME}</argument>
Constant::NAME passed as an argument. All constant names are possible.

 

Node format Description Possible values
<argument xsi:type=”null”/> Pass null as an argument. n/a

 

Node format Description Possible values
<argument xsi:type=”array”>
<item key=”someItem”
xsi:type=”string”>someVal</item>
</argument>
Array with elements (the infinite number of items) corresponding to the items passed as an argument. The items can have any type as arguments, including both an object type and array itself. n/a

The example:

Arguments with the same name will be completely replaced  after configuration is merged. For different argument types and the same names, arguments are overridden.

Parameter configuration inheritance

Configured for a class type parameters are configured for all of their descendants automatically. It their turn, descendants are able to override parameters configured for the supertype:

Lifestyle management

Every object has a lifestyle, which determines in what scope instances should be reused, and when is the correct moment to release them.

The object manager works with the following types of objects:

  • singleton — one class instance is created at the first request. This instance is subsequently reused. It is released when the container is disposed.
  • transient — a new class instance is created every time, when the class is requested.

To configure the preceding lifestyles you can us:

  • argument (it only defines the lifestyle of an argument);
  • type  (this convenience configuration defines lifestyles for all instances of the certain type).

Injectables and non-injectables

Some objects be instantiated by the object manager. They are called Injectable. Object that can’t be instantiated are non-injectable. They have a transient lifestyle and requires external to be created. The better part of models are non-injectable.

  • Non-injectables can’t request other objects in a constructor – injectables can do this.
  • If an injectable object produces non-injectables, then it must ask for the factory in the constructor.
  • If an injectable object performs some actions on non-injectable, then it must receive the non-injectable as a method argument

You always have the ability to both pass non-injectables in as method parameters or create them in services with object factories.

Keep in mind, that the push of injectables to non-injectables violates the Law of Demeter.

Factories

The only purpose of factories is the creation of an for one non-injectable class or interface. They are able to depend on the object manager and are used to isolate OM from a business code:

Definition compiler tool

 

Сlass definitions are read with reflection by default. PHP reflection is slow, so you should use definition compiler tool. It is able to:

  • generate all required factories; proxies declared in di.xml ; and interceptors for all classes with plug-ins in di.xml;
  • compile definitions for all libraries and modules; class inheritance implementation relations; and plug-in definitions.

The compiler tool creates the following files and directories:

  • <your Magento install dir>/var/generation directory with all generated classes and modules.
  • <your Magento install dir>/var/di directory with definitions.php for compiled definitions; relations.php for class inheritance implementation relations; and plugins.php for declared public methods in plug-in definitions.

It is necessary to understand that the tool doesn’t analyze auto-generated factory classes in files from <your Magento install dir>lib/internal/Magento directory.

Create factory classes at the library level manually. Don’t use auto-generation.

Use di.xml only to declare proxy classes.

Use PHP file’s __construct of a class located under<your Magento install dir>app/code to declare factory classes.

Naming rules for an auto-generated proxy class: Some\Model\Name\Proxy; for an auto-generated factory class: Some\Model\NameFactory

Running the definition compiler tool

To run the definition compiler tool , you should first of all be logged in as the web server user. Then, you should change to the [your Magento install dir]/dev/tools/Magento/Tools/Di directory.

This is the command syntax:

If you need to wrap strings, you should use double quotes (“).

Option Description
–serializer <word> Uses serialize (the default one) or binary.
–verbose | v With it you will get the verbose output, without it – errors only.
–extra-classes-file <string> By including it, you will specify factories that are not included into the code base.
–generation <string> It shows the absolute filesystem path necessary to generate service classes: <magento_root>/var/di (the default one).
–help This option displays command help

Specifying extra classes

–extra-classes-file  is a special parameter developed to generate proxies and factories which are not declared in dependency injection or the code base of Magento. Here is the example:

Sample commands

1. Running the definition tool in verbose mode

php compiler.php -v
As a result you should get the following output:

Generated classes:
Magento\AdminNotification\Model\FeedFactory
Magento\AdminNotification\Model\InboxFactory
Magento\Authorization\Model\Acl\Role\GroupFactory
Magento\Authorization\Model\Acl\Role\UserFactory
Magento\Authorization\Model\Resource\Role\CollectionFactory
Magento\Authorization\Model\Resource\Rules\CollectionFactory
Magento\Authorization\Model\RoleFactory
… (more)
2. Specifying an alternate path to generated files

php compiler.php –generation “/var/www/magento2/mydir”
To run the definition compiler tool you must have a write access permission to the directory you specify.

And don’t forget to check the Magento 2 Demo.