Pagination
Displaying a reasonable number of records per page has always been a criticalpart of every application and used to cause many headaches for developers.CakePHP eases the burden on the developer by providing a quick, easy way topaginate data.
Pagination in CakePHP is offered by a component in the controller. You then use in your view templates togenerate pagination controls.
To paginate a query we first need to load the PaginatorComponent
:
Once loaded we can paginate an ORM table class or Query
object:
- public function index()
- {
- // Paginate the ORM table.
- $this->set('articles', $this->paginate($this->Articles));
- // Paginate a partially completed query
- $query = $this->Articles->find('published');
- $this->('articles', $this->paginate($query));
- }
Advanced Usage
PaginatorComponent
supports more complex use cases by configuring the $paginate
controller property or as the $settings
argument to paginate()
. Theseconditions service as the basis for you pagination queries. They are augmentedby the sort
, direction
, limit
, and page
parameters passed infrom the URL:
- class ArticlesController extends AppController
- {
- public $paginate = [
- 'limit' => 25,
- 'order' => [
- 'Articles.title' => 'asc'
- ]
- ];
- }
Tip
Default order
options must be defined as an array.
While you can include any of the options supported by such as fields
in your paginationsettings. It is cleaner and simpler to bundle your pagination options intoa Custom Finder Methods. You can use your finder in pagination by using thefinder
option:
- class ArticlesController extends AppController
- {
- public $paginate = [
- 'finder' => 'published',
- ];
- }
- {
- // find articles by tag
- public function tags()
- {
- $tags = $this->request->getParam('pass');
- $customFinderOptions = [
- 'tags' => $tags
- ];
- // We're using the $settings argument to paginate() here.
- // But the same structure could be used in $this->paginate
- //
- // Our custom finder is called findTagged inside ArticlesTable.php
- // which is why we're using `tagged` as the key.
- // Our finder should look like:
- // public function findTagged(Query $query, array $options) {
- $settings = [
- 'finder' => [
- 'tagged' => $customFinderOptions
- ]
- ];
- $articles = $this->paginate($this->Articles, $settings);
- $this->set(compact('articles', 'tags'));
- }
- }
In addition to defining general pagination values, you can define more than oneset of pagination defaults in the controller. The name of each model can be usedas a key in the $paginate
property:
The values of the Articles
and Authors
keys could contain all theproperties that a basic $paginate
array would.
Once you have used paginate()
to create results. The controller’s requestwill be updated with paging parameters. You can access the pagination metadataat $this->request->getParam('paging')
.
Simple Pagination
By default pagination uses a count()
query to calculate the size of theresult set so that page number links can be rendered. On very large datasetsthis count query can be very expensive. In situations where you only want toshow ‘Next’ and ‘Previous’ links you can use the ‘simple’ paginator which doesnot do a count query:
- public function initialize()
- {
- parent::initialize();
- // Load the paginator component with the simple paginator strategy.
- $this->loadComponent('Paginator', [
- 'paginator' => new \Cake\Datasource\SimplePaginator(),
- ]);
- }
When using the SimplePaginator
you will not be able to generate pagenumbers, counter data, links to the last page, or total record count controls.
If you need to paginate data from another component you may want to use thePaginatorComponent
directly. It features a similar API to the controllermethod:
- $articles = $this->Paginator->paginate($articleTable->find(), $config);
- // Or
The first parameter should be the query object from a find on table object youwish to paginate results from. Optionally, you can pass the table object and letthe query be constructed for you. The second parameter should be the array ofsettings to use for pagination. This array should have the same structure as the$paginate
property on a controller. When paginating a Query
object, the option will be ignored. It is assumed that you are passing inthe query you want paginated.
Paginating Multiple Queries
You can paginate multiple models in a single controller action, using thescope
option both in the controller’s $paginate
property and in thecall to the paginate()
method:
- // Paginate property
- public $paginate = [
- 'Articles' => ['scope' => 'article'],
- 'Tags' => ['scope' => 'tag']
- ];
- // In a controller action
- $articles = $this->paginate($this->Articles, ['scope' => 'article']);
- $tags = $this->paginate($this->Tags, ['scope' => 'tag']);
- $this->set(compact('articles', 'tags'));
- /dashboard?article[page]=1&tag[page]=3
See the section for how to generate scoped HTMLelements and URLs for pagination.
To paginate the same model multiple times within a single controller action youneed to define an alias for the model. See Using the TableLocator foradditional details on how to use the table registry:
Control which Fields Used for Ordering
By default sorting can be done on any non-virtual column a table has. This issometimes undesirable as it allows users to sort on un-indexed columns that canbe expensive to order by. You can set the whitelist of fields that can be sortedusing the sortWhitelist
option. This option is required when you want tosort on any associated data, or computed fields that may be part of yourpagination query:
- public $paginate = [
- 'sortWhitelist' => [
- 'id', 'title', 'Users.username', 'created'
- ]
- ];
Any requests that attempt to sort on fields not in the whitelist will beignored.
The number of results that are fetched per page is exposed to the user as thelimit
parameter. It is generally undesirable to allow users to fetch allrows in a paginated set. The maxLimit
option asserts that no one can setthis limit too high from the outside. By default CakePHP limits the maximumnumber of rows that can be fetched to 100. If this default is not appropriatefor your application, you can adjust it as part of the pagination options, forexample reducing it to 10
:
- public $paginate = [
- // Other keys here.
- 'maxLimit' => 10
- ];
If the request’s limit param is greater than this value, it will be reduced tothe maxLimit
value.
Joining Additional Associations
Additional associations can be loaded to the paginated table by using thecontain
parameter:
- public function index()
- {
- $this->paginate = [
- 'contain' => ['Authors', 'Comments']
- ];
- $this->set('articles', $this->paginate($this->Articles));
- }
Out of Range Page Requests
The PaginatorComponent will throw a NotFoundException
when trying toaccess a non-existent page, i.e. page number requested is greater than totalpage count.
- use Cake\Http\Exception\NotFoundException;
- public function index()
- {
- try {
- $this->paginate();
- } catch (NotFoundException $e) {
- // Do something here like redirecting to first or last page.
- // $this->request->getAttribute('paging') will give you required info.
- }
Check the documentation forhow to create links for pagination navigation.