Basic Pagination Overview (1.2)
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.
You do not need to do anything special in your Model
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.
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.
Yes, it is that simple. You might say that was "Cake".
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
Download code
You can use images for your prev and next links. You have to use the escape option.
Download code
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
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
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
Comment
1 Correction
Comment
2 reply Correction
Comment
3 It doesnt work
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
Comment
4 reply It doesnt work
Comment
5 very cool
Comment
6 How to limit the fields..
Comment
7 How to add additional filters
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!
Comment
8 Limiting Results...
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.
Comment
9 Reply how to limit the fields
it's very easy, in controller:
var $paginate = array('fields'=>array('Customer.name', 'Customer.store'));
Comment
10 paginate() function
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?
Comment
11 solved paginate() function
Sorry forget this. I was using 1.1, apologies for dragging this post up
Comment
12 Thank you
Comment
13 (Un)binding models before pagination
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);
}
?>
Comment
14 Paginate with Group By columns
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!
Comment
15 Indicator showing which column is sorted
Comment
16 prev and next with two args now
$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'=> ... ?>
Comment
17 Dynamic parameters for pagination
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:
<?phpecho $paginator->sort('Price', 'price', array('url' => array('brand:Sony')));
?>