THIS CONTENT IS OUT OF DATE! IF YOU’RE USING CAKE 2, YOU SHOULDN’T READ THIS.
If you use CakePHP’s caching system but don’t like having to wrap you calls to Model::find() in if statements (“if cache result found… else…”) then this little quick tip is for you. Basically, we’re just going to put a slightly modified version of Model::find() in AppModel. Our new find() method will check for the existence of a ‘cache’ argument in the options array. Then, the function will either grab the query results from the cache or run a DB query, depending on what’s passed in the ‘cache’ argument.
A couple of notes:
- Automatic caching only occurs if debug is set to 0.
- The updated Model::find() function also implements Matt Curry’s version of custom find methods.
- After writing this code a few months ago, I came across another implementation of the same idea on End Your If. The two methods are pretty similar, but we came to the results independently. Must mean it’s a pretty good system.
We’re putting two methods into AppModel: find() and __getCachedResults(), a helper function. You can download the latest version of this code at my GitHub repository, or grab it from the bottom of this post.
Usage is simple:
- Whenever you want to cache a Model::find() result, pass ‘cache’ as one of the method’s arguments. Pass it as either a string or an array.
- string: the name used to generate the cache key, which takes the format: model_alias_cache_key
- array: two valid arguments: ‘name’, used as above, and ‘config’, optionally used to pass the name of the cache config to use. ‘default’ is used if not otherwise specified.
- And that’s it! Enjoy the speed benefits, but use caching carefully. Pay attention to your cache results; only cache stuff that makes sense (for example, only cache user-specific stuff if you specify the user ID in the cache name).
The code:
<?php
class AppModel extends Model {
/**
* Adds support for custom find methods (__findXX) and automatic caching.
* Automatic caching will kick in when 'cache' is passed in the $options
* array.
*
* If 'cache' is a string, then it will be used to generate the
* cache name, which takes the format model_alias_cache_name.
*
* If 'cache' is an array, then two arguments are valid: 'name', required,
* and 'config', optional. 'name' is used as above, while 'config'
* determines the cache configuration to use - 'default' if not specified.
*/
function find($type, $options = array()) {
$results = $this->_getCachedResults($options);
if (!$results) {
$method = null;
if (is_string($type)) {
$method = sprintf('__find%s', Inflector::camelize($type));
}
if ($method && method_exists($this, $method)) {
$results = $this->{$method}($options);
} else {
$args = func_get_args();
$results = call_user_func_array(array('parent', 'find'), $args);
}
if ($this->useCache) {
Cache::write($this->cacheName, $results, $this->cacheConfig);
}
}
return $results;
}
function _getCachedResults($options) {
$this->useCache = true;
if (Configure::read('debug') > 0 || !is_array($options) || !isset($options['cache']) || $options['cache'] == false) {
$this->useCache = false;
return false;
}
if (is_string($options['cache'])) {
$this->cacheName = $this->alias . '_' . $options['cache'];
} else {
if (!isset($options['cache']['name'])) {
return false;
}
$this->cacheName = $this->alias . '_' . $options['cache']['name'];
$this->cacheConfig = isset($options['cache']['config']) ? $options['cache']['config'] : 'default';
}
$results = Cache::read($this->cacheName, $this->cacheConfig);
return $results;
}
}
?>

Nice one Jamie.
As a general point though, I’d make the getCachedResults method implied protected (single underscore) rather than implied private (double underscore) so if you need to you can override the method in your actual models if you need to.
Good point, Neil – having private functions in a class like AppModel really takes away from flexibility. I’ve updated the code on GitHub (and, if Matt Curry’s WordPress GitHub plugin is working, on here too).
Bookmarked
I precisely wanted to say thanks once more. I am not sure the things I would have achieved in the absence of the actual concepts revealed by you concerning my question. It had become a real frightful scenario in my opinion, nevertheless encountering this professional technique you treated it made me to leap with happiness. Extremely happy for your information and thus hope that you comprehend what an amazing job you happen to be getting into instructing others via a site. I’m certain you have never encountered any of us.
naturally like your website but you need to check the spelling on quite a few of your posts. Several of them are rife with spelling problems and I find it very troublesome to tell the truth nevertheless I will certainly come back again.