Basic Pagination Overview (1.2)

By Rob Conner (rtconner)
Just a basic introduction to the wonderful abilities of pagination in Cake 1.2. Gives an overview of how to use pagination to do some very complex things with very little code.
Pagination in Cake 1.2 is very simple to set up and use. There is not much to it. I'll just walk you through step by step getting a basic table with pagination going. From there its on you to explore the more advanced options that exist.

A Quick Walk Through

For this example we'll use a Customer Model. So we'll be displaying a list of customers and sorting them and paging through them.

You do not need to do anything special in your Model

Model Class:

Download code <?php 
class Customer extends AppModel {
  
    var 
$name "Customer";
}
?>

In your controller just add the $paginate variable. It tells the system to start and page 1, and show 15 entries per page. You will call the paginate function from the controller to generate the data list.

Controller Class:

Download code <?php 
class CustomersController extends AppController {

    var 
$name 'Customers';

    var 
$paginate = array('limit' => 15'page' => 1);

    function 
display() {
        
$this->set('customers'$this->paginate('Customer'));
    }
}
?>

And lastly in your view you will wants to use the $paginator to display your data. You view will look something like this. This will be the file /views/customers/display.ctp.

View Template:

Download code Showing Page <?php echo $paginator->counter(); ?>
<table>
    <tr>
        <th><?php echo $paginator->sort('Customer Name''name');?></th>
        <th><?php echo $paginator->sort('Store Location''store');?></th>
    </tr>
<?php foreach($customers as $customer): ?>
    <tr>
        <td><?php echo $customer['Customer']['name']; ?></td>
        <td><?php echo $customer['Customer']['store']; ?></td>
    </tr>
<?php endforeach; ?>
</table>
<?php echo $paginator->prev(); ?>
<?php 
echo $paginator->numbers(); ?>
<?php 
echo $paginator->next(); ?>


Yes, it is that simple. You might say that was "Cake".

Further Reading

There are two parts to pagination with CakePHP. The paginate function within the controller and the $paginator helper within the view. All of the options for these can be found in the 1.2 API documentation.

The paginate function is used to define your data set. You can pass in parameters to screen out certain data, perhaps only display customers from a certain store. This function is assisted by the $paginate variable in the controller which has a few options such as rows per page and default sort order.

The paginator helper does a great job of supporting Ajax pagination. Information is available in the API, but more information should come in a later tutorial on advanced pagination abilities. For now, the only real good tip I have is that you have to always use arrays when passing in custom urls.

You paginator Ajax links might look like this:
Download code <?php echo 
$paginator->sort('Article Name''name', array('url'=>
            array(
'controller'=>'Articles''action'=>'index'),
            
'update'=>'ArticleListTable')); ?>
But like I said there is a lot to this. Ajax and Url handling will need a tutorial of its own.

Tips & Hints

To set a default sort order use the $paginate variable like this:
Download code // in your Controller
var $paginate = array('order'=>array('name' => 'desc'));

You can use images for your prev and next links. You have to use the escape option.
Download code <?php echo $paginator->link('<img src="myimage.jpg">', array('escape'=>false))?>
It is possible to have more than one paginator within a controller and view. You just have to specify the Model that you are going to use everywhere.
Download code // this goes in the Controller
var $paginate = array('Article' => array('limit'=>25), 'Customer'=>array('limit'=>10));

<!-- these will go in the view -->
<?php echo $paginator->sort('Article Sort''id', array('model'=>'Article')); ?>
<?php 
echo $paginator->sort('Customer Name''name', array('model'=>'Customer')); ?>

The counter function of the $paginator helper is very powerful, giving you access to all kinds of data that you might want to display. Thanks to Gwoo for this lovely little piece of code.
Download code <?php 
echo $paginator->counter(array(
        
'format' => 'Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%'
)); 
?>

 

Comments 444

CakePHP Team Comments Author Comments
 

Comment

1 Correction

PaginatorHelper only supports arrays for building URLs. This is by design.
Posted Jun 13, 2007 by Nate
 

Comment

2 reply Correction

PaginatorHelper only supports arrays for building URLs. This is by design. Aha. Thanks.. I wasn't aware it was by design. I'll modify that line to correct that information.
Posted Jun 13, 2007 by Rob Conner
 

Comment

3 It doesnt work

It works great except when i use another model.. for example when i have in my article controller:

var $uses = array('Tag');

Then i get this error:

Notice (8): Undefined variable: paginator [CORE\app\views\articles\index.ctp, line 36]

Fatal error: Call to a member function prev() on a non-object in C:\wamp\www\mech7\app\views\articles\index.ctp on line 36
Posted Jun 17, 2007 by chris
 

Comment

4 reply It doesnt work

See the Tips section on using multiple Models. If you are using a Model besides the default for a controller, you have to specify the name of the Model in both the paginate variable, function, and the $paginator functions.
Posted Jun 18, 2007 by Rob Conner
 

Comment

5 very cool

Thank you for posting this very helpful :-). My only gripe is that when the "<< Previous" text is shown the link is being underlined between it and the 1st page text, there should be a gap.
Posted Jun 20, 2007 by Phil McGuire
 

Comment

6 How to limit the fields..

I have setup several HABTM but when i use paginate i get a huge number of queries, is it possible to define custom fields (columns) in paginate?
Posted Jun 27, 2007 by chris
 

Comment

7 How to add additional filters

Hi. I had a question, now answered, that I will ask and answer here. (Actually, two, related, questions)

1) How do you apply additional filters to pagination?
- The pagination seems to only work on all members of a model.

2) How do you maintain the URL params in the "next" and "prev" links?
- The "page:X" and "sort:XXX" params seem to override the controller method params from the URL.

Answers
1) Pass in an array of "WHERE" (as in "SQL WHERE") conditions, for example (using this tuts model):

$this->set('customers', $this->paginate('Customer', array("`Customer`.`id` in (1,2,3,4,5)));

2) Pass in an option "url" as an array into the next(), prev(), and numbers() helper functions:

e.g. prev(array('url'=>'S/J')); ?>
(an example assuming that the display() function filters on first initial of last name/first name or something like that)

I hope this is helpful, and, more importantly, correct!
Posted Aug 30, 2007 by Jeffrey Silverman
 

Comment

8 Limiting Results...

I'd also like to know how you can limit the results...paginate() seems to just be a blind findAll() -- it's simply pulling WAY too much data, especially with associated models.

Anyway to limit the fields? Also maybe the recursiveness?

...well I tried $this->paginate['fields'] = array('Model.column', 'Model.column'); and it worked... So there's how you limit fields, but that's just for the model at hand.

Still trying to figure how to limit the associated model fields...you can't put in Model1.column, Model2.column in that array for whatever reason.

Though adding $this->Model->recursive = -1; before the $this->paginate['fields'] does do the trick...I'd rather not make several find calls after paginate. Guess it's better than having too much info though.
Posted Oct 6, 2007 by Tom Maiaroto
 

Comment

9 Reply how to limit the fields

I have setup several HABTM but when i use paginate i get a huge number of queries, is it possible to define custom fields (columns) in paginate?
it's very easy, in controller:

var $paginate = array('fields'=>array('Customer.name', 'Customer.store'));
Posted Oct 25, 2007 by xmihu
 

Comment

10 paginate() function

I've been getting into cake over the last couple of weeks and wanted to add pagination to a project of mine. I've followed this guide on 1.2 but I get an undefined method calling paginate() from the controller.

I've looked through the API but couldn't find any reference to paginate. I also checked if it's a helper I should be including.

I'm stumped on this, and it looked so easy :P Any ideas?
Posted Jan 8, 2008 by Matt Harrison
 

Comment

11 solved paginate() function

I'm stumped on this, and it looked so easy :P Any ideas?
Sorry forget this. I was using 1.1, apologies for dragging this post up
Posted Jan 8, 2008 by Matt Harrison
 

Comment

12 Thank you

Extremely helpful lesson, thanks a bunch!
Posted Jan 29, 2008 by Matt Huggins
 

Comment

13 (Un)binding models before pagination

I had a special scenario where I needed to bind models during the pagination process. Fortunately, a custom paginate() and paginateCount() function can be specified in your model class. If you need to bind or unbind (or really perform any other special processing) prior to your pagination call, just add something like the following to your model.

Model Class:

<?php 
function paginateCount($conditions null$recursive null) {
    
$this->bindModel(array(
        
'hasOne' => array(
            
'Gender' => array(
                
'className'  => 'Gender',
                
'foreignKey' => 'profile_id',
                
'conditions' => 'Gender.gender_id = '.$conditions['Gender.id'],
            ),
        ),
    ));
    return 
$this->findCount($conditions$recursive);
}

function 
paginate($conditions null$fields null$order null$limit null$page 1$recursive null) {
    
$this->bindModel(array(
        
'hasOne' => array(
            
'Gender' => array(
                
'className'  => 'Gender',
                
'foreignKey' => 'profile_id',
                
'conditions' => 'Gender.gender_id = '.$conditions['Gender.id'],
            ),
        ),
    ));
    return 
$this->findAll($conditions$fields$order$limit$page$recursive);
}
?>
Posted Jan 29, 2008 by Matt Huggins
 

Comment

14 Paginate with Group By columns

I have this scenario where I have two tables, 'users' and 'articles' table. Each user has many articles and I need to retrieve all users together with submitted article count and be able to paginate the result.

I tried this using paginate method as given in the tutorial but I don't know where to put the GROUP BY clause within this method.

What I can insert is the count articles inside the 'fields' array of paginate as shown below:

$this->paginate['Article'] = array('fields' => array('SUM(IF(Article.status=\'Approved\',1,0)) as count'));

$this->set('authors', $this->paginate('Article'));


But this statement has an SQL Error since it is missing the GROUP By clause. What I also need to come-up is the query similar to the statement below and be able to paginate it:

SELECT
User.id,
User.first_name,
User.last_name,
SUM(IF(Article.status='Approved',1,0)) as count
FROM
articles as Article
LEFT JOIN users as User on Article.user_id = User.id
GROUP BY
Article.user_id ORDER BY count DESC




Any comments, suggestions and or good solution is highly appreciated.


Thank you very much for helping!

Posted Jan 29, 2008 by Wendell Malpas
 

Comment

15 Indicator showing which column is sorted

I find it very annoying that there is no indicator of which column is being sorted on. I was able to hack in a few lines into the paginator helper that just add html ↑ and ↓ into the title cells. It is a little more painful than I'd like because I have to fight with an htmlspecialchars() call lurking in link(). And it probably should be driven off some $option value passed in to sort(). Anyway, is this something others would like to see? If so, where is the best place to submit patches/suggestions?
Posted Mar 19, 2008 by Joe Pruett
 

Comment

16 prev and next with two args now

2) Pass in an option "url" as an array into the next(), prev(), and numbers() helper functions:

e.g. prev(array('url'=>'S/J')); ?>
(an example assuming that the display() function filters on first initial of last name/first name or something like that)

$paginator->prev() now accepts the first field as being a string text, so you'll have to do lit like so:

<?php echo $paginator->prev('<< Previous', array('url'=> ... ?>
Posted Apr 24, 2008 by Elmo
 

Comment

17 Dynamic parameters for pagination

If anyone would like to try dynamic pagination try this

Controller Class:

<?php 
$conditions 
array_merge($conditions, array('Manufacturer.name' => $this->params['named']['brand']));
$this->paginate array_merge($this->paginate, array('conditions' => $conditions));
?>

Model Class:

<?php 
echo $paginator->sort('Price''price', array('url' => array('brand:Sony')));
?>
Posted Apr 30, 2008 by Tim
 

Question

18 paginator images

hello, i've been trying to use images for the prev and next links but no success . I tried your code but it doesnt work. I get a regular link with the actual image tag text. Please help ! thanks
Posted Jul 29, 2008 by alejjak
 

Comment

19 Very simple

hello, i've been trying to use images for the prev and next links but no success . I tried your code but it doesnt work. I get a regular link with the actual image tag text. Please help ! thanks
you have to use something like this:

<?php echo $paginator->next($html->image('design/next.gif', array('border'=>'0')), array('escape'=>false));?>

where design can be replaced with whateverfolder you are having in the design or not to be placed at all if you save your images in img folder.
Posted Aug 8, 2008 by Mihai Puscasu
 

Question

20 Sorting for another modal

Hi,

First of all thanks for this nice tutorial.
I am trying to sorting on HABTM association but not getting success.

Tables:
1) problems(id, title)
2) users(id, username)
3) problems_users(problem_id, user_id)

Relation ship between problems and users table is HABTM

I am successfully able to sort on problem title column using
sort('Title', 'Problem.title'); ?>
but when I am trying to sort on username using
First :
sort('Username', 'User.username', array('modal' => 'User')) ?> its generating errors:
Warning (512): SQL Error: 1054: Unknown column 'User.username'

Second :
sort('Username', 'username', array('modal' => 'User')) ?> its not giving any error but not sorting data:

Please tell me how can I sort a column (username) based on above HABTM associations?
Thanks!!
Posted Dec 23, 2008 by bookme
 

Question

21 How to do LIKE with this pagination helper?

Hi,

I wanna know if is possible to do the mysql LIKE with this helper.

Example:
SELECT * FROM nome_tbl WHERE key_col LIKE "Patrick%";

How can i do this?

Thanks por any help!
Posted Dec 27, 2008 by Danilo
 

Comment

22 Remove "page:" from URL

Posted Jul 3, 2009 by Christian Strang