Dependency Injection in Magento 2
Magento 2
In Magento 2 Dependency Injection is one of
the most useful design patterns.
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.
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 Pkgroup\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 Pkgroup\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:
Injectable:
Injectable objects are singleton objects which
use “di.xml’s” configuration for Dependency Injection. Constructor Injection is
one of the examples 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 depend on factories to get new able 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 Pkgroup\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.