1

How to override file Magento\CatalogSearch\Model\Layer\Filter\Category ?

In above file with one $private key available and its create issue to override.

I want to do modify function _getItemsData() from this file.

Code for i have done:

etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\CatalogSearch\Model\Layer\Filter\Category" type="Name\Module\Model\Layer\Filter\Category" />
</config>

Code for Name\Module\Model\Layer\Filter\Category.php

in construct i have to add category model,

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Name\Module\Model\Layer\Filter;

use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
use Magento\Catalog\Model\Layer\Filter\DataProvider\Category as CategoryDataProvider;

/**
 * Layer category filter
 */
class Category extends \Magento\CatalogSearch\Model\Layer\Filter\Category
{
    private $dataProvider;
    protected $categorys;
    public function __construct(
        \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Catalog\Model\Layer $layer,
        \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder,
        \Magento\Framework\Escaper $escaper,
        \Magento\Catalog\Model\Layer\Filter\DataProvider\CategoryFactory $categoryDataProviderFactory,
        \Magento\Catalog\Model\Category $categoryFactory,
        array $data = []
    ) {
        parent::__construct(
            $filterItemFactory,
            $storeManager,
            $layer,
            $itemDataBuilder,
            $escaper,
            $data
        );

        $this->dataProvider = $categoryDataProviderFactory->create(['layer' => $this->getLayer()]);
        $this->categorys = $categoryFactory;
    }
    /**
     * Get data array for building category filter items
     *
     * @return array
     */
    protected function _getItemsData()
    {
        /** @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $productCollection */
        $productCollection = $this->getLayer()->getProductCollection();
        $optionsFacetedData = $productCollection->getFacetedData('category');
        $category = $this->dataProvider->getCategory();
        $categories = $category->getChildrenCategories();

        $collectionSize = $productCollection->getSize();
        //echo 'testes';exit;
        if ($category->getIsActive()) {
            foreach ($categories as $category) { 
                if ($category->getIsActive())
                {
                    $this->itemDataBuilder->addItemData(
                        $this->escaper->escapeHtml($category->getName()),
                        $category->getId(),
                        1//custom add count 
                    );
                }
            }
        }
        return $this->itemDataBuilder->build();
    }
}

After remove var folder and check in frontend,

Notice: Undefined variable: dataProvider in app/code/Name/Module/Model/Layer/Filter/Category.php on line 28
        #0 /var/www/html/mayvillagetrading-com/app/code/Name/Module/Model/Layer/Filter/Category.php(28): Magento\Framework\App\ErrorHandler->handler(8, 'Undefined varia...', '/var/www/html/m...', 28, Array)
1

Since it is a protected method and so you cannot use plugins, you can solve it by adding a preference in your di.xml:

<?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\CatalogSearch\Model\Layer\Filter\Category" type="My\Module\Model\Layer\Filter\Category" />
    ...
</config>

And create a new class extending the previuous:

<?php
namespace My\Module\Model\Layer\Filter;

class Category extends \Magento\CatalogSearch\Model\Layer\Filter\Category {
    ...
    protected function _getItemsData()
    {
        ...
    }
    ...
}

It is more or less the same approach of Magento 1 rewrites.

Optional:

If I correctly understood what you need, you will also probably need to access the private variable $dataProvider.

Since it is a private variable you cannot access it, so the best option is to redefine your logic or copy the whole class code in your new one.

You class will extend AbstractFilter instead of the original Category class.

Your new class will look like this:

<?php
namespace My\Module\Model\Layer\Filter;

use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
use Magento\Catalog\Model\Layer\Filter\DataProvider\Category as CategoryDataProvider;

/**
 * Layer category filter
 */
class Category extends AbstractFilter
{
    /**
     * @var \Magento\Framework\Escaper
     */
    private $escaper;

    /**
     * @var CategoryDataProvider
     */
    private $dataProvider;

    /**
     * @param \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Catalog\Model\Layer $layer
     * @param \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder
     * @param \Magento\Catalog\Model\CategoryFactory $categoryFactory
     * @param \Magento\Framework\Escaper $escaper
     * @param CategoryManagerFactory $categoryManager
     * @param array $data
     */
    public function __construct(
        \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Catalog\Model\Layer $layer,
        \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder,
        \Magento\Framework\Escaper $escaper,
        \Magento\Catalog\Model\Layer\Filter\DataProvider\CategoryFactory $categoryDataProviderFactory,
        array $data = []
    ) {
        parent::__construct(
            $filterItemFactory,
            $storeManager,
            $layer,
            $itemDataBuilder,
            $data
        );
        $this->escaper = $escaper;
        $this->_requestVar = 'cat';
        $this->dataProvider = $categoryDataProviderFactory->create(['layer' => $this->getLayer()]);
    }

    /**
     * Apply category filter to product collection
     *
     * @param   \Magento\Framework\App\RequestInterface $request
     * @return  $this
     */
    public function apply(\Magento\Framework\App\RequestInterface $request)
    {
        $categoryId = $request->getParam($this->_requestVar) ?: $request->getParam('id');
        if (empty($categoryId)) {
            return $this;
        }

        $this->dataProvider->setCategoryId($categoryId);

        $category = $this->dataProvider->getCategory();

        $this->getLayer()->getProductCollection()->addCategoryFilter($category);

        if ($request->getParam('id') != $category->getId() && $this->dataProvider->isValid()) {
            $this->getLayer()->getState()->addFilter($this->_createItem($category->getName(), $categoryId));
        }
        return $this;
    }

    /**
     * Get filter value for reset current filter state
     *
     * @return mixed|null
     */
    public function getResetValue()
    {
        return $this->dataProvider->getResetValue();
    }

    /**
     * Get filter name
     *
     * @return \Magento\Framework\Phrase
     */
    public function getName()
    {
        return __('Category');
    }

    /**
     * Get data array for building category filter items
     *
     * @return array
     */
    protected function _getItemsData()
    {
        /** @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $productCollection */
        $productCollection = $this->getLayer()->getProductCollection();
        $optionsFacetedData = $productCollection->getFacetedData('category');
        $category = $this->dataProvider->getCategory();
        $categories = $category->getChildrenCategories();

        $collectionSize = $productCollection->getSize();

        if ($category->getIsActive()) {
            foreach ($categories as $category) {
                if ($category->getIsActive()
                    && isset($optionsFacetedData[$category->getId()])
                    && $this->isOptionReducesResults($optionsFacetedData[$category->getId()]['count'], $collectionSize)
                ) {
                    $this->itemDataBuilder->addItemData(
                        $this->escaper->escapeHtml($category->getName()),
                        $category->getId(),
                        $optionsFacetedData[$category->getId()]['count']
                    );
                }
            }
        }
        return $this->itemDataBuilder->build();
    }
}

Then change the code you need to change.

There is probably a best way to do it, but we should know what you are going to do.

  • Its not working. i have try same as above.plz test on your site. – Rakesh Jesadiya Apr 26 '16 at 5:00
  • I just tested on my local installation and it seems to be correctly working. Try flushing your cache and clearing var/generation. – Phoenix128_RiccardoT Apr 26 '16 at 7:16
  • display error: Notice: Undefined property: Namespace\Module\Model\Layer\Filter\Category::$dataProvider in /app/code/Namespace/Module/Model/Layer/Filter/Category.php – Rakesh Jesadiya Apr 26 '16 at 11:48
  • $dataProvider is private because it comes form direct injection. You cannot access it from a subclass, you have to require it from your contructor and rebuild the logic. – Phoenix128_RiccardoT Apr 26 '16 at 12:06
  • plz show your full code in answer. – Rakesh Jesadiya Apr 26 '16 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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