hello world!
Published: September 29, 2010

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 cachemanger to create your cache then pass that cache onto your other components through the 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 straight forward in that they accept an instance of Zend_Cache. Doctrine on the other hand defines it's 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 "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 insite as to how my application is configured, allows for easier changes and managing my cache is much simpler.

Leave a Reply

linkedin-squaregithub-squarestack-overflowfacebook-official