Pagination Caching With CakePHP

Pagination Caching With CakePHP

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',
	));

Posted by VoiDeT

Categorised under CakePHP
Bookmark the permalink or leave a trackback.

12 Comments

  1. Thanks Bigtime!!! I’ve been searching a solution to cache paginated queries! This seems to work great!

    February 25, 2010 @ 1:56 pm
  2. anagram

    it doesn’t work on my app … it’s broken when a pagination use a containable

    any workaround for this issue? Thx

    March 10, 2010 @ 1:39 am
  3. VoiDeT

    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.

    March 10, 2010 @ 9:28 am
  4. yusuf

    i m also have used this to cache the pagination (thanks for sollution :) ), but i am get a problem with $paginator (prev/next),

    March 30, 2010 @ 7:47 pm
  5. daniel

    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.

    April 10, 2010 @ 2:07 am
  6. VoiDeT

    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.

    April 10, 2010 @ 11:00 am
  7. daniel

    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.

    April 10, 2010 @ 6:08 pm
  8. 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.

    May 20, 2010 @ 12:10 am
  9. Floris

    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.

    May 25, 2010 @ 11:28 pm
  10. i m also have used this to cache the pagination (thanks for sollution :) ), but i am get a problem with $paginator (prev/next),

    June 23, 2010 @ 11:53 pm
  11. Great tutorial, just one question… How do I reset the cache using an afterSave method?

    August 24, 2010 @ 5:53 pm
  12. VoiDeT

    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 :)

    August 24, 2010 @ 9:12 pm

2 Trackbacks

  1. [...] Pagination Caching With CakePHP [...]

  2. By CakePHP & Caching Until a Future Post • Jotlab on March 23, 2010 at 1:36 pm

    [...] 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 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

or