load($cachekey))) { * $result = caluate some how; * $cache->save($result); * } * * return $result; * * Normally there's no need to remove things from the cache - the cache backends clear out entries based on age & * maximum allocated storage. If you include the version of the object in the cache key, even object changes don't * need any invalidation * * DISABLING CACHING IN DEV MOVE * * (in _config.php) * * if (Director::isDev()) SS_Cache::set_cache_lifetime('any', -1, 100); * * USING MEMCACHED AS STORE * * (in _config.php) * * SS_Cache::add_backend('primary_memcached', 'Memcached', * array('host' => 'localhost', 'port' => 11211, 'persistent' => true, 'weight' => 1, 'timeout' => 5, * 'retry_interval' => 15, 'status' => true, 'failure_callback' => '' ) * ); * * SS_Cache::pick_backend('primary_memcached', 'any', 10); * // Aggregate needs a backend with tag support, which memcached doesn't provide * SS_Cache::pick_backend('default', 'aggregate', 20); * * * USING APC AND FILE AS TWO LEVEL STORE * * (in _config.php) * * SS_Cache::add_backend('two-level', 'TwoLevels', array( * 'slow_backend' => 'File', * 'fast_backend' => 'Apc', * 'slow_backend_options' => array('cache_dir' => TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache') * )); * * // No need for special backend for aggregate - TwoLevels with a File slow backend supports tags * SS_Cache::pick_backend('two-level', 'any', 10); * * @author hfried * @package framework * @subpackage core */ class SS_Cache { protected static $backends = array(); protected static $backend_picks = array(); protected static $cache_lifetime = array(); /** * Initialize the 'default' named cache backend */ protected static function init(){ if (!isset(self::$backends['default'])) { $cachedir = TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache'; if (!is_dir($cachedir)) mkdir($cachedir); self::$backends['default'] = array( 'File', array('cache_dir' => TEMP_FOLDER . DIRECTORY_SEPARATOR . 'cache') ); self::$cache_lifetime['default'] = array('lifetime' => 600, 'priority' => 1); } } /** * Add a new named cache backend * * @param string $name The name of this backend as a freeform string * @param string $type The Zend_Cache backend ('File' or 'Sqlite' or ...) * @param array $options The Zend_Cache backend options (see http://framework.zend.com/manual/en/zend.cache.html) * @return none */ public static function add_backend($name, $type, $options=array()) { self::init(); self::$backends[$name] = array($type, $options); } /** * Pick a named cache backend for a particular named cache * * @param string $name The name of the backend, as passed as the first argument to add_backend * @param string $for The name of the cache to pick this backend for (or 'any' for any backend) * @param integer $priority The priority of this pick - the call with the highest number will be the actual * backend picked. A backend picked for a specific cache name will always be used instead * of 'any' if it exists, no matter the priority. * @return none */ public static function pick_backend($name, $for, $priority=1) { self::init(); $current = -1; if (isset(self::$backend_picks[$for])) $current = self::$backend_picks[$for]['priority']; if ($priority >= $current) self::$backend_picks[$for] = array('name' => $name, 'priority' => $priority); } /** * Return the cache lifetime for a particular named cache. * @return array */ public static function get_cache_lifetime($for) { return (isset(self::$cache_lifetime[$for])) ? self::$cache_lifetime[$for] : false; } /** * Set the cache lifetime for a particular named cache * * @param string $for The name of the cache to set this lifetime for (or 'any' for all backends) * @param integer $lifetime The lifetime of an item of the cache, in seconds, or -1 to disable caching * @param integer $priority The priority. The highest priority setting is used. Unlike backends, 'any' is not * special in terms of priority. */ public static function set_cache_lifetime($for, $lifetime=600, $priority=1) { self::init(); $current = -1; if (isset(self::$cache_lifetime[$for])) $current = self::$cache_lifetime[$for]['priority']; if ($priority >= $current) { self::$cache_lifetime[$for] = array('lifetime' => $lifetime, 'priority' => $priority); } } /** * Build a cache object * @param string $for The name of the cache to build the cache object for * @param string $frontend (optional) The type of Zend_Cache frontend to use. Output is almost always the best * @param array $frontendOptions (optional) Any frontend options to use. * * @return The cache object. It has been partitioned so that actions on the object * won't affect cache objects generated with a different $for value, even those using the same Zend_Backend * * -- Cache a calculation * * if (!($result = $cache->load($cachekey))) { * $result = caluate some how; * $cache->save($result); * } * * return $result; * * -- Cache captured output * * if (!($cache->start($cachekey))) { * * // output everything as usual * echo 'Hello world! '; * echo 'This is cached ('.time().') '; * * $cache->end(); // output buffering ends * } * * -- Invalidate an element * * $cache->remove($cachekey); * * -- Clear the cache (warning - this clears the entire backend, not just this named cache partition) * * $cache->clean(Zend_Cache::CLEANING_MODE_ALL); * * See the Zend_Cache documentation at http://framework.zend.com/manual/en/zend.cache.html for more * */ public static function factory($for, $frontend='Output', $frontendOptions=null) { self::init(); $backend_name = 'default'; $backend_priority = -1; $cache_lifetime = self::$cache_lifetime['default']['lifetime']; $lifetime_priority = -1; foreach (array('any', $for) as $name) { if (isset(self::$backend_picks[$name]) && self::$backend_picks[$name]['priority'] > $backend_priority) { $backend_name = self::$backend_picks[$name]['name']; $backend_priority = self::$backend_picks[$name]['priority']; } if (isset(self::$cache_lifetime[$name]) && self::$cache_lifetime[$name]['priority'] > $lifetime_priority) { $cache_lifetime = self::$cache_lifetime[$name]['lifetime']; $lifetime_priority = self::$cache_lifetime[$name]['priority']; } } $backend = self::$backends[$backend_name]; $basicOptions = array('cache_id_prefix' => $for); if ($cache_lifetime >= 0) $basicOptions['lifetime'] = $cache_lifetime; else $basicOptions['caching'] = false; $frontendOptions = $frontendOptions ? array_merge($basicOptions, $frontendOptions) : $basicOptions; require_once 'Zend/Cache.php'; return Zend_Cache::factory($frontend, $backend[0], $frontendOptions, $backend[1]); } }