I thought I was quite familiar now with plugins and preferences to override built-in behavior of Magento 2.

However it seems not, and I have a question, is there some particular technical limitations with overriding by preference (on top of that provided in the official documentation) ?. Or any tips?

My example: I created a custom category attribute. As there is some treatment to process before displaying it, I created a Category model in my module, make it inherit the original one, defined my getter for the custom attribute, defined the preference in di.xml.

However, this time it's not working. Instead of preference on the category interface I have to make preference on the model to make it work. Is there a particular technical reason?

My example is when the user access to a category page in the front office.



So, according to your recommendation, I set the di.xml in front end, without success. Hence, there is my code:


<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Vendor_Module" setup_version="1.0.2">
        <module name="Magento_Catalog"/>


<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Api\Data\CategoryInterface" type="Vendor\Module\Model\Category" />

My Model/Category.php contructor:

public function __construct(
    \Vendor\Module\Api\CategoryUrlRepositoryInterface $categoryUrlRepositoryInterface,
    \Magento\Framework\Model\Context $context,
    \Magento\Framework\Registry $registry,
    \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
    AttributeValueFactory $customAttributeFactory,
    \Magento\Store\Model\StoreManagerInterface $storeManager,
    \Magento\Catalog\Api\CategoryAttributeRepositoryInterface $metadataService,
    \Magento\Catalog\Model\ResourceModel\Category\Tree $categoryTreeResource,
    \Magento\Catalog\Model\ResourceModel\Category\TreeFactory $categoryTreeFactory,
    \Magento\Store\Model\ResourceModel\Store\CollectionFactory $storeCollectionFactory,
    \Magento\Framework\UrlInterface $url,
    \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
    \Magento\Catalog\Model\Config $catalogConfig,
    \Magento\Framework\Filter\FilterManager $filter,
    \Magento\Catalog\Model\Indexer\Category\Flat\State $flatState,
    \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator $categoryUrlPathGenerator,
    UrlFinderInterface $urlFinder,
    \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry,
    CategoryRepositoryInterface $categoryRepository,
    \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
    \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
    array $data = []
    parent::__construct($context, $registry, $extensionFactory, $customAttributeFactory, $storeManager, $metadataService,
        $categoryTreeResource, $categoryTreeFactory, $storeCollectionFactory, $url, $productCollectionFactory,
        $catalogConfig, $filter, $flatState, $categoryUrlPathGenerator, $urlFinder, $indexerRegistry, $categoryRepository, $resource, $resourceCollection, $data);

    $this->categoryUrlRepositoryInterface = $categoryUrlRepositoryInterface;
  • what error you are getting while override model using preference? Jan 27, 2017 at 12:51
  • I don't have any error: if I use preference on the CategoryInterface, it simply doesn't work. To make it work, I have to do it on the Model. And as far I know (correct me if I am wrong), in dependency injection with service contract, I have to preference with the interface, not the model.
    – enrico69
    Jan 27, 2017 at 13:20

3 Answers 3


There's not enough information in your question to be sure, but my guess is that this is likely a load order issue. I've run into these before with di.xml files. Make sure that your di.xml is located in an appropriate area folder, if necessary. It can be in the main etc/ directory but do know that it will be overwritten by area-specific DI.

So, for example, if your file is in etc/, and the Magento one is in etc/frontend, the Magento one will take precedence. If they're both in the same directory level (e.g., etc/frontend), I suggest making your module depend on the Magento_Catalog module to ensure that it is loaded after the Magento_Catalog module.

  • No effects. I posted my code as requested.
    – enrico69
    Jan 30, 2017 at 14:57

Post your di.xml and constructor class code that handles dependencies.

Looks like there is some issue in your created module. Updated after code posted : Magento\Catalog\Api\Data\CategoryInterface for this I dont see where this has been injected in constructor class.You need to place this as an argument in Constructor

  • Do you mean that it may be a constructor issue?
    – enrico69
    Jan 30, 2017 at 14:57

If you checkout the constructor for the following class: Magento\Catalog\Model\CategoryRepository, you can see, it is using the Magento\Catalog\Model\CategoryFactory as argument.

That is why your preference set on the CategoryInterface does not work.

If instead it would have been Magento\Catalog\Api\Data\CategoryInterfaceFactory it would have worked.

You can make the test by changing its constructor and you will see it works if you replace it by the CategoryInterfaceFactory and apply your previous preference.

  • OK thanks. But I don't want (and never have to) change core files. So is there a solution for me to respect the service contract or am I stuck?
    – enrico69
    Feb 2, 2017 at 11:26
  • No idea? It is strange that it couln't be done.
    – enrico69
    Feb 10, 2017 at 13:14

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.