9

I have created a module for rating filter and its working but after filter number of item and pagination showing wrong as per attached screenshot.

There is only one 5 start product but showing wrong item and pagination.

Below is the code which is developed by me:

app/code/Namespace/Catalog/Model/Layer/Filter/Rating.php

<?php

/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Namespace\Catalog\Model\Layer\Filter;

use Magento\Catalog\Model\Category as CategoryModel;
use Magento\Catalog\Model\CategoryFactory as CategoryModelFactory;
use Magento\Catalog\Model\Layer;
use Magento\Framework\Registry;

/**
 * Layer category filter
 *
 * @author      Magento Core Team <[email protected]>
 */
class Rating extends \Magento\Catalog\Model\Layer\Filter\AbstractFilter {

    /**
     * Active Category Id
     *
     * @var int
     */
    protected $_categoryId;

    /**
     * Applied Category
     *
     * @var \Magento\Catalog\Model\Category
     */
    protected $_appliedCategory;

    /**
     * Core data
     *
     * @var \Magento\Framework\Escaper
     */
    protected $_escaper;

    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry;

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

    /**
     * Construct
     *
     * @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\Framework\Escaper $escaper
     * @param CategoryFactory $categoryDataProviderFactory
     * @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\Framework\ObjectManagerInterface $objectManager, 
    \Magento\Catalog\Model\Product $productModel, 
    \Magento\Catalog\Model\Product\Attribute\Source\Status $productStatus, 
    \Magento\Catalog\Model\Product\Visibility $productVisibility, 
    \Magento\Store\Model\StoreManagerInterface $storeManager,            
    array $data = []
    ) {
         $this->_storeManager = $storeManager;        
        parent::__construct($filterItemFactory, $storeManager, $layer, $itemDataBuilder, $data);
        $this->_escaper = $escaper;
        $this->objectManager = $objectManager;
        $this->_productModel = $productModel;
        $this->productStatus = $productStatus;
        $this->productVisibility = $productVisibility;
         $this->_requestVar = 'rating';
    }

    protected $stars = array(
        1 => 20,
        2 => 40,
        3 => 60,
        4 => 80,
        5 => 100,
    );    

    /**
     * Get filter value for reset current filter state
     *
     * @return mixed|null
     */


    /**
     * Apply category filter to layer
     *
     * @param   \Magento\Framework\App\RequestInterface $request
     * @return  $this
     */
    public function apply(\Magento\Framework\App\RequestInterface $request) {
        /**
         * Filter must be string: $fromPrice-$toPrice
         */
        $filter = $request->getParam($this->getRequestVar());
        if (!$filter) {
            return $this;
        }
        $collection = $this->getLayer()->getProductCollection();
        $select = $collection->getSelect();
        $minRating = (array_key_exists($filter, $this->stars))
            ? $this->stars[$filter]
            : 0;
        $reviewSummary = 'review_entity_summary';
        $select->joinLeft(
            array('rating' => $reviewSummary),
            sprintf('`rating`.`entity_pk_value`=`e`.entity_id
                    AND `rating`.`entity_type` = 1
                    AND `rating`.`store_id`  =  %d',
                $this->_storeManager->getStore()->getId()
            ),
            ''
        );
        $select->where('`rating`.`rating_summary` >= ?',
            $minRating);
        $state = $this->_createItem($this->getLabelHtml($filter), $filter)
                      ->setVar($this->_requestVar);
        $this->getLayer()->getState()->addFilter($state);


        return $this;
    }

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

    protected function _getItemsData()
    {   
        $data = array();
        $count = $this->_getCount();

        $currentValue = $this->getRequestVar();
        for ($i=1;$i<=5;$i++) {
            $data[] = array(
                'label' => $this->getLabelHtml($i),
                'value' => ($currentValue == $i) ? null : $i,
                'count' => $count[($i-1)],
                'option_id' => $i,
            );
        }
        return $data;
    }
    /**
     * @return array
     */
    protected function _getCount()
    {
        $collection = $this->getLayer()->getProductCollection();
        $connection = $collection->getConnection();
        $connection
            ->query('SET @ONE :=0, @TWO := 0, @THREE := 0, @FOUR := 0, @FIVE := 0');
        $select = clone $collection->getSelect();

        $select->reset(\Zend_Db_Select::COLUMNS);
        $select->reset(\Zend_Db_Select::ORDER);
        $select->reset(\Zend_Db_Select::LIMIT_COUNT);
        $select->reset(\Zend_Db_Select::LIMIT_OFFSET);
        $select->reset(\Zend_Db_Select::WHERE);      
        $reviewSummary = 'review_entity_summary';
        $select->joinLeft(
            array('rsc' => $reviewSummary),
            sprintf('`rsc`.`entity_pk_value`=`e`.entity_id
                AND `rsc`.entity_type = 1
                AND `rsc`.store_id  =  %d',
                $this->_storeManager->getStore()->getId()),
            'rsc.rating_summary AS rating'
        );
        $columns = new \Zend_Db_Expr("
            IF(`rsc`.`rating_summary` <  40, @ONE := @ONE + 1, 0),
            IF(`rsc`.`rating_summary` >= 40 AND `rsc`.`rating_summary` < 60, @TWO := @TWO + 1, 0),
            IF(`rsc`.`rating_summary` >= 60 AND `rsc`.`rating_summary` < 80, @THREE := @THREE + 1, 0),
            IF(`rsc`.`rating_summary` >= 80 AND `rsc`.`rating_summary` < 100, @FOUR := @FOUR + 1, 0),
            IF(`rsc`.`rating_summary` >= 100, @FIVE := @FIVE + 1, 0)
        ");
        $select->columns($columns);
        $connection->query($select);
        $result = $connection->fetchRow('SELECT @ONE, @TWO, @THREE, @FOUR, @FIVE;');
        return array_values($result);
    }
    protected function _initItems()
    {   
        $data  = $this->_getItemsData();

        $items = array();
        foreach ($data as $itemData) {
            $item = $this->_createItem(
                $itemData['label'],
                $itemData['value'],
                $itemData['count']
            );
            $item->setOptionId($itemData['option_id']);
            $items[] = $item;
        }
        $this->_items = $items;

        return $this;
    }

    protected function getLabelHtml($countStars)
    {
         $html = '<div class="rating-summary" style="display: inline-block;margin-top: -5px;">
                                        <div class="rating-result" title="100%">
                                            <span style="width:'.$countStars*20 .'%"></span>
                                        </div>
                                    </div>';
        return $html;
    }



}

?>

enter image description here

4
  • Hi Nikunj Vadariya, did you find an answer to this question?
    – Ruud N.
    May 30, 2017 at 11:05
  • just for curiosity, what happens if you visit the second page?
    – juhanix
    Jun 1, 2017 at 7:53
  • @juhanix it will say that products matching the selection can't be found.
    – Ruud N.
    Jun 1, 2017 at 14:06
  • HI @Nikunj Vadariya, I have try your Rating.php file and it's working for me, but when I filter for 2 star rating it display all product, any solution for that?
    – MageDev
    Aug 24, 2020 at 6:01

2 Answers 2

1

What fixed the problem for me was exruciatingly simple, yet so hard to find: $collection->getSize();

You need to call that method in the apply method of your filter.

EDIT: my working code below

public function apply(\Magento\Framework\App\RequestInterface $request)
    {
        $filter = $request->getParam($this->getRequestVar(), null);
        if (is_null($filter)) {
            return $this;
        }
        $this->_activeFilter = true;

        $collection = $this->getLayer()->getProductCollection();
        $collection->setFlag(self::WIDTH_COLLECTION_FLAG, true);

        // Paste magic code to calculate $included_entities, which is an array of product id's. 

        $collection->getSelect()->where('e.entity_id IN (' . implode(',',$included_entities) . ')');
        $this->getLayer()->getState()->addFilter(
            $this->_createItem($filter, $filter)
        );
        $collection->getSize(); // This did the trick!
        return $this;
    }
3
  • Pls share your working code so it will help others Jun 7, 2017 at 4:17
  • Updated the answer accordingly.
    – Ruud N.
    Jun 7, 2017 at 10:35
  • @NikunjVadariya I need help for filtering mate Sep 2, 2019 at 13:15
0

Can you try instead of

$collection = $this->getLayer()->getProductCollection();

to

$collection = $this->getLayer()->getLoadedProductCollection();

I was facing similar issues and solved by this.

1
  • Thank you for your answer, but getLoadedProductCollection is not a method in \Magento\Catalog\Model\Layer.
    – Ruud N.
    Jun 6, 2017 at 14:25

Your Answer

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

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