Pagination
A list of hundreds of articles is not shown in full; it is split into pages. CakePHP has the paginate() controller method and the Paginator template helper for this: the first takes the required portion of records from the database and the second draws links to pages.
In the controller
// src/Controller/ArticlesController.php
public function index(): void
{
$articles = $this->paginate($this->Articles->find());
$this->set(compact('articles'));
}Instead of calling ->all(), the query is passed to paginate(). By default it returns 20 records and reads the page number from the address by itself: /articles?page=2.
Links to pages
Add this to the end of templates/Articles/index.php:
<nav>
<?= $this->Paginator->prev('← Previous') ?>
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next('Next →') ?>
</nav>Page numbers and the "Previous" and "Next" links appear under the list. The foreach loop over $articles stays the same.
Settings
// src/Controller/ArticlesController.php
protected array $paginate = [
'limit' => 10,
'order' => ['Articles.created' => 'DESC'],
];The $paginate property sets the page size and the default order for all actions of the controller. Now a page has ten articles, newest first.
| Setting | What it sets |
|---|---|
limit | Records per page |
maxLimit | The largest limit value that may be passed in the address |
order | The default order |
sortableFields | Columns that sorting is allowed by |
Counter
<p><?= $this->Paginator->counter('Page {{page}} of {{pages}}, articles in total: {{count}}') ?></p>The words in double curly braces are replaced with numbers: "Page 2 of 5, articles in total: 48".
Sorting by a column
<table>
<tr>
<th><?= $this->Paginator->sort('title', 'Title') ?></th>
<th><?= $this->Paginator->sort('created', 'Date') ?></th>
</tr>
</table>A column heading becomes a link of the form /articles?sort=title&direction=asc. The first click sorts in ascending order and the second in descending order; paginate() reads these parameters itself.
Together with conditions
public function index(): void
{
$query = $this->Articles->find()->where(['published' => true]);
$this->set('articles', $this->paginate($query));
}Any query can be passed to paginate(): with conditions, with associations through contain(), with a custom finder.
Common mistake
When a sortableFields list is set, CakePHP silently ignores sorting by columns outside the list; this protects from arbitrary values in the address. When a heading link "does not sort", add the column to the list: 'sortableFields' => ['title', 'created'].