Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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.

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.

SettingWhat it sets
limitRecords per page
maxLimitThe largest limit value that may be passed in the address
orderThe default order
sortableFieldsColumns 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'].

Thanks for reading!

Donate to the site — we work hard for you.