or send us a message

Magento2 controller dependency injection

Written by: Simon Smith, On: Tuesday 29th August 2017

When you are working on custom Magento2 modules, it can sometimes be difficult to debug issues, especially for uninitiated and those coming from a M1 background.

In particular, working with Magento2 controllers can cause confusion when trying to inject new classes into your own controller class.

For example, here is a controller for a module we made recently for fetching and displaying Trust Pilot reviews;


<?php
namespace PixieMedia\TrustPilot\Controller\Index;

use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\App\Action\Context;
use PixieMedia\TrustPilot\Model\ResourceModel\Trustreview\Collection;
use PixieMedia\TrustPilot\Helper\Trustpilot;

class Reviews extends \Magento\Framework\App\Action\Action
{
	
	protected $helper;
    
	public function __construct(
        Context $context,
        Collection $reviewCollection,
        PageFactory $resultPageFactory,
	Trustpilot $helper
    ) {
        $this->resultPageFactory = $resultPageFactory;
        $this->reviewCollection = $reviewCollection;
	$this->helper = $helper;

        parent::__construct($context);
    }
	
    public function execute() { 
     // do the magic
}
}


Now we decide we want to include the Magento product factory model for use in our controller;


<?php
namespace PixieMedia\TrustPilot\Controller\Index;

use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\App\Action\Context;
use PixieMedia\TrustPilot\Model\ResourceModel\Trustreview\Collection;
use PixieMedia\TrustPilot\Helper\Trustpilot;

class Reviews extends \Magento\Framework\App\Action\Action
{
	
	protected $helper;
        protected $_productFactory;
    
	public function __construct(
        Context $context,
        Collection $reviewCollection,
        PageFactory $resultPageFactory,
	Trustpilot $helper,
        \Magento\Catalog\Model\ProductFactory $productFactory
    ) {
        $this->resultPageFactory = $resultPageFactory;
        $this->reviewCollection = $reviewCollection;
	$this->helper = $helper;
        $this->_productFactory = $productFactory;

        parent::__construct($context);
    }
	
    public function execute() { 
     
    $id = 1;
    // Get product ID 1:
    $_product = $this->loadProductBy($id);
    // Do the magic
}

public function loadProductBy($id) {
    return $this->_productFactory->create()->load($id);
}
}


So code in place, we run our new controller and find this error;


Uncaught TypeError: Argument 5 passed to PixieMedia\TrustPilot\Controller\Index\Reviews::__construct() must be an instance of Magento\Catalog\Model\ProductFactory, none given 


The reason being, controllers typically extend interceptors (/app/action/) and the dependency of plugins (interceptors), factories and proxies are all auto-compiled, even when in developer mode.

The first time these classes are loaded, the instantiated objects and associated object injections are compiled in to the folder;


/var/generation


Personally, I’d like to see an option to disable this while in development mode, but since there is not, we need to delete the contents of this folder when altering the construct function of our controller class so the new dependency injections can take place.


rm –rf var/generation/*


Happy coding!

Pixie Media

We are a Devon's first and only Magento Partner Agency. With over 18 years experience, we offer complete digital solutions to ecommerce clients across the globe.

Magento Business Partner
Pixie Media - Devon's first Magento Partner Agency
Certified Magento Developers
We Specialise In;