Consolidating Cache Management in Zend Framework
In version 1.10, Zend added an Application Resource to the Zend Framework for easily setting up your Caching resources through configuration files.
resources.cachemanager.cacheCoreFile.frontend.name = "Core"
resources.cachemanager.cacheCoreFile.frontend.options.lifetime = 3600
resources.cachemanager.cacheCoreFile.frontend.options.cache_id_prefix = APPLICATION_ENV "_cache_core_file"
resources.cachemanager.cacheCoreFile.frontend.options.automatic_serialization = true
resources.cachemanager.cacheCoreFile.frontend.options.automatic_cleaning_factor = 1
resources.cachemanager.cacheCoreFile.backend.name = "File"
resources.cachemanager.cacheCoreFile.backend.options.cache_dir = APPLICATION_PATH "/data/cache"
The problem is that components like Doctrine, Zend_Translate, Zend_Db and so on all have directives for their own cache configurations.
This makes managing cache times, invalidations, and timeouts very difficult.
A solution to this is to use the cache manager to create your cache and then pass that cache onto your other components through bootstrap ( see example below ).
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
...
$this->_cache = null;
protected function _initCache() {
$this->bootstrap('cachemanager');
$cache = $this->getResource('cachemanager')>getCache('cacheCoreFile');
$this->_cache = $cache;
Zend_Registry::set('cacheCoreFile', $cache);
}
protected function _initTranslateCache() {
$this->bootstrap('cache');
$this->bootstrap('translate');
Zend_Translate::setCache($this->_cache);
}
protected function _initDoctrineCache() {
$this->bootstrap('cache');
$this->bootstrap('doctrine');
$doctrineAdapter = new DoctrineAdapter(
$this->_cache ,
'my_doctrine_cache_prefix'
);
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute( Doctrine_Core::ATTR_RESULT_CACHE , $doctrineAdapter );
}
...
}
Most of the Zend components are pretty straightforward in that they accept an instance of Zend_Cache. Doctrine on the other hand defines its own cache drivers. Thanks to Benjamin Steininger we have a Doctrin_Cache driver implementation for Zend_Cache.
I made a small modification to the "save" method to add some custom cache tags, which I'll explain in a minute.
class DoctrineAdapter implements Doctrine_Cache_Interface {
...
public function save($id, $data, $lifetime = false) {
$id = $this->_prefix . $id;
return $this->_cache->save(
$data,
$id,
array( My_CacheTags::TAG_DOCTRINE ),
$lifetime
);
}
...
}
Zend_Cache tags allow for the "categorizing" of cached items.
To make my tag management easier I created a class with all the tags I use as static properties. This also allows me to reflect on the class for building my cache admin interfaces.
class My_CacheTags {
const TAG_MODULE_DEFAULT = "TAG_MODULE_DEFAULT";
const TAG_MODULE_OTHER = "TAG_MODULE_OTHER";
const TAG_ACTION = "TAG_ACTION";
const TAG_VIEW = "TAG_VIEW";
const TAG_DOCTRINE = "TAG_DOCTRINE";
// Zend Translate automatically adds it's tag Zend_Translate so we'll use it's tag name
const TAG_TRANSLATE = "Zend_Translate";
}
Now, emptying specific groups of items from the cache is much easier since we can specify which tags I want to clean from the cache.
$cache->clean(
Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array(
My_CacheTags::TAG_MODULE_DEFAULT ,
My_CacheTags::TAG_VIEW
)
);
The set-up described gives me much better insight as to how my application is configured, allows for easier changes, and manages my cache much more simpler.