Last active
June 21, 2024 07:19
-
-
Save Naskalin/6306172b8081813ea213099a4d16019a to your computer and use it in GitHub Desktop.
Simple Doctrine Paginator and example usage for Symfony. Простейшая постраничная навигация в Symfony.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Controller; | |
use App\Utils\Paginator; | |
use Doctrine\ORM\EntityManagerInterface; | |
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
class PostController extends AbstractController | |
{ | |
public function index(Request $request, Paginator $paginator, EntityManagerInterface $em): Response | |
{ | |
// Query or Query Builder | |
// NOT RESULTS! | |
$query = $em->getRepository(Post::class)->findActivePostsQuery(); | |
$paginator->paginate($query, $request->query->getInt('page', 1)); | |
return $this->render('index.html.twig', [ | |
'paginator' => $paginator, | |
]); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% for post in paginator.items %} | |
{{ post.title }} | |
{% endfor %} | |
{% include 'paginator.html.twig' %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Utils; | |
use Doctrine\ORM\Query; | |
use Doctrine\ORM\QueryBuilder; | |
use Doctrine\ORM\Tools\Pagination\Paginator as OrmPaginator; | |
class Paginator | |
{ | |
/** | |
* @var integer | |
*/ | |
private $total; | |
/** | |
* @var integer | |
*/ | |
private $lastPage; | |
private $items; | |
/** | |
* @param QueryBuilder|Query $query | |
* @param int $page | |
* @param int $limit | |
* @return Paginator | |
*/ | |
public function paginate($query, int $page = 1, int $limit = 10): Paginator | |
{ | |
$paginator = new OrmPaginator($query); | |
$paginator | |
->getQuery() | |
->setFirstResult($limit * ($page - 1)) | |
->setMaxResults($limit); | |
$this->total = $paginator->count(); | |
$this->lastPage = (int) ceil($paginator->count() / $paginator->getQuery()->getMaxResults()); | |
$this->items = $paginator; | |
return $this; | |
} | |
public function getTotal(): int | |
{ | |
return $this->total; | |
} | |
public function getLastPage(): int | |
{ | |
return $this->lastPage; | |
} | |
public function getItems() | |
{ | |
return $this->items; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% set _currentPage = app.request.query.get('page') ?: 1 %} | |
{% set _currentRoute = app.request.attributes.get('_route') %} | |
{% set _lastPage = paginator.lastPage %} | |
{% set _currentParams = app.request.query.all|merge(app.request.attributes.get('_route_params')) %} | |
{% if paginator.lastPage > 1 %} | |
<nav> | |
<ul class="pagination justify-content-center"> | |
<li class="page-item{{ _currentPage <= 1 ? ' disabled' : '' }}"> | |
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: _currentPage - 1})) }}" aria-label="Previous"> | |
« Назад | |
</a> | |
</li> | |
{% for i in 1..paginator.lastPage %} | |
<li class="page-item {% if i == _currentPage %}active{% endif %}"> | |
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: i})) }}">{{ i }}</a> | |
</li> | |
{% endfor %} | |
<li class="page-item {{ _currentPage >= paginator.lastPage ? ' disabled' : '' }}"> | |
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: _currentPage + 1})) }}" aria-label="Next"> | |
Далее » | |
</a> | |
</li> | |
</ul> | |
</nav> | |
{% endif %} |
I've got an 'Call to a member function setFirstResult() on array'. Does anybody know where this comes from?
You must have the QUERY returned in the repository, not the result!
$paginator = new OrmPaginator($query);
In the paginator template, you list all the pages as separate links. In case of 100< pages it will be a huge UI problem. Here's an updated version to display only 5 links in the pager:
paginator.html.twig
{% set _currentPage = app.request.query.get('page') ?: 1 %}
{% set _currentRoute = app.request.attributes.get('_route') %}
{% set _lastPage = paginator.lastPage %}
{% set _currentParams = app.request.query.all|merge(app.request.attributes.get('_route_params')) %}
{% if paginator.lastPage > 1 %}
<nav>
<ul class="pagination justify-content-center">
<li class="page-item{{ _currentPage <= 1 ? ' disabled' : '' }}">
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: _currentPage - 1})) }}" aria-label="Previous">
« {{ "Previous"|trans }}
</a>
</li>
{% set startPage = max(1, _currentPage - 2) %}
{% set endPage = min(_lastPage, startPage + 4) %}
{% if startPage > 1 %}
<li class="page-item">
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: 1})) }}">1</a>
</li>
{% if startPage > 2 %}
<li class="page-item disabled">
<span class="page-link">...</span>
</li>
{% endif %}
{% endif %}
{% for i in startPage..endPage %}
<li class="page-item {% if i == _currentPage %}active{% endif %}">
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: i})) }}">{{ i }}</a>
</li>
{% endfor %}
{% if endPage < _lastPage %}
{% if endPage < _lastPage - 1 %}
<li class="page-item disabled">
<span class="page-link">...</span>
</li>
{% endif %}
<li class="page-item">
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: _lastPage})) }}">{{ _lastPage }}</a>
</li>
{% endif %}
<li class="page-item {{ _currentPage >= paginator.lastPage ? ' disabled' : '' }}">
<a class="page-link" href="{{ path(_currentRoute, _currentParams|merge({page: _currentPage + 1})) }}" aria-label="Next">
{{ "Next"|trans }} »
</a>
</li>
</ul>
</nav>
{% endif %}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you!