Pagination Adapter
Pagerfanta defines Pagerfanta\Adapter\AdapterInterface which is the abstraction layer for any system to provide data to a Pagerfanta instance to support pagination lists.
The interface requires two methods to be implemented:
getNbResults: Retrieves a count of the total number of items in the list- Generally, an adapter should return a result count of at least 0 as the count will come from either a database result or a
count($foo)type of operation, however, an adapter can optionally validate the count and throw aPagerfanta\Exception\NotValidResultCountExceptionif the count is a negative number
- Generally, an adapter should return a result count of at least 0 as the count will come from either a database result or a
getSlice: Retrieves the list of items in the current page of the paginated list
<?php
namespace Pagerfanta\Adapter;
use Pagerfanta\Exception\NotValidResultCountException;
interface AdapterInterface
{
/**
* Returns the number of results for the list.
*
* @throws NotValidResultCountException if the number of results is less than zero.
*/
public function getNbResults(): int;
/**
* Returns an slice of the results representing the current page of items in the list.
*/
public function getSlice(int $offset, int $length): iterable;
}The AdapterInterface is composed of two smaller interfaces, which describe the capabilities of an adapter separately:
Pagerfanta\Adapter\CountableAdapterInterface: An adapter which can count the total number of items in the list withgetNbResultsPagerfanta\Adapter\OffsetAdapterInterface: An adapter which can retrieve a page of items withgetSlice, using an offset and a length
Cursor Adapters
Pagerfanta defines Pagerfanta\Adapter\CursorAdapterInterface which is the abstraction layer for any system to provide data to a cursor pager.
The interface requires two methods to be implemented:
getSlice: Retrieves the items following (or preceding, based on the direction of the cursor) the given cursor, along with the cursors pointing to the neighboring pages- A null cursor requests the first page
- The items must always be returned in the sort order of the list, regardless of the direction of the cursor
- An adapter can throw a
Pagerfanta\Exception\InvalidCursorExceptionif the cursor is not valid for it, such as when the cursor fields do not match the fields the list is sorted by
supportsBackwardNavigation: Reports whether the adapter can paginate backwards, adapters which cannot should never return a cursor for the previous page
A cursor adapter does not count the total number of items in the list unless it also implements Pagerfanta\Adapter\CountableAdapterInterface.
<?php
namespace Pagerfanta\Adapter;
use Pagerfanta\Cursor\Cursor;
use Pagerfanta\Exception\InvalidCursorException;
interface CursorAdapterInterface
{
/**
* Returns the slice of results following (or preceding, based on the cursor's direction) the given cursor.
*
* @throws InvalidCursorException if the cursor is not valid for this adapter
*/
public function getSlice(?Cursor $cursor, int $limit): CursorSlice;
/**
* Whether this adapter can paginate backwards (i.e. generate a cursor for the previous page).
*/
public function supportsBackwardNavigation(): bool;
}The Pagerfanta\Adapter\CursorSlice returned by getSlice holds the items on the page, and the cursors for the previous page (with the Direction::Previous direction) and the next page (with the Direction::Next direction), which are null when there is no page in that direction.
Detecting Neighboring Pages
To know whether there is another page without counting the results, an adapter generally fetches one more item than the limit and trims the extra item before returning the slice. The CursorSlice::fromLookahead() method implements this approach for adapters which fetch up to $limit + 1 items in the direction of the cursor (in reverse sort order for a cursor with the previous direction), given a callable which creates the cursor pointing to an item.
<?php
use Pagerfanta\Adapter\CursorAdapterInterface;
use Pagerfanta\Adapter\CursorSlice;
use Pagerfanta\Cursor\Cursor;
use Pagerfanta\Cursor\Direction;
final class PostCursorAdapter implements CursorAdapterInterface
{
public function getSlice(?Cursor $cursor, int $limit): CursorSlice
{
// Fetch up to $limit + 1 posts after the cursor, or before it in reverse order for a cursor with the previous direction
$items = $this->fetchPosts($cursor, $limit + 1);
return CursorSlice::fromLookahead(
$items,
$limit,
$cursor,
static fn (Post $post, Direction $direction): Cursor => new Cursor(['id' => $post->id], $direction),
);
}
public function supportsBackwardNavigation(): bool
{
return true;
}
}