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:
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:
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;
}
}
?>
4 Responses to Adding Automatic Query Caching to Model::find() in CakePHP 1.2
CakePHP : signets remarquables du 23/11/2009 au 25/11/2009 | Cherry on the...
November 25th, 2009 at 12:04 am
[...] Adding Automatic Query Caching to Model::find() in CakePHP 1.2 | Jamie Nay [...]
Neil Crookes
November 25th, 2009 at 6:07 am
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.
Jamie
November 25th, 2009 at 8:36 am
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).
loopmob
December 3rd, 2009 at 8:10 am
Bookmarked