In this example, we cache data using the following front-ends: core, standard output, class method, function. Data are cached in a file or in a database.
Components used in this example
Working with caches
class MyCache
{
public static $frontend = array('Core', 'Class', 'Object', 'Function', 'Output');
public static $backend = array('File', 'Sqlite');
Processing the cache request- We get the front-end, the back-end, the record identifier, the data or parameter, the tags, and the lifetime.
- We set the cache.
- We get the record identifiers currently cached.
- We perform the action on the cache.
- We refresh the list of record identifiers currently cached.
- If we catch an exception, we return the error message.
public function process()
{
// We get the front-end, the back-end, the record identifier,
// the data or parameter, the tags, and the lifetime.
list($frontend, $backend, $action, $id, $param, $tags, $lifetime) =
$this->_getParameters();
$ids = array();
$params = array();
try {
// We set the cache.
$cache = $this->_setCache($frontend, $backend, $lifetime);
// We get the record identifiers currently cached.
$ids = $this->_getIds($cache);
// We perform the action on the cache.
switch($action) {
case 'clean all':
case 'clean matchingAnyTag':
case 'clean matchingTag':
case 'clean notMatchingTag':
case 'clean old':
list(, $mode) = explode(' ', $action);
$result = $cache->clean($mode, $tags);
break;
case 'getBackend':
case 'getFillingPercentage':
case 'getIds':
case 'getTags':
$result = $cache->$action();
break;
case 'getIdsMatchingTags':
case 'getIdsNotMatchingTags':
$result = $cache->$action($tags);
break;
case 'getMetadatas':
case 'load':
case 'remove':
case 'test':
$result = $cache->$action($id);
break;
case 'touch 3':
case 'touch 10':
case 'touch 60':
case 'touch 3600':
list(, $extraLifetime) = explode(' ', $action);
$result = $cache->touch($id, $extraLifetime);
break;
case 'Cache':
$result = $this->_cache($cache, $frontend, $backend, $tags,
$lifetime, $param);
$id = null;
break;
case 'Set':
default:
$result = "The $frontend / $backend cache is set";
}
// We refresh the list of record identifiers currently cached.
$ids = $this->_getIds($cache);
} catch (Exception $e) {
// If we catch an exception, we return the error message.
$result = $e->getMessage();
}
return array($frontend, $backend, $action, $id, $param, $lifetime, $ids, $result);
}
Extraction of the parameters from the GET request
private function _getParameters()
{
$frontend = isset($_GET['frontend'])? $_GET['frontend'] : 'Core';
$backend = isset($_GET['backend'])? $_GET['backend'] : 'File';
$id = isset($_GET['id'])? $_GET['id'] : null;
$param = isset($_GET['param'])? $_GET['param'] : null;
$tags = isset($_GET['tags'])? $_GET['tags'] : array();
$lifetime = isset($_GET['lifetime'])? $_GET['lifetime'] : 300;
isset($_GET['submit']) and $action = $_GET['submit'] or
$action = isset($_GET['action'])? $_GET['action'] : null;
return array($frontend, $backend, $action, $id, $param, $tags, $lifetime);
}
Setting the cache
private function _setCache($frontend, $backend)
{
$frontendOptions = array(
'lifetime' => 3600,
'automatic_serialization' => true,
'cache_id_prefix' => $this->_setPrefix($frontend),
);
switch($frontend) {
case 'Class':
$frontendOptions['cached_entity'] = __CLASS__;
break;
case 'Object':
$frontend = 'Class';
$frontendOptions['cached_entity'] = $this;
break;
}
switch($backend) {
case 'Sqlite':
$backendOptions['cache_db_complete_path'] = 'data/cache/cache.sqlite';
break;
case 'File':
default:
$backendOptions['cache_dir'] = 'data/cache';
break;
}
return Zend_Cache::factory($frontend, $backend, $frontendOptions, $backendOptions);
}
Getting the record identifiers currently cached without prefixes
private function _getIds($cache)
{
$ids = $cache->getIds();
$prefixes = implode('|', self::$frontend);
$fct = create_function('$s', "return !preg_match('~($prefixes)~', \$s);");
return array_filter($ids, $fct);
}
Caching data- We cache the data or parameter along with the back-end, the front-end, the tags, the save method, and the lifetime.
private function _cache($cache, $frontend, $backend, $tags, $lifetime, $param)
{
// We cache the data or parameter along with the back-end, the front-end,
// the tags, the save method, and the lifetime.
switch($frontend) {
case 'Core':
if (!($isCached = $data = $cache->load($param))) {
$data = self::_makeData($frontend, $backend, $tags, 'save()',
$lifetime, $param);
$cache->save($data, $param, $tags, $lifetime);
}
break;
case 'Class':
$method = __CLASS__ . '::' . __FUNCTION__ . '()';
$lifetime and $cache->setSpecificLifetime($lifetime);
$tags and $cache->setTagsArray($tags);
$time = time();
$data = $cache->staticMethod($frontend, $backend, $tags, $method,
$lifetime, $param);
$isCached = $data['settings']['timestamp'] < $time;
break;
case 'Object':
$method = '$cache->' . __FUNCTION__ . '()';
$lifetime and $cache->setSpecificLifetime($lifetime);
$tags and $cache->setTagsArray($tags);
$time = time();
$data = $cache->nonStaticMethod($frontend, $backend, $tags, $method,
$lifetime, $param);
$isCached = $data['settings']['timestamp'] < $time;
break;
case 'Function':
$method = __FUNCTION__ . '()';
$parameters = array($frontend, $backend, $tags, $method, $lifetime, $param);
$time = time();
$data = $cache->call('myFunction', $parameters, $tags, $lifetime);
$isCached = $data['settings']['timestamp'] < $time;
break;
case 'Output':
if (!($isCached = $data = $cache->start($param, false, false))) {
$data = self::_makeData($frontend, $backend, $tags, 'start()/end()',
$lifetime, $param);
print_r($data);
$cache->end($tags, $lifetime, null, false);
}
break;
}
$result[] = $isCached?
'THE DATA WAS RETRIEVED FROM THE CACHE.' :
'THE DATA HAS JUST BEEN ADDED TO THE CACHE.';
$result[] = $data;
return $result;
}
Static method to be cached
public static function staticMethod($frontend, $backend, $tags, $method,
$lifetime, $param)
{
return self::_makeData($frontend, $backend, $tags, $method, $lifetime, $param);
}
Non-static method to be cached
public static function nonStaticMethod($frontend, $backend, $tags, $method,
$lifetime, $param)
{
return self::_makeData($frontend, $backend, $tags, $method, $lifetime, $param);
}
Putting the data together
public static function _makeData($frontend, $backend, $tags, $method, $lifetime, $param)
{
$data['DATA'] = $param;
$data['settings'] = array(
'date' => date(DATE_COOKIE),
'lifetime' => $lifetime,
'frontend' => $frontend,
'backend' => $backend,
'method' => $method,
'timestamp' => time(),
'tags' => $tags,
);
return $data;
}
Building the prefix of identifiers- We store a random number in a cookie to identify a user.
- We build the prefix with the user identifier and the name of front-end.
private function _setPrefix($frontend)
{
// We store a random number in a cookie to identify a user.
if (empty($_COOKIE['cache'])) {
$user = rand(1000, 9999);
setcookie('cache', $user, time() + 3600 * 24, '/');
} else {
$user = $_COOKIE['cache'];
}
// We build the prefix with the user identifier and the name of front-end.
return "$user$frontend";
}
}
No comments:
Post a Comment