I have a custom plugin that has an entity certificate
and it lists all the certificates from that entity in the storefront.
The problem: I managed to create the view for listing, and the pagination, but when clicking on the pagination buttons, they don't work or go anywhere.
Maybe I'm doing something wrong here.
- CertificateController.php:
<?php declare(strict_types=1);
namespace Certificate\Storefront\Controller;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
use Shopware\Storefront\Controller\StorefrontController;
use Certificate\Service\ReadingData;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route(defaults={"_routeScope"={"storefront"}})
*/
class CertificateController extends StorefrontController
{
private ReadingData $readingData;
private EntityRepository $certificateReposiitory;
public function __construct(ReadingData $readingData, EntityRepository $certificateReposiitory)
{
$this->readingData = $readingData;
$this->certificateReposiitory = $certificateReposiitory;
}
/**
* @Route("/certificate", name="frontend.certificate.certificate", methods={"GET"})
*/
public function index(Request $request, Context $context): Response
{
$searchQuery = $request->query->get('search', '');
$results = [];
$criteria = new Criteria();
$criteria->setOffset(1);
$criteria->setLimit(25);
$criteria->addSorting(new FieldSorting('name', FieldSorting::ASCENDING));
$result = $this->certificateReposiitory->search($criteria, $context);
$total = $this->certificateReposiitory->search(new Criteria(), $context)->getTotal();
$pages = ceil($total / $criteria->getLimit());
if (!empty($searchQuery)) {
$results = $this->readingData->readData($searchQuery, $context);
} else {
$results = $result->getEntities();
}
return $this->renderStorefront('@Certificate/storefront/page/certificate.html.twig', [
'searchQuery' => $searchQuery,
'results' => $results,
'pages' => $pages,
'currentPage' => $request->query->get('page', 1),
'limit' => $criteria->getLimit(),
'criteria' => $criteria,
'total' => $total
]);
}
}
- src/Resources/views/storefront/page/certificate.html.twig:
{% sw_extends '@Storefront/storefront/base.html.twig' %}
{% block base_content %}
<form action="{{ path('frontend.certificate.certificate') }}" method="GET">
<div class="form-group md-4">
<label for="search">Search:</label>
<input type="text" class="form-control" id="search" name="search" placeholder="Enter your search query"
value="{{ searchQuery|default('') }}">
</div>
<button type="submit" class="btn btn-primary">Search</button>
</form>
{% if searchQuery is not empty or results %}
{% if results %}
<h2>Certificates</h2>
{% else %}
<h2>Search Results:</h2>
{% endif %}
{% if results|length > 0 %}
<div class="row">
{% for certificate in results %}
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ certificate.name }}</h5>
{% if certificate.media is not null %}
<a href="{{ certificate.media.url }}" target="_blank" class="btn btn-secondary">Download</a>
{% else %}
<a href="{{ certificate.fileName }}" target="_blank" class="btn btn-secondary">Download</a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
{% block page_actions_pagination %}
<div class="cms-element-product-listing-actions row justify-content-between">
<div class="col-md-auto">
{% sw_include '@Storefront/storefront/component/pagination.html.twig' with {
prev_link: currentPage > 1 ? path('frontend.certificate.certificate', {page: currentPage - 1, search: searchQuery}) : null,
next_link: currentPage < pages ? path('frontend.certificate.certificate', {page: currentPage + 1, search: searchQuery}) : null,
'currentPage': currentPage,
'total': total,
'limit': limit,
'pages': pages,
'criteria': criteria,
'searchRoute': 'frontend.certificate.index',
'searchQuery': searchQuery
} %}
</div>
</div>
{% endblock %}
{% else %}
<p>No results found for "{{ searchQuery }}".</p>
{% endif %}
{% endif %}
{% endblock %}
The pagination needs to be included inside a form element. You can then use the FormAutoSubmit
plugin to make it submit on changes by adding the data-form-auto-submit
attribute.
<form action="{{ path('frontend.certificate.certificate') }}"
method="get"
data-form-auto-submit="true">
{% sw_include '@Storefront/storefront/component/pagination.html.twig' with {
prev_link: currentPage > 1 ? path('frontend.certificate.certificate', {page: currentPage - 1, search: searchQuery}) : null,
next_link: currentPage < pages ? path('frontend.certificate.certificate', {page: currentPage + 1, search: searchQuery}) : null,
'currentPage': currentPage,
'total': total,
'limit': limit,
'pages': pages,
'criteria': criteria,
'searchRoute': 'frontend.certificate.index',
'searchQuery': searchQuery
} %}
</form>
In your controller you have to use the p
parameter to calculate offset
:
$currentPage = (int) $request->query->get('p', 1);
$limit = 25;
$criteria->setOffset(($currentPage - 1) * $limit);
$criteria->setLimit($limit);
You can also avoid a second search to find the total number of record by setting the total count mode of the criteria, which will cause the total to ignore limit and offset.
$criteria->setTotalCountMode(Criteria::TOTAL_COUNT_MODE_EXACT);
$result = $this->certificateReposiitory->search($criteria, $context);
$total = $result->getTotal();