Magento 2 – Dependency Injection & Extending a Block

blocksclassdependency-injectionextendmagento2

I seem to be struggling to grasp Magento 2 dependency injection with blocks, every time I try to extend a block that isn't \Magento\Framework\View\Element\Template I end up with errors.

I want to create a block that extends the very basic block class of Magento\Theme\Block\Html\Header\Logo – everything works fine until I try dependency injection within the construct method:

<?php

namespace Creare\Test\Block\Header;

class Logo extends \Magento\Theme\Block\Html\Header\Logo
{

    protected $_creareHelper;

    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Creare\Seo\Helper\Data $creareHelper,
        array $data = []
    )
    {
        $this->_creareHelper = $creareHelper;
        parent::__construct($context, $data);
    }
}

As soon as I try to inject my helper class (or anything else for that matter, I get a stack trace starting with the following error:

Recoverable Error: Argument 2 passed to Magento\Theme\Block\Html\Header\Logo::__construct() must be an instance of Magento\MediaStorage\Helper\File\Storage\Database, array given, called in /Users/adammoss/PhpstormProjects/Magento2/app/code/Creare/Test/Block/Header/Logo.php on line 17 and defined in /Users/adammoss/PhpstormProjects/Magento2/app/code/Magento/Theme/Block/Html/Header/Logo.php on line 33

If I add the same dependencies to my __construct as the file I'm extending from it works, but surely that's a backwards way of doing things as the point of class inheritance is that I absorb all of the parent's methods and properties?

I think I just need a basic 101 explanation from someone on extending from classes and using DI with Magento 2. Any help much appreciated!

Best Answer

The class you are trying to extend has this constructor:

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageHelper,
    array $data = []
) {
    $this->_fileStorageHelper = $fileStorageHelper;
    parent::__construct($context, $data);
}

so you need to make your constructor look like this

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageHelper,
    \Creare\Seo\Helper\Data $creareHelper,
    array $data = []
)
{
    $this->_creareHelper = $creareHelper;
    parent::__construct($context, $fileStorageHelper, $data);
}

Conclusion...
In your child classes you need to specify all the parent class constructor params plus your new params. I don't think the order is important, and I don't know what the best practice is.
Then in the constructor you assign your new injected objects to member vars and call the parent constructor with the same number of parameters it requires.

Related Topic