2

On the product view page the reviews get loaded via the following code:

$_items = $block->getReviewsCollection()->getItems();

This is what the getReviewsCollection function looks like:

public function getReviewsCollection()
{
    if (null === $this->_reviewsCollection) {
        $this->_reviewsCollection = $this->_reviewsColFactory->create()->addStoreFilter(
            $this->_storeManager->getStore()->getId()
        )->addStatusFilter(
            \Magento\Review\Model\Review::STATUS_APPROVED
        )->addEntityFilter(
            'product',
            $this->getProduct()->getId()
        )->setDateOrder();
    }
    return $this->_reviewsCollection;
}

This is later used in the following way:

foreach ($_items as $_review):
    ...
    ...
    foreach ($_review->getRatingVotes() as $_vote):
        ...
        ...

I'm trying to replicate this in order to display the recently reviewed products on the category pages. My code so far looks like this:

public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
    \Magento\Framework\Registry $registry,
    \Magento\Review\Model\ResourceModel\Review\CollectionFactory $reviewCollection,
    \Magento\Store\Model\StoreManagerInterface $storeManager, 
    \Magento\Framework\View\Element\Template\Context $context,
    array $data = []
) {
    $this->productRepository = $productRepository;
    $this->registry = $registry;
    $this->reviewCollection = $reviewCollection;
    $this->storeManager = $storeManager;
    parent::__construct($context, $data);
}

public function getCollection()
{
    $category = $this->registry->registry('current_category');
    $collection = $category->getProductCollection();

    foreach( $collection as $product ) {

        // this is the method from the magento
        // core function (getReviewsCollection()) mentioned above
        $reviewCollection = $this->reviewCollection->create()
            ->addStoreFilter(
                $this->storeManager->getStore()->getId()
            )->addStatusFilter(
                \Magento\Review\Model\Review::STATUS_APPROVED
            )->addEntityFilter(
                'product',
                $product->getId()
            )->setDateOrder();

        $reviews = $reviewCollection->getItems();

        if( !empty($reviews) ){
            foreach ($reviews as $review){
                // this is where the code breaks
                foreach( $review->getRatingVotes() as $vote ){
                    // do stuff here
                }
            }
        } 
    }
}

Inside the getCollection function I use the same method to retrieve the review collection as in the getReviewsCollection method from the magento core. I can successfully retrieve an array of \Magento\Review\Model\Review objects.

But my code breaks as soon as I try to iterate over the reviews and use the $review->getRatingVotes() method inside the inner most foreach loop. getRatingVotes() returns null and I get an Invalid argument supplied for foreach() exception.

I decided to investigate the getRatingVotes() method but I cannot find where it is defined. I did a search of the whole codebase inside VSCode as well as via grep. The only place where it occurs is inside the .phtml template file of the reviews list.

  • I guess getRatingVotes() is a magic getter function which is not available from within the scope of my block class. My plan was to manually calculate the average rating of a product. Is there a good built-in way to do this, given a product object? – bronkopopovic Mar 18 at 17:29
0

Looks like I tried really hard to do it the hard way.
A simple:

$this->reviewFactory->create()->getEntitySummary($product, $this->storeManager->getStore()->getId());

$summary = $prod->getRatingSummary()->getRatingSummary();

Did the trick!!!

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.