shopware

Shopware pagination using wrong total-property to calculate totalPages in pagination.html.twig


In Shopware I want to implement pagination for reviews on the product detail-page.

To achieve this I extend pagination.html.twig

{% sw_include '@Storefront/storefront/component/pagination.html.twig' with {
    entities: reviews,
    criteria: criteria,
}  %}

Because I wanted to customize the limit of the items per page I made a custom decorator

<?php declare(strict_types=1);

namespace My\App\Decorators;

use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Page\Product\Review\ProductReviewLoader;
use Symfony\Component\HttpFoundation\Request;
use Shopware\Storefront\Page\Product\Review\ReviewLoaderResult;

final class ProductDetailPageReviewPagerDecorator extends ProductReviewLoader
{
    private const LIMIT = 3;

    private ProductReviewLoader $decorated;

    public function __construct(ProductReviewLoader $decorated)
    {
        $this->decorated = $decorated;
    }

    public function load(Request $request, SalesChannelContext $context): ReviewLoaderResult
    {
        $request->attributes->set("limit", $request->get("limit", self::LIMIT));
        return $this->decorated->load($request, $context);
    }
}

The pagination is not showing, the issue is the totalPages variable in pagination.html.twig.

    {% set totalPages = (entities.total / criteria.limit)|round(0, 'ceil') %}

The totalPages is calculated by using entities.total but this contains the value of the amount of LOADED reviews which by definition is equal to or lower then the limit. So totalPages is always 1.

Shopware pdp page dump

There is also a variable totalReviews which does contain the correct amount of totalReviews. So by making the following change:

    {% set totalPages = (entities.totalReviews / criteria.limit)|round(0, 'ceil') %}

it does work. But making changes in the vendor Shopware-core of course is not allowed.

Other disallowed options

  1. I could also make a new component called pdp-pagination.html.twig containing the following code
{% sw_extends '@Storefront/storefront/component/pagination.html.twig' %}

{% block component_pagination_nav %}
    {% set currentPage = ((criteria.offset + 1) / criteria.limit )|round(0, 'ceil') %}
    {% set totalPages = (entities.totalReviews / criteria.limit)|round(0, 'ceil') %}
    {% if totalPages > 1 %}
        <nav aria-label="pagination" class="pagination-nav">
            {% block component_pagination %}
                {% set totalPages = (entities.totalReviews / criteria.limit)|round(0, 'ceil') %}
                {{ parent() }}
            {% endblock %}
        </nav>
    {% endif %}
{% endblock %}

This fixes the issue but is not allowed.

  1. Using reflection - works but is not allowed
    public function load(Request $request, SalesChannelContext $context): ReviewLoaderResult
    {
        $request->attributes->set("limit", $request->get("limit", self::LIMIT));
        $result = $this->decorated->load($request, $context);

        $reflectionReviewLoaderResult = new ReflectionClass($result);
        $reviewLoaderResultTotal = $reflectionReviewLoaderResult->getProperty('total');
        $reviewLoaderResultTotal->setAccessible(true);
        $reviewLoaderResultTotal->setValue($result, $result->getTotalReviews());

        return $result;
    }

So how would I fix this?


Solution

  • Use $criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);.

    Source: https://stackoverflow.com/a/76182723/6533037