Basic Pagination Overview (1.2)

By Rob Conner aka "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 Wed, Jun 13th 2007, 09:57 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 Wed, Jun 13th 2007, 12:31 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 [COREappviewsarticlesindex.ctp, line 36]


Fatal error: Call to a member function prev() on a non-object in C:wampwwwmech7appviewsarticlesindex.ctp on line 36
posted Sun, Jun 17th 2007, 10:48 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 Mon, Jun 18th 2007, 10:36 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 Wed, Jun 20th 2007, 17:02 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 Wed, Jun 27th 2007, 13:57 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. <?php echo $paginator->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 Thu, Aug 30th 2007, 13:33 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 Sat, Oct 6th 2007, 23:02 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 Thu, Oct 25th 2007, 00:04 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 Tue, Jan 8th 2008, 05:43 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 Tue, Jan 8th 2008, 05:55 by Matt Harrison

Comment

12 Thank you

Extremely helpful lesson, thanks a bunch!
posted Tue, Jan 29th 2008, 15:33 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 Tue, Jan 29th 2008, 15:38 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 Tue, Jan 29th 2008, 23:58 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 &uarr; and &darr; 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 Wed, Mar 19th 2008, 17:01 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. <?php echo $paginator->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 Thu, Apr 24th 2008, 00:59 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 Wed, Apr 30th 2008, 02:30 by Tim

Login to Submit a Comment