cache.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: cache_8php-source.html 580 2008-07-01 14:45:49Z gwoo $ */
00003 /**
00004  * Caching for CakePHP.
00005  *
00006  *
00007  * PHP versions 4 and 5
00008  *
00009  * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
00010  * Copyright 2005-2008, Cake Software Foundation, Inc.
00011  *                              1785 E. Sahara Avenue, Suite 490-204
00012  *                              Las Vegas, Nevada 89104
00013  *
00014  * Licensed under The MIT License
00015  * Redistributions of files must retain the above copyright notice.
00016  *
00017  * @filesource
00018  * @copyright       Copyright 2005-2008, Cake Software Foundation, Inc.
00019  * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00020  * @package         cake
00021  * @subpackage      cake.cake.libs
00022  * @since           CakePHP(tm) v 1.2.0.4933
00023  * @version         $Revision: 580 $
00024  * @modifiedby      $LastChangedBy: gwoo $
00025  * @lastmodified    $Date: 2008-07-01 09:45:49 -0500 (Tue, 01 Jul 2008) $
00026  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00027  */
00028 /**
00029  * Included libraries.
00030  */
00031 /**
00032  * Caching for CakePHP.
00033  *
00034  * @package     cake
00035  * @subpackage  cake.cake.libs
00036  */
00037 class Cache extends Object {
00038 /**
00039  * Cache engine to use
00040  *
00041  * @var object
00042  * @access protected
00043  */
00044     var $_Engine = null;
00045 /**
00046  * Cache configuration stack
00047  *
00048  * @var array
00049  * @access private
00050  */
00051     var $__config = array();
00052 /**
00053  * Holds name of the current configuration being used
00054  *
00055  * @var array
00056  * @access private
00057  */
00058     var $__name = 'default';
00059 /**
00060  * Returns a singleton instance
00061  *
00062  * @return object
00063  * @access public
00064  */
00065     function &getInstance() {
00066         static $instance = array();
00067         if (!isset($instance[0]) || !$instance[0]) {
00068             $instance[0] =& new Cache();
00069         }
00070         return $instance[0];
00071     }
00072 /**
00073  * Tries to find and include a file for a cache engine and returns object instance
00074  *
00075  * @param $name Name of the engine (without 'Engine')
00076  * @return mixed $engine object or null
00077  * @access private
00078  */
00079     function __loadEngine($name) {
00080         if (!class_exists($name . 'Engine')) {
00081             $fileName = LIBS . DS . 'cache' . DS . strtolower($name) . '.php';
00082             if (!require($fileName)) {
00083                 return false;
00084             }
00085         }
00086         return true;
00087     }
00088 /**
00089  * Set the cache configuration to use
00090  *
00091  * @see app/config/core.php for configuration settings
00092  * @param string $name Name of the configuration
00093  * @param array $settings Optional associative array of settings passed to the engine
00094  * @return array(engine, settings) on success, false on failure
00095  * @access public
00096  */
00097     function config($name = null, $settings = array()) {
00098         $_this =& Cache::getInstance();
00099         if (is_array($name)) {
00100             $settings = $name;
00101         }
00102 
00103         if ($name === null || !is_string($name)) {
00104             $name = $_this->__name;
00105         }
00106 
00107         if (!empty($settings)) {
00108             $_this->__name = null;
00109             $_this->__config[$name] = $settings;
00110         } elseif (isset($_this->__config[$name])) {
00111             $settings = $_this->__config[$name];
00112         } else {
00113             return false;
00114         }
00115 
00116         if (empty($settings['engine'])) {
00117             return false;
00118         }
00119 
00120         $engine = $settings['engine'];
00121 
00122         if ($name !== $_this->__name) {
00123             if ($_this->engine($engine, $settings) === false) {
00124                 return false;
00125             }
00126             $_this->__name = $name;
00127 
00128         }
00129         $settings = $_this->__config[$name] = $_this->settings($engine);
00130         return compact('engine', 'settings');
00131     }
00132 /**
00133  * Set the cache engine to use or modify settings for one instance
00134  *
00135  * @param string $name Name of the engine (without 'Engine')
00136  * @param array $settings Optional associative array of settings passed to the engine
00137  * @return boolean True on success, false on failure
00138  * @access public
00139  */
00140     function engine($name = 'File', $settings = array()) {
00141         if (!$name || Configure::read('Cache.disable')) {
00142             return false;
00143         }
00144 
00145         $cacheClass = $name . 'Engine';
00146         $_this =& Cache::getInstance();
00147         if (!isset($_this->_Engine[$name])) {
00148             if ($_this->__loadEngine($name) === false) {
00149                 return false;
00150             }
00151             $_this->_Engine[$name] =& new $cacheClass();
00152         }
00153 
00154         if ($_this->_Engine[$name]->init($settings)) {
00155             if (time() % $_this->_Engine[$name]->settings['probability'] == 0) {
00156                 $_this->_Engine[$name]->gc();
00157             }
00158             return true;
00159         }
00160         $_this->_Engine[$name] = null;
00161         return false;
00162     }
00163 /**
00164  * Garbage collection
00165  *
00166  * Permanently remove all expired and deleted data
00167  *
00168  * @access public
00169  */
00170     function gc() {
00171         $_this =& Cache::getInstance();
00172         $config = $_this->config();
00173         extract($config);
00174         $_this->_Engine[$engine]->gc();
00175     }
00176 /**
00177  * Write data for key into cache
00178  *
00179  * @param string $key Identifier for the data
00180  * @param mixed $value Data to be cached - anything except a resource
00181  * @param mixed $duration Optional - string configuration name OR how long to cache the data, either in seconds or a
00182  *          string that can be parsed by the strtotime() function OR array('config' => 'default', 'duration' => '3600')
00183  * @return boolean True if the data was successfully cached, false on failure
00184  * @access public
00185  */
00186     function write($key, $value, $duration = null) {
00187         $_this =& Cache::getInstance();
00188         $config = null;
00189         if (is_array($duration)) {
00190             extract($duration);
00191         } elseif (isset($_this->__config[$duration])) {
00192             $config = $duration;
00193             $duration = null;
00194         }
00195         $current = $_this->__name;
00196         $config = $_this->config($config);
00197 
00198         if (!is_array($config)) {
00199             return null;
00200         }
00201         extract($config);
00202 
00203         if (!$_this->isInitialized($engine)) {
00204             return false;
00205         }
00206 
00207         if (!$key = $_this->__key($key)) {
00208             return false;
00209         }
00210 
00211         if (is_resource($value)) {
00212             return false;
00213         }
00214 
00215         if (!$duration) {
00216             $duration = $settings['duration'];
00217         }
00218         $duration = ife(is_numeric($duration), intval($duration), strtotime($duration) - time());
00219 
00220         if ($duration < 1) {
00221             return false;
00222         }
00223 
00224         $success = $_this->_Engine[$engine]->write($settings['prefix'] . $key, $value, $duration);
00225         $_this->config($current);
00226         return $success;
00227     }
00228 /**
00229  * Read a key from the cache
00230  *
00231  * @param string $key Identifier for the data
00232  * @param string $config name of the configuration to use
00233  * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
00234  * @access public
00235  */
00236     function read($key, $config = null) {
00237         $_this =& Cache::getInstance();
00238         $current = $_this->__name;
00239 
00240         $config = $_this->config($config);
00241 
00242         if (!is_array($config)) {
00243             return null;
00244         }
00245         extract($config);
00246 
00247         if (!$_this->isInitialized($engine)) {
00248             return false;
00249         }
00250         if (!$key = $_this->__key($key)) {
00251             return false;
00252         }
00253         $success = $_this->_Engine[$engine]->read($settings['prefix'] . $key);
00254         $_this->config($current);
00255         return $success;
00256     }
00257 /**
00258  * Delete a key from the cache
00259  *
00260  * @param string $key Identifier for the data
00261  * @param string $config name of the configuration to use
00262  * @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
00263  * @access public
00264  */
00265     function delete($key, $config = null) {
00266         $_this =& Cache::getInstance();
00267         $current = $_this->__name;
00268         $config = $_this->config($config);
00269         extract($config);
00270 
00271         if (!$_this->isInitialized($engine)) {
00272             return false;
00273         }
00274 
00275         if (!$key = $_this->__key($key)) {
00276             return false;
00277         }
00278 
00279         $success = $_this->_Engine[$engine]->delete($settings['prefix'] . $key);
00280         $_this->config($current);
00281         return $success;
00282     }
00283 /**
00284  * Delete all keys from the cache
00285  *
00286  * @param boolean $check if true will check expiration, otherwise delete all
00287  * @param string $config name of the configuration to use
00288  * @return boolean True if the cache was succesfully cleared, false otherwise
00289  * @access public
00290  */
00291     function clear($check = false, $config = null) {
00292         $_this =& Cache::getInstance();
00293         $current = $_this->__name;
00294         $config = $_this->config($config);
00295         extract($config);
00296 
00297         if (!$_this->isInitialized($engine)) {
00298             return false;
00299         }
00300         $success = $_this->_Engine[$engine]->clear($check);
00301         $_this->config($current);
00302         return $success;
00303     }
00304 /**
00305  * Check if Cache has initialized a working storage engine
00306  *
00307  * @param string $engine Name of the engine
00308  * @param string $config Name of the configuration setting
00309  * @return bool
00310  * @access public
00311  */
00312     function isInitialized($engine = null) {
00313         if (Configure::read('Cache.disable')) {
00314             return false;
00315         }
00316         $_this =& Cache::getInstance();
00317         if (!$engine && isset($_this->__config[$_this->__name]['engine'])) {
00318             $engine = $_this->__config[$_this->__name]['engine'];
00319         }
00320         return isset($_this->_Engine[$engine]);
00321     }
00322 
00323 /**
00324  * Return the settings for current cache engine
00325  *
00326  * @param string $engine Name of the engine
00327  * @return array list of settings for this engine
00328  * @access public
00329  */
00330     function settings($engine = null) {
00331         $_this =& Cache::getInstance();
00332         if (!$engine && isset($_this->__config[$_this->__name]['engine'])) {
00333             $engine = $_this->__config[$_this->__name]['engine'];
00334         }
00335 
00336         if (isset($_this->_Engine[$engine]) && !is_null($_this->_Engine[$engine])) {
00337             return $_this->_Engine[$engine]->settings();
00338         }
00339         return array();
00340     }
00341 /**
00342  * generates a safe key
00343  *
00344  * @param string $key the key passed over
00345  * @return mixed string $key or false
00346  * @access private
00347  */
00348     function __key($key) {
00349         if (empty($key)) {
00350             return false;
00351         }
00352         $key = str_replace(array(DS, '/', '.'), '_', strval($key));
00353         return $key;
00354     }
00355 }
00356 /**
00357  * Storage engine for CakePHP caching
00358  *
00359  * @package     cake
00360  * @subpackage  cake.cake.libs
00361  */
00362 class CacheEngine extends Object {
00363 /**
00364  * settings of current engine instance
00365  *
00366  * @var int
00367  * @access public
00368  */
00369     var $settings = array();
00370 /**
00371  * Iitialize the cache engine
00372  *
00373  * Called automatically by the cache frontend
00374  *
00375  * @param array $params Associative array of parameters for the engine
00376  * @return boolean True if the engine has been succesfully initialized, false if not
00377  * @access public
00378  */
00379     function init($settings = array()) {
00380         $this->settings = array_merge(array('prefix' => 'cake_', 'duration'=> 3600, 'probability'=> 100), $this->settings, $settings);
00381         return true;
00382     }
00383 /**
00384  * Garbage collection
00385  *
00386  * Permanently remove all expired and deleted data
00387  *
00388  * @access public
00389  */
00390     function gc() {
00391     }
00392 /**
00393  * Write value for a key into cache
00394  *
00395  * @param string $key Identifier for the data
00396  * @param mixed $value Data to be cached
00397  * @param mixed $duration How long to cache the data, in seconds
00398  * @return boolean True if the data was succesfully cached, false on failure
00399  * @access public
00400  */
00401     function write($key, &$value, $duration) {
00402         trigger_error(sprintf(__('Method write() not implemented in %s', true), get_class($this)), E_USER_ERROR);
00403     }
00404 /**
00405  * Read a key from the cache
00406  *
00407  * @param string $key Identifier for the data
00408  * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
00409  * @access public
00410  */
00411     function read($key) {
00412         trigger_error(sprintf(__('Method read() not implemented in %s', true), get_class($this)), E_USER_ERROR);
00413     }
00414 /**
00415  * Delete a key from the cache
00416  *
00417  * @param string $key Identifier for the data
00418  * @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed
00419  * @access public
00420  */
00421     function delete($key) {
00422     }
00423 /**
00424  * Delete all keys from the cache
00425  *
00426  * @param boolean $check if true will check expiration, otherwise delete all
00427  * @return boolean True if the cache was succesfully cleared, false otherwise
00428  * @access public
00429  */
00430     function clear($check) {
00431     }
00432 /**
00433  * Cache Engine settings
00434  *
00435  * @return array settings
00436  * @access public
00437  */
00438     function settings() {
00439         return $this->settings;
00440     }
00441 }
00442 ?>