1

I'm trying to extend a Block in Magento, the Magento\Catalog\Block\Product\ListProduct block and Inject a dependency on it, but I've hit a wall and just get this error.

Fatal error: Uncaught TypeError: Argument 2 passed to Holy\Demo\Block\Product\ListProduct::__construct() must implement interface Magento\CatalogInventory\Api\StockStateInterface, instance of Magento\Framework\Data\Helper\PostHelper given, called in /var/www/html/generated/code/Holy/Demo/Block/Product/ListProduct/Interceptor.php on line 14 and defined in /var/www/html/app/code/Holy/Demo/Block/Product/ListProduct.php:14 Stack trace: #0 /var/www/html/generated/code/Holy/Demo/Block/Product/ListProduct/Interceptor.php(14): Holy\Demo\Block\Product\ListProduct->__construct(Object(Magento\Catalog\Block\Product\Context), Object(Magento\Framework\Data\Helper\PostHelper), Object(Magento\Catalog\Model\Layer\Resolver), Object(Magento\Catalog\Model\CategoryRepository\Interceptor), Object(Magento\Framework\Url\Helper\Data), Array) #1 /var/www/html/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php(111): Holy\Demo\Block\Product\ListProduct\Inte in /var/www/html/app/code/Holy/Demo/Block/Product/ListProduct.php on line 14

This is the di.xml of my module:

<?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\Catalog\Block\Product\ListProduct" type="Holy\Demo\Block\Product\ListProduct" />
</config>

And this is my Block class:

<?php

namespace Holy\Demo\Block\Product;

/**
 * Product list
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class ListProduct extends \Magento\Catalog\Block\Product\ListProduct
{
    /**
     * @param \Magento\CatalogInventory\Api\StockStateInterface $stockState
     */
   public function __construct(
       \Magento\Catalog\Block\Product\Context $context,
//        \Magento\Backend\Block\Template\Context $context,
       \Magento\CatalogInventory\Api\StockStateInterface $stockState,
       array $data = []
   )
   {
       $this->stockState = $stockState;
       parent::__construct($context, $data);
   }

    public function getStockQty($product) {
      // TODO: Don't use objectManager, Inject the \Magento\CatalogInventory\Api\StockStateInterface on the constructor of the block
      // $_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
      // $_stockState = $_objectManager->get('\Magento\CatalogInventory\Api\StockStateInterface');
      // return $_stockState->getStockQty($product->getId(), $product->getStore()->getWebsiteId());

       return $this->stockState->getStockQty($product->getId(), $product->getStore()->getWebsiteId());
    }
}

UPDATE

I was able to get it working by adding all of the parent class arguments from it's constructor to my constructor, but this does not seem like a good approach to me as if in a Magento update a new dependency is added to the parent class, won't that break my module?

public function __construct(
    \Magento\Catalog\Block\Product\Context $context,
    \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
    \Magento\Catalog\Model\Layer\Resolver $layerResolver,
    \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository,
    \Magento\Framework\Url\Helper\Data $urlHelper,
    \Magento\CatalogInventory\Api\StockStateInterface $stockState,
    array $data = []
)
{
    $this->stockState = $stockState;
    parent::__construct($context, $postDataHelper , $layerResolver, $categoryRepository, $urlHelper, $data);
}
6
  • Try to clear your cache and remove var/generation.
    – Zefiryn
    Commented Apr 19, 2017 at 23:01
  • thanks but i tried that already
    – Holly
    Commented Apr 19, 2017 at 23:07
  • In your updated info, it's ok! Magento used this approach. Commented Apr 20, 2017 at 5:35
  • @KhoaTruongDinh yes you are correct Commented Apr 20, 2017 at 5:40
  • if in a Magento update a new dependency is added to the parent class, could that break my module?
    – Holly
    Commented Apr 20, 2017 at 5:42

1 Answer 1

1

Your child arguments constructor should inherit from parent class:

 public function __construct(
        \Magento\Catalog\Block\Product\Context $context, 
        \Magento\Framework\Data\Helper\PostHelper $postDataHelper, 
        \Magento\Catalog\Model\Layer\Resolver $layerResolver,
        \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository, 
        \Magento\Framework\Url\Helper\Data $urlHelper, 
        array $data = []
    )
    {
        parent::__construct($context, $postDataHelper, $layerResolver, $categoryRepository, $urlHelper, $data);
    }

Remember to remove var/generation and clear cache also.

[EDIT]

For this answer: Magento 2 StoreManagerInterface already exists in context object in compilation. We don't need to inject \Magento\Store\Model\StoreManagerInterface in our child class, but we inject \Magento\Framework\View\Element\Context in the construct. This class has \Magento\Store\Model\StoreManagerInterface in its constructor already.

6
  • Thanks, that worked. Why do I need to pass in all the arguments from the parent? I've read in other answers that you don't need to inject dependencies in your constructor if the parent class already has them. What if in a Magento update a new dependency is added to the parent class, won't that break my module?
    – Holly
    Commented Apr 20, 2017 at 4:32
  • Also, I don't have a var/generation directory, I think becuase I'm working in developer mode, but I cleared the cache and ran php bin/magento setup:upgrade; php bin/magento setup:di:compile; which from the devdocs I believe should take care of any cache issues
    – Holly
    Commented Apr 20, 2017 at 4:36
  • @Holy magento.stackexchange.com/a/136211/6549 . We don't need to inject \Magento\Store\Model\StoreManagerInterface in our child, but we inject \Magento\Framework\View\Element\Context in the construct. This class has \Magento\Store\Model\StoreManagerInterface in its constructor already. Commented Apr 20, 2017 at 4:40
  • yes, that's why I'm wondering why I need to add them if it's in the parent constructor already, see my updated Question.
    – Holly
    Commented Apr 20, 2017 at 5:10
  • can you update your answer to include the \Magento\CatalogInventory\Api\StockStateInterface $stockState dependency from my question? Just to make it clearer to others who may view this later. Thanks :)
    – Holly
    Commented Apr 20, 2017 at 9:19

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.