My Ride
Started: Thursday 20th June 2013 7:06am
Distance: 13.36km
Duration: 00:30:30
Rest Time: 00:13:55
Climb: 100m
Max Speed: 56.52kmph
Average Speed: 26.29kmphInstagrams
-
Recent Posts
Recent Comments
Archives
- February 2013
- December 2012
- September 2012
- July 2012
- January 2012
- September 2011
- August 2011
- February 2011
- January 2011
- November 2010
- October 2010
- August 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
Categories
Meta
Pagination Caching With CakePHP
February 9, 2010,
5,674 views
A site i was working with was using pagination quite extensively with lots of records and associations. This was producing unnecessary high load on the database and wait times on the production site. Caching had to be done. Unlike normal returned data from finds etc. Paginated data can not be cached as easily, as the paginate method needs to be called to generate the pagination numbers etc. So what was done was to do a custom pagination query with cache built in. So in your app_model.php file add in:
function paginate ($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array()) {
$args = func_get_args();
$uniqueCacheId = '';
foreach ($args as $arg) {
$uniqueCacheId .= serialize($arg);
}
if (!empty($extra['contain'])) {
$contain = $extra['contain'];
}
$uniqueCacheId = md5($uniqueCacheId);
$pagination = Cache::read('pagination-'.$this->alias.'-'.$uniqueCacheId, 'paginate_cache');
if (empty($pagination)) {
$pagination = $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'group', 'contain'));
Cache::write('pagination-'.$this->alias.'-'.$uniqueCacheId, $pagination, 'paginate_cache');
}
return $pagination;
}
function paginateCount ($conditions = null, $recursive = 0, $extra = array()) {
$args = func_get_args();
$uniqueCacheId = '';
foreach ($args as $arg) {
$uniqueCacheId .= serialize($arg);
}
$uniqueCacheId = md5($uniqueCacheId);
if (!empty($extra['contain'])) {
$contain = $extra['contain'];
}
$paginationcount = Cache::read('paginationcount-'.$this->alias.'-'.$uniqueCacheId, 'paginate_cache');
if (empty($paginationcount)) {
$paginationcount = $this->find('count', compact('conditions', 'contain', 'recursive'));
Cache::write('paginationcount-'.$this->alias.'-'.$uniqueCacheId, $paginationcount, 'paginate_cache');
}
return $paginationcount;
}
This will then take over from any paginate calls and generate a cached version of the dataset for the paginated items and the pagination controls, unique to each page and query set. I am in the process of trying to convert this over to a behaviour, will post up if i get a chance to complete it.
Of course you need to specify the caching rule in core.php, something like:
Cache::config('paginate_cache', array(
'engine' => 'File',
'path' => CACHE .'sql'. DS,
'serialize' => true,
'duration' => '+1 hour',
));






20 Comments
Thanks Bigtime!!! I’ve been searching a solution to cache paginated queries! This seems to work great!
it doesn’t work on my app … it’s broken when a pagination use a containable
any workaround for this issue? Thx
What exactly is broken?
I’ve used this on my apps and the pagination caches fine with contains, as you can see it is included in the finds. What you might have to do is included the extra array into the unique cache id, but i’d be surprised if you’re getting conflicting caches.
Anagram please explain what is going on.
i m also have used this to cache the pagination (thanks for sollution
), but i am get a problem with $paginator (prev/next),
thanks a lot for the code.
just one question: how can I temporarily disable the pagination-caching?
I got some views in the backend where I need fresh data.
Hey Daniel,
I would simply use the extras parameter or add another parameter that would accept a cache disabled test, then i would just use that to turn the cache off or on in the method.
Let me know if you need help to achieve this and i can post a modified version.
Hi,
thanks for the answer. That’s exactly what I did yesterday and it works perfectly.
My problem was that I first tried to put the parameter in the paginate-call and not in the controllers paginate variable.
Hi,
thanks for the answer. That’s exactly what I did yesterday and it works perfectly.
My problem was that I first tried to put the parameter in the paginate-call and not in the controllers paginate variable.
To make sure the custom paginate function also works with Contain:
On line 13; remove ‘recursive’.
When using Containable, you most likely defined $recursive = -1; in your AppModel. The function compact on line 13 uses this variable, wich would mean, recursive is passed with the find function on line 13 and there fore, you explicitly ask for no recursion.
i m also have used this to cache the pagination (thanks for sollution
), but i am get a problem with $paginator (prev/next),
Great tutorial, just one question… How do I reset the cache using an afterSave method?
You can use Cache::delete(‘paginate_cache_unique_id’); in your afterSave() method to clear out the cache for the pagination. Just change the key to whatever you used to generate your pagination cache with. Or if you want to flush all cache for pagination then you can use the Cache::clear(expiration_check, config_name) method
We often use the ‘joins’ parameter in our find options. If you want those to be used in the code above you need to add to each function:
if(!empty($extra['joins'])){
$joins = $extra['joins'];
}
Just after the section checking that $extra['contain'] is not empty and then add the ‘joins’ to the find like so:
$paginationcount = $this->find('count', compact('conditions', 'contain', 'recursive', 'joins'));
and:
$pagination = $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'group', 'contain', 'joins'));
Great article, keep it up.
Сould you please post a code for afterSave() method to clear out pagination cache?
We should use Cache::delete(‘paginate_cache_unique_id’);
But I can’t find out how to get the value for paginate_cache_id. Cos it’s dynamic. Any ideas on solving this?
And one more question on temporarily disabling the pagination-caching.
I would simply use the extras parameter or add another parameter that would accept a cache disabled test, then i would just use that to turn the cache off or on in the method.
Let me know if you need help to achieve this and i can post a modified version.
Could you post it please? Can’t find out how to add this extra paramater from controller.
$this->paginate('Post.Comment', array('Post.id'=>$id));Where should I call for “no caching mode”?You, sir, are an absolute pro!!
This is one of those simple things that ‘just works’, but helps so much with performance.
Did you ever succeed in turning this into a behaviour?
Hey Ollie!
Thanks for the comments and great idea. I will look into moving this into a behaviour. But AppModel is pretty easy as it stands! I will update this page when I do some enhancements, also keep an eye on my GitHub page.
Hi there,
How to fix this?
the code still not works with “containable” on my site. I have the 3 models: A,B,C. A belongs to B ,B belongs to C. It works great when paginate A with some B fields but when I need query some fields from C, it return nothing
Just for the record, it would be impossible to turn this into a behavior because the Controller class does a “method_exists” on the object (usually a Model) that is being paginated. Since behaviors do not open classes as in rails, you would never get this to occur.
The proper way would likely be to override the AppController::paginate() method, or even to separate Pagination into it’s own component, and then being able to set model/behavior callbacks from there.
This causes issue with virtual field. Any idea to solve?
Compatibility Cake 2.0 : just add “public” before the functions
Thanks
2 Trackbacks
[...] Pagination Caching With CakePHP [...]
[...] for all find, pagination and pagination count methods with CakePHP. You can find a post on this here. The cache was expiring after every hour, however we failed to realise something. Our CMS system [...]