Spiral database, ORM and ODM layers support ability to specify limit and offset values based on external pagination object.
Pagination interface is defined using following contract:
interface PaginatorInterface
{
/**
* Get pagination limit value.
*
* @return int
*/
public function getLimit(): int;
/**
* Get calculated offset value.
*
* @return int
*/
public function getOffset(): int;
/**
* Get parameter paginator depends on. Environment specific.
*
* @return null|string
*/
public function getParameter();
}
Classes which are open for pagination must implement PaginatorAwareInterface
:
interface PaginatorAwareInterface
{
/**
* Indication that object has associated paginator.
*
* @return bool
*/
public function hasPaginator(): bool;
/**
* Manually set paginator instance for specific object.
*
* @param PaginatorInterface $paginator
*/
public function setPaginator(PaginatorInterface $paginator);
/**
* Get paginator for the current selection. Paginate method should be already called or
* paginator must be previously set.
*
* Potentially to be renamed to getPaginator method since this method does not create paginator
* automatically.
*
* @see paginate()
*
* @return PaginatorInterface
*
* @throws PaginationException
*/
public function getPaginator(): PaginatorInterface;
}
Default pagination implementation can be received using Spiral\Pagination\Paginator
class, we can use it directly in our code:
$paginator = new Paginator(10);
$selection = $this->db->users->select('name', 'email');
$selection->setPaginator($paginator->withPage(2));
In most of cases you want to associate paginator with specific query page parameter, you can either do
it manually or use PaginatorsInterface
which is based on active request scope:
$paginator = $this->paginators->createPaginator('query-parameter', 10);
$selection = $this->db->users->select('name', 'email')->paginate();
$selection->setPaginator($paginator);
In addition, DBAL, ORM and ODM components include shortcut method which will initiate paginator automatically:
//Default page parameter is "page"
$selection = $this->db->users->select('name', 'email')->paginate(10, 'query-parameter');
Spiral does not include rendering logic into pagination class itself, you have to render page range by youself.
Luckily, if you have installed spiral/toolkit
you can use widget "spiral:paginator" for such purposes. Widget can accept both PaginatorInterface
and PaginatorAwareInterface
:
protected function indexAction()
{
return $this->views->render('users/list', [
'list' => $this->db->users->select('name','email')->paginate(2)
]);
}
View source:
<extends:spiral:layouts.blank page="Users list"/>
<block:content>
<table>
<thead>
<tr>
<th>[[Name:]]</th>
<th>[[Email:]]</th>
</tr>
</thead>
<tbody>
<?php
/**
* @var array[]|\Spiral\Pagination\PaginableInterface
*/
foreach ($list as $user) {
?>
<tr>
<td><?= e($user['name']) ?></td>
<td><?= e($user['email']) ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<spiral:paginator source="<?= $list ?>"/>
</block:content>
Result:
You can create your own project/module paginators using Stempler virtual tags (widgets).
You can create your own pagination responses by talking to Paginator
class directly:
class ResponseWrapper implements JsonSerializable
{
protected $select;
public function __construct(PaginatorAwareInterface $select)
{
if (!$select->hasPaginator()) {
throw new RuntimeException('Selection must be paginated');
}
if ($select->getPaginator() instanceof PagedIterface) {
throw new RuntimeException('PagedIterface compatible paginator is required');
}
$this->select = $select;
}
public function jsonSerialize()
{
$paginator = $this->select->getPaginator();
return [
'result' => $this->select,
'pagination' => [
'count' => $paginator->count(),
'page' => $paginator->getPage(),
'nextPage' => $paginator->nextPage(),
'previousPage' => $paginator->previousPage()
]
];
}
}
protected function indexAction()
{
$selection = $this->dbal->db()->users->select('name', 'email')->paginate(2);
return new \ResponseWrapper($selection);
}
And our result will look like:
{
"result": [
{
"name": "Anton",
"email": "anton@email.com"
},
{
"name": "John",
"email": "john@email.com"
}
],
"pagination": {
"count": 5,
"page": 1,
"nextPage": 2,
"previousPage": false
}
}