The latest versions of Magento Commerce and Magento Open Source v2.4 are now available. More info: https://bit.ly/3h5P28D

Dependency Injection in Magento 2

Magento 2
Dependency in Magento 2

In Magento 2 Dependency Injection is one of the most useful design pattern.

We all are aware about class and objects, class is collection of objects and methods, while object is an instance of class.

Dependency means the class will use objects to perform some function. Injection is process of passing required dependency to that Class / Object. In other words, you can use functions of parent class with the help of dependency injection to reuse code.

If you have one class (Magento\Customer\Block\Form) that fetches data from other class (Magento\Customer\Model\URL), then it is conceived that one class has dependency on other class to provide some data or results.

There are mainly two types of dependency injection in Magento 2 which are as below.

Two type of Dependency Injection In Magento 2
Constructor Injection:

It is the basic type of dependency injection used in Magento 2, where you just have to add parameter in class constructor to inject dependency.

In Magento 2, if you want to get current customer’s data then you can inject dependency of customer session in the created class easily, there is no need to write whole code to get customer data.

To understand this in detail, we take an example. Data block class of custom module to get customer’s data and also it has used viewHelper dependency to get customer name.

<?php
namespace Sparsh\Custom\Block\Data;
 
class Data extends \Magento\Framework\View\Element\Template
{
           protected $_customerSession;
           protected $_viewHelper;
 
	public function __construct(
                \Magento\Framework\View\Element\Template\Context $context,
                \Magento\Customer\Model\Session $customerSession,
                \Magento\Customer\Helper\View $viewHelper
            )
	{
                       /* dependency injection of customerSession and viewHelper for Data class */
                       $this->_customerSession = $customerSession;
                       $this->_viewHelper = $viewHelper;
		parent::__construct($context);
	}
 
	public function getCustomer()
	{
	      return  $this->_customerSession->getData(); // retrive customer data
 
	}
                public function getName()
               {
                  /* get customer name with the help of viewHelper object's dependency injection using
                      customer data*/
                   return $this->_viewHelper->getCustomerName($this->getCustomer());
 
                }
}
?>

Code Sample: Data.php (Constructor Injection)

In above sample code, a defined Data class for custom module is created that will fetch data of customer session.

In this example, Data class has used object customerSession to call the logic of getData() method, where you don’t have to write separate code to get customer session data.

Method Injection:

When a particular method is dependent on class then we have to pass that class as dependency in our method. The best example to understand this concept is Magento Event’s Observer.

To understand this in detail, consider below code sample of sales_order_place_after event’s OrderNumber Observer.

<?php
namespace Sparsh\Custom\Observer;
 
use Magento\Framework\Event\ObserverInterface;
 
class OrderNumber implements ObserverInterface {
 
    /**
     * @param Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer) {
        $order = $observer->getEvent()->getOrder();
        // Do Something Here
    }
}
 
?>

Code Sample: OrderNumber.php(Method Injection)

In the above sample code, Magento\Framework\Event\Observer will be served as a Dependency Injection for OrderNumber class’s execute () method Or we can say that execute() method function of OrderNumber class will be dependent on Magento\Framework\Event\Observer to get order object $order.

ObjectManager:

The ObjectManager is class which handles `automatic` Dependency Injection in Magento 2. When any class is constructed, ObjectManager automatically injects class’s dependencies which is provided directly (Constructor Injection) and defined in all di.xml files of modules.

The di.xml file defines which dependencies are injected by ObjectManager which can be better understood with the use of following di.xml code sample.

<? Xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
          <preference for="Magento\Customer\Api\CustomerNameGenerationInterface"
                type="Magento\Customer\Helper\View" />
</config>

Code Sample: di.xml

According to the above code sample di.xml of customer module has specified dependency of class Magento\Customer\Helper\View on Interface CustomerNameGenerationInterface. Preferences defines which class will be used to instantiate an object.

Consider Constructor Injection Code Sample, in which ObjectManager directly injects dependency of viewHelper, which will use Magento\Customer\Api\CustomerNameGenerationInterface to instantiate viewHelper object according to above di.xml code sample.

Dependency Injection Object Types:

There are mainly two types of Objects in Dependency Injection:

Objects in Dependency Injection
Injectable:

Injectable objects are singleton objects which use di.xml’s configuration for Dependency Injection. Constructor Injection is one of the example of Injectable Objects.

Newable:

It can be also known as non-injectable objects. These objects are used when we will require input from user or database.

For Example, we cannot directly depend on model like Magento\Customer\Model because it cannot be used without customer_id or we have to specify customer object and we cannot specify such data in constructor because it can’t be injectable.

In Magento 2, we can overcome this problem with the use of factories. Factories are classes used to instantiate non-injectable classes, so it can be called as service classes.

Models that represent a database entity is non-injectable class and that can be instantiate using factories. Factory classes provide one layer of abstraction to combine ObjectManager and business code. Injectable objects depends on factories to get newable objects.

Newable objects are obtained by creating new class instance when required with the use of create () method of factory class. There is no need to define factory class because they are automatically generated by ObjectManager when we define factory in class constructor.

For Example, we can directly use customer model’s factory to get specific customer’s data or we can retrieve collection of customer’s data from customer model object.

<?php
namespace Sparsh\Custom\Block;
 
class CustomerData extends \Magento\Framework\View\Element\Template
{
    protected $customerFactory;
 
    /**
     * Construct
     *
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Customer\Model\CustomerFactory $customerSession
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Customer\Model\CustomerFactory $customerFactory,
        array $data = []
    ) {
        parent::__construct($context, $data);
        $this->customerFactory = $customerFactory; // non-injectable objects used factory
    }
 
    public function CustomerData()
    {
        $id = 10 // Customer Id
        /* create new instance of customer model class using injectable object */
        $customerModel = $this->customerFactory->create()->load($id);
        /*call this method to get customer email from customer model object*/
        $customerEmail = $customerModel->getEmail();
        /* retrive collection of customer model  */
        $collection = $customerModel->getCollection();
    }
}
?>

Code Sample: CustomerData.php (Use of Factories)

Another use of ObjectManager is that we can directly use any model class, interfaces in templates, block or constructor.

To understand this consider following example of sample template code.

<?php
     $ObjectManager = \Magento\Framework\App\ObjectManager::getInstance(); // get ObjectManager instance
     $customerid = 14;
     /* create new instance of customer model class using ObjectManager which is same as $customerModel  of above code sample */
     $customer = $ObjectManager->create('Magento\Customer\Model\Customer')->load($customerid);
     echo $customer->getEmail(); //  
?>

Code Sample: custom.phtml (Use Of ObjectManager In Template)

In above code sample, we have used ObjectManager dependency to call customer model and the code written will also give customer’s email from customer’s object.

Both the code (CustomerData.php and custom.phtml) will give customer’s email but it gets differentiated because Magento 2 supports automatic dependency injection as specified. So, when we use factories, we don’t need to take ObjectManager dependencies, Magento 2 will automatically inject it using customer factory; but in templates, Magento 2 does not support automatic dependency injection and we have to use ObjectManager to get customer’s data directly.

Using ObjectManager directly in template is not recommended because it defeats the purpose of dependency injection and if we don’t use ObjectManager directly then our code will be clearer to understand dependency by exploring constructors.

Tell us about your project

Hire dedicated Magento developer from the vast and talented pool of resources.