Hey to Amasty blog readers!

We are continuing with our posts in preparation for the Magento 2 certification exam. This time we asked Stanislav, one of our team Magento 1 certified developers and a Zend Certified Engineer, to tell about Magento’s dependency injection approach and architecture. Read on to find out how to use the dependency injection at first hand.

What is Magento 2 dependency injection?

Dependency injection is a design pattern that allows declaring object dependencies in Magento 2. The realization allows not only to make your code more structural and independent but also to make the process of coding more convenient.

How are objects realized in Magento 2?

As you know, in Magento 1 objects are handled with the use of the Mage class. In Magento 2 we use Object Manager and Dependency Injection that replaced the functionality provided by the Mage. This has allowed for the loose coupling of code.

Read the official documentation on DI here.

How to get a class object in pure PHP?

In Magento 2, we can apply the $object = new SomeClass(); method to get a class object in pure PHP. However, we’ll be deprived of the benefits from the Magento 2 ObjectManager usage.

To learn more about the ObjectManager, read here.

How to get a class object in Magento 2 by using ObjectManager?

You can hardly see any benefits from the $objectManager->create(‘SomeClass’); variant. But let’s look at this in greater detail.

The first (1) advantage of the method is that instead of writing your Singleton for a class you can use $objectManager->get(‘SomeClass’); to apply Singleton for any class.

If you want to get how it works, see here: \Magento\Framework\ObjectManager\ObjectManager.

The second (2) advantage lies in the possibility to use the Automatic Dependency Injection. So, what does that give you? This allows you to make injections of code in the existing code.

In this case, we can change the imageUploader for any other variant. Besides, we won’t have to make any changes to the original class. When using the ObjectManager for classes creation, dependencies are automatically substituted from the class constructor.

Along with this, there is the third (3) advantage. It becomes possible to inject the class’s dependencies into the class constructor through the di.xml file, which can be very convenient. E.g.: say, we have the next class with constructor \Magento\Framework\App\RouterList:
public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, array $routerList)

We can add the next code into the di.xml file of the module:

and, as a result, the parameter defined in the di.xml file will be injected into the routerList constructor in \Magento\Framework\App\RouterList.

While transferring classes to a constructor the same $objectManager->create(SomeImageUploader) code is applied. And if you pass SomeImageUploaderFactory instead of SomeImageUploader to the constructor, a factory will be created automatically. E.g.: let’s say there is a SomeImageUploader class and we need to get a SomeImageUploader factory in another class. For this, you need to add SomeImageUploaderFactory to the constructor and then use $this->imageUploaderFactory>create(); to get the class object:

Note that in the SomeImageUploader class there is an imageUploaderFactory variable to which we have assigned the SomeImageUploaderFactory value.

Learn more about factories from here. Due to the auto-generation, proxy becomes available too. Find more information on it here.

Thus, we don’t need to write a factory manually, because of the code auto-generation. You can learn more about the code generation from here.

Why is it important to have a centralized process creating object instances?

It is thanks to the centralized creation of objects that you can use the advantages described above. Moreover, it gives you a possibility to avoid the inheritance, which means that applications become more flexible. In this, you don’t need to think about the child classes when changing the parent one.

How to use DI configuration files for customizing Magento 2?

To customize Magento 2 you need to work in the <moduleDir>/etc/di.xml DI configuration file.

How can you override a native class?

The method resembles rewrites in Magento 1 and allows for classes rewrite as well. However, if you have a possibility to use plugins, don’t apply the rewrite method. It can lead to conflicts when there are other extensions. E.g.: 

How to customize Magento 2 by using plugins?

Plugins can be applied to the flexible behavior change of the public functions. E.g:

You can read more about their usage here.

How can you inject your class into another object?

You can find the examples of class injections into another object in Magento 2 code. E.g.: say, Magento\Sales\Model\ResourceModel\Provider\UpdatedIdListProvider is our own class that we want to inject and the vendor/magento/module-sales/Model/ResourceModel/Provider/NotSyncedDataProvider.php is the class object in which we are going to inject our class:

Other techniques available in di.xml: VirtualType

Virtual types are convenient for DI only in case we need to indicate our classes in the dependencies. Thus, you won’t need to create a separate class.

You can find many examples in Magento 2 simply by using virtualType search query in the di.xml file. E.g.: in the magento2/vendor/magento/module-sales/etc/di.xml file:

That’s it for today! We hope, the post will help you receive an outline of DI in Magento 2. Please, refer to the official Magento DevDocs to learn more.

Drop us a line if you still have questions on the topic.

Stay tuned!