1

I created this module about a year ago. Maybe because of elasticseach search engine or something now I am facing this error in Magento 2.4.1

main.CRITICAL: Error: Call to undefined method Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\Interceptor::getCollectionClone() in D:\xampp\htdocs\ms241\app\code[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute.php:115

The full function in the Attribute.php file is like this

protected function _getItemsData()
    {
        if (!$this->_moduleHelper->isLayeredNavigationEnabled()) {
            return parent::_getItemsData();
        }

        $attribute = $this->getAttributeModel();

        /** @var \[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection $productCollection */
        $productCollection = $this->getLayer()->getProductCollection();

        if ($this->_isFilter) {
            $productCollection = $productCollection->getCollectionClone()
                ->removeAttributeSearch($attribute->getAttributeCode());// ERROR HERE
        }

        $optionsFacetedData = $productCollection->getFacetedData($attribute->getAttributeCode());

        if (count($optionsFacetedData) === 0
            && $this->getAttributeIsFilterable($attribute) !== static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS
        ) {
            return $this->itemDataBuilder->build();
        }

        $productSize = $productCollection->getSize();

        $itemData   = [];
        $checkCount = false;

        $options = $attribute->getFrontend()
            ->getSelectOptions();
        foreach ($options as $option) {
            if (empty($option['value'])) {
                continue;
            }

            $value = $option['value'];

            $count = isset($optionsFacetedData[$value]['count'])
                ? (int)$optionsFacetedData[$value]['count']
                : 0;

            // Check filter type
            if ($this->getAttributeIsFilterable($attribute) == static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS
                && (!$this->_moduleHelper->getFilterModel()->isOptionReducesResults($this, $count, $productSize))
            ) {
                continue;
            }

            if ($count > 0) {
                $checkCount = true;
            }

            $itemData[] = [
                'label' => $this->tagFilter->filter($option['label']),
                'value' => $value,
                'count' => $count
            ];
        }

        if ($checkCount) {
            foreach ($itemData as $item) {
                $this->itemDataBuilder->addItemData($item['label'], $item['value'], $item['count']);
            }
        }

        return $this->itemDataBuilder->build();

Module's di.xml file is like this

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="categoryFilterList" type="Magento\Catalog\Model\Layer\FilterList">
        <arguments>
            <argument name="filters" xsi:type="array">
                <item name="attribute" xsi:type="string">[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute</item>
                <item name="price" xsi:type="string">[Vendor]\LayeredNavigation\Model\Layer\Filter\Price</item>
                <item name="category" xsi:type="string">[Vendor]\LayeredNavigation\Model\Layer\Filter\Category</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="searchFilterList" type="Magento\Catalog\Model\Layer\FilterList">
        <arguments>
            <argument name="filters" xsi:type="array">
                <item name="attribute" xsi:type="string">[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute</item>
                <item name="price" xsi:type="string">[Vendor]\LayeredNavigation\Model\Layer\Filter\Price</item>
                <item name="category" xsi:type="string">[Vendor]\LayeredNavigation\Model\Layer\Filter\Category</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="Magento\CatalogSearch\Model\ResourceModel\Fulltext\CollectionFactory" type="Magento\Catalog\Model\ResourceModel\Product\CollectionFactory">
        <arguments>
            <argument name="instanceName" xsi:type="string">[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection</argument>
        </arguments>
    </virtualType>
    <virtualType name="Magento\CatalogSearch\Model\ResourceModel\Fulltext\SearchCollection" type="[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection">
        <arguments>
            <argument name="searchRequestName" xsi:type="string">quick_search_container</argument>
        </arguments>
    </virtualType>
</config>

If I do this change navigation filter won't show

if ($this->_isFilter) {
    //$productCollection = $productCollection->getCollectionClone()
    //    ->removeAttributeSearch($attribute->getAttributeCode());
        $productCollectionClone = clone $productCollection;
        $productCollectionClone->removeAttributeSearch($attribute->getAttributeCode());
}

$optionsFacetedData = $productCollectionClone->getFacetedData($attribute->getAttributeCode()); // ERROR HERE

main.CRITICAL: Notice: Undefined variable: productCollectionClone in D:\xampp\htdocs\ms241\app\code[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute.php on line 121

And If I do this change navigation filter is showing but not working

if ($this->_isFilter) {
            //$productCollection = $productCollection->getCollectionClone()
            //    ->removeAttributeSearch($attribute->getAttributeCode());
                $productCollection = clone $productCollection;
                $productCollection->removeAttributeSearch($attribute->getAttributeCode());
        }

main.CRITICAL: Error: Call to undefined method Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\Interceptor::removeAttributeSearch() in D:\xampp\htdocs\ms241\app\code[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute.php:118

[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection.php has getCollectionClone() & removeAttributeSearch() functions like this

public function getCollectionClone()
    {
        if ($this->collectionClone === null) {
            $this->collectionClone = clone $this;
            $this->collectionClone->setSearchCriteriaBuilder($this->searchCriteriaBuilder->cloneObject());
        }

        $searchCriterialBuilder = $this->collectionClone->getSearchCriteriaBuilder()->cloneObject();

        /** @var \[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection $collectionClone */
        $collectionClone = clone $this->collectionClone;
        $collectionClone->setSearchCriteriaBuilder($searchCriterialBuilder);

        return $collectionClone;
    }

public function removeAttributeSearch($attributeCode)
    {
        if (is_array($attributeCode)) {
            foreach ($attributeCode as $attCode) {
                $this->searchCriteriaBuilder->removeFilter($attCode);
            }
        } else {
            $this->searchCriteriaBuilder->removeFilter($attributeCode);
        }

        $this->_isFiltersRendered = false;

        return $this->loadWithFilter();
    }

After adding this to di.xml

<virtualType name="elasticsearchLayerCategoryItemCollectionProvider" type="Magento\Elasticsearch\Model\Layer\Category\ItemCollectionProvider">
        <arguments>
            <argument name="factories" xsi:type="array">
                <item name="elasticsearch7" xsi:type="object">[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\CollectionFactory</item><!-- Alioze AdrienF -->
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="elasticsearchLayerSearchItemCollectionProvider" type="Magento\Elasticsearch\Model\Layer\Search\ItemCollectionProvider">
        <arguments>
            <argument name="factories" xsi:type="array">
                <item name="elasticsearch7" xsi:type="object">[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\CollectionFactory</item><!-- Alioze AdrienF -->
            </argument>
        </arguments>
    </virtualType>

And changing this Magento\Elasticsearch\SearchAdapter\Query\Builder\Sort.php

private const DEFAULT_SKIPPED_FIELDS = [
        'entity_id',
    ];

To

private const DEFAULT_SKIPPED_FIELDS = [
        null,
         'entity_id',
    ];

I am able to filter products with single filter value like one color or one size but multiple selection not working giving me this errors

{"0":"Sorry, something went wrong. You can find out more in the error log.","1":" #1 Magento\Framework\Data\Collection\AbstractDb->_renderFilters() called at [app\code\[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection.php:391]\n #2 [Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection->_renderFilters() called at [vendor\magento\framework\Data\Collection\AbstractDb.php:578]\n #3 Magento\Framework\Data\Collection\AbstractDb->loadWithFilter(false, false) called at [generated\code\[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection\Interceptor.php:1076]\n #4 [Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection\Interceptor->loadWithFilter() called at [app\code\[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection.php:179]\n #5 [Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection->removeAttributeSearch('color') called at [generated\code\[Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection\Interceptor.php:41]\n #6 [Vendor]\LayeredNavigation\Model\ResourceModel\Fulltext\Collection\Interceptor->removeAttributeSearch('color') called at [app\code\[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute.php:116]\n #7 [Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute->_getItemsData() called at [vendor\magento\module-catalog\Model\Layer\Filter\AbstractFilter.php:202]\n #8 Magento\Catalog\Model\Layer\Filter\AbstractFilter->_initItems() called at [vendor\magento\module-catalog\Model\Layer\Filter\AbstractFilter.php:159]\n #9 Magento\Catalog\Model\Layer\Filter\AbstractFilter->getItems() called at [vendor\magento\module-catalog\Model\Layer\Filter\AbstractFilter.php:148]\n#10

Basically, the module was for multiple selections of navigation filters. Like we can choose filter color red and black or any other color also. The same goes for other filters.

I have checked this module is working in Magento 2.3.2 with PHP version 7.1.7 where Configuration->Catalog->Catalog Search->Search engine is = MYSQL

There are many files so let me know if anything else needs to be shared here. Any help would be great.

1
0

Instead of using getCollectionClone() just clone the object with php object clonning clone

Like this:

$productCollection = clone $productCollection;
$productCollection->removeAttributeSearch($attribute->getAttributeCode());

In addition, it would be better if you change your cloned variable $productCollection to $productCollectionClone so that it would be different from main object, otherwise purpose of cloning would be lost and you would endup replacing your main object with clone object

4
  • It gives me this error main.CRITICAL: Error: Call to undefined method Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\Interceptor::removeAttributeSearch() in D:\xampp\htdocs\ms241\app\code\[Vendor]\LayeredNavigation\Model\Layer\Filter\Attribute.php:118 – Klaus Mikaelson Dec 20 '20 at 12:35
  • I have added in the question. What happens when I try both of your suggestions. – Klaus Mikaelson Dec 20 '20 at 12:43
  • why you are using function removeAttributeSearch? I am unable to find it in whole magento code base – Shoaib Munir Dec 20 '20 at 15:36
  • I have added that information also in my question. – Klaus Mikaelson Dec 20 '20 at 16:01

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.