16

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!

1
  • "surely that's a backwards way of doing things" Agreed.
    – James
    Commented Apr 12, 2016 at 15:24

1 Answer 1

22

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.

5
  • 2
    That makes sense thanks for your answer. I guess I was just hoping it was more elegant than that.
    – Adam Moss
    Commented Jul 16, 2015 at 8:28
  • @Marius order of arguments needs to same as parent class __construct method arguments, your custom arguments need to pass at the end. Commented Jan 4, 2016 at 6:26
  • @chiragdodia Why? I don't think so. Everything I built so far on M2 I built using the custom construct arguments randomly added. And it worked. the only constraint is that the arguments with a default value should go last.
    – Marius
    Commented Jan 4, 2016 at 7:17
  • @Marius yes its working in some of cases but in my case when i have extend \Magento\Catalog\Block\Product\View its not working i need to make same order of arguments as in parent constructor and added custom arguments at last. Take a look at my code here magento.stackexchange.com/questions/95697/… Commented Jan 4, 2016 at 7:55
  • It is not working for me when I tried to override \Magento\Customer\Block\Form\Register Block
    – DEEP JOSHI
    Commented Jan 23, 2018 at 6:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.