Upgrade to KH 3.3.0

This commit is contained in:
Deon George
2012-11-22 14:25:06 +11:00
parent e5e67a59bb
commit 5bd1841571
1455 changed files with 114353 additions and 9466 deletions

View File

@@ -9,13 +9,11 @@ Supported cache solutions
Currently this module supports the following cache methods.
1. APC
2. eAccelerator
3. Memcache
4. Memcached-tags (Supports tags)
5. SQLite (Supports tags)
6. File
7. Xcache
8. Wincache
2. Memcache
3. Memcached-tags (Supports tags)
4. SQLite (Supports tags)
5. File
6. Wincache
Planned support
---------------

View File

@@ -1,3 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
class Cache_Eaccelerator extends Kohana_Cache_Eaccelerator {}
interface Cache_Arithmetic extends Kohana_Cache_Arithmetic {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
class Cache_Exception extends Kohana_Cache_Exception {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
interface Cache_GarbageCollect extends Kohana_Cache_GarbageCollect {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
interface Cache_Tagging extends Kohana_Cache_Tagging {}

View File

@@ -1,3 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
class Cache_Xcache extends Kohana_Cache_Xcache {}
class HTTP_Cache extends Kohana_HTTP_Cache {}

View File

@@ -1,11 +1,11 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Kohana Cache provides a common interface to a variety of caching engines. Tags are
* supported where available natively to the cache system. Kohana Cache supports multiple
* supported where available natively to the cache system. Kohana Cache supports multiple
* instances of cache engines through a grouped singleton pattern.
*
*
* ### Supported cache engines
*
*
* * [APC](http://php.net/manual/en/book.apc.php)
* * [eAccelerator](http://eaccelerator.net/)
* * File
@@ -13,28 +13,28 @@
* * [Memcached-tags](http://code.google.com/p/memcached-tags/)
* * [SQLite](http://www.sqlite.org/)
* * [Xcache](http://xcache.lighttpd.net/)
*
*
* ### Introduction to caching
*
*
* Caching should be implemented with consideration. Generally, caching the result of resources
* is faster than reprocessing them. Choosing what, how and when to cache is vital. PHP APC is
* presently one of the fastest caching systems available, closely followed by Memcache. SQLite
* and File caching are two of the slowest cache methods, however usually faster than reprocessing
* a complex set of instructions.
*
*
* Caching engines that use memory are considerably faster than the file based alternatives. But
* memory is limited whereas disk space is plentiful. If caching large datasets it is best to use
* file caching.
*
*
* ### Configuration settings
*
*
* Kohana Cache uses configuration groups to create cache instances. A configuration group can
* use any supported driver, with successive groups using the same driver type if required.
*
*
* #### Configuration example
*
*
* Below is an example of a _memcache_ server configuration.
*
*
* return array(
* 'default' => array( // Default group
* 'driver' => 'memcache', // using Memcache driver
@@ -48,30 +48,30 @@
* 'compression' => FALSE, // Use compression?
* ),
* )
*
*
* In cases where only one cache group is required, if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance.
*
*
* #### General cache group configuration settings
*
*
* Below are the settings available to all types of cache driver.
*
*
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | (_string_) The driver type to use
*
*
* Details of the settings specific to each driver are available within the drivers documentation.
*
*
* ### System requirements
*
*
* * Kohana 3.0.x
* * PHP 5.2.4 or greater
*
*
* @package Kohana/Cache
* @category Base
* @version 2.0
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_Cache {
@@ -91,19 +91,19 @@ abstract class Kohana_Cache {
/**
* Creates a singleton of a Kohana Cache group. If no group is supplied
* the __default__ cache group is used.
*
*
* // Create an instance of the default group
* $default_group = Cache::instance();
*
*
* // Create an instance of a group
* $foo_group = Cache::instance('foo');
*
*
* // Access an instantiated group directly
* $foo_group = Cache::$instances['default'];
*
* @param string the name of the cache group to use [Optional]
* @return Kohana_Cache
* @throws Kohana_Cache_Exception
* @param string $group the name of the cache group to use [Optional]
* @return Cache
* @throws Cache_Exception
*/
public static function instance($group = NULL)
{
@@ -120,11 +120,14 @@ abstract class Kohana_Cache {
return Cache::$instances[$group];
}
$config = Kohana::config('cache');
$config = Kohana::$config->load('cache');
if ( ! $config->offsetExists($group))
{
throw new Kohana_Cache_Exception('Failed to load Kohana Cache group: :group', array(':group' => $group));
throw new Cache_Exception(
'Failed to load Kohana Cache group: :group',
array(':group' => $group)
);
}
$config = $config->get($group);
@@ -140,59 +143,100 @@ abstract class Kohana_Cache {
/**
* @var Config
*/
protected $_config;
protected $_config = array();
/**
* Ensures singleton pattern is observed, loads the default expiry
*
* @param array configuration
*
* @param array $config configuration
*/
protected function __construct(array $config)
{
$this->_config = $config;
$this->config($config);
}
/**
* Getter and setter for the configuration. If no argument provided, the
* current configuration is returned. Otherwise the configuration is set
* to this class.
*
* // Overwrite all configuration
* $cache->config(array('driver' => 'memcache', '...'));
*
* // Set a new configuration setting
* $cache->config('servers', array(
* 'foo' => 'bar',
* '...'
* ));
*
* // Get a configuration setting
* $servers = $cache->config('servers);
*
* @param mixed key to set to array, either array or config path
* @param mixed value to associate with key
* @return mixed
*/
public function config($key = NULL, $value = NULL)
{
if ($key === NULL)
return $this->_config;
if (is_array($key))
{
$this->_config = $key;
}
else
{
if ($value === NULL)
return Arr::get($this->_config, $key);
$this->_config[$key] = $value;
}
return $this;
}
/**
* Overload the __clone() method to prevent cloning
*
* @return void
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function __clone()
final public function __clone()
{
throw new Kohana_Cache_Exception('Cloning of Kohana_Cache objects is forbidden');
throw new Cache_Exception('Cloning of Kohana_Cache objects is forbidden');
}
/**
* Retrieve a cached value entry by id.
*
*
* // Retrieve cache entry from default group
* $data = Cache::instance()->get('foo');
*
*
* // Retrieve cache entry from default group and return 'bar' if miss
* $data = Cache::instance()->get('foo', 'bar');
*
*
* // Retrieve cache entry from memcache group
* $data = Cache::instance('memcache')->get('foo');
*
* @param string id of cache to entry
* @param string default value to return if cache miss
* @param string $id id of cache to entry
* @param string $default default value to return if cache miss
* @return mixed
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
abstract public function get($id, $default = NULL);
/**
* Set a value to cache with id and lifetime
*
*
* $data = 'bar';
*
*
* // Set 'bar' to 'foo' in default group, using default expiry
* Cache::instance()->set('foo', $data);
*
*
* // Set 'bar' to 'foo' in default group for 30 seconds
* Cache::instance()->set('foo', $data, 30);
*
*
* // Set 'bar' to 'foo' in memcache group for 10 minutes
* if (Cache::instance('memcache')->set('foo', $data, 600))
* {
@@ -200,37 +244,37 @@ abstract class Kohana_Cache {
* return
* }
*
* @param string id of cache entry
* @param string data to set to cache
* @param integer lifetime in seconds
* @param string $id id of cache entry
* @param string $data data to set to cache
* @param integer $lifetime lifetime in seconds
* @return boolean
*/
abstract public function set($id, $data, $lifetime = 3600);
/**
* Delete a cache entry based on id
*
*
* // Delete 'foo' entry from the default group
* Cache::instance()->delete('foo');
*
*
* // Delete 'foo' entry from the memcache group
* Cache::instance('memcache')->delete('foo')
*
* @param string id to remove from cache
* @param string $id id to remove from cache
* @return boolean
*/
abstract public function delete($id);
/**
* Delete all cache entries.
*
*
* Beware of using this method when
* using shared memory cache systems, as it will wipe every
* entry within the system for all clients.
*
*
* // Delete all cache entries in the default group
* Cache::instance()->delete_all();
*
*
* // Delete all cache entries in the memcache group
* Cache::instance('memcache')->delete_all();
*
@@ -243,8 +287,8 @@ abstract class Kohana_Cache {
*
* // Sanitize a cache id
* $id = $this->_sanitize_id($id);
*
* @param string id of cache to sanitize
*
* @param string $id id of cache to sanitize
* @return string
*/
protected function _sanitize_id($id)

View File

@@ -2,54 +2,54 @@
/**
* [Kohana Cache](api/Kohana_Cache) APC driver. Provides an opcode based
* driver for the Kohana Cache library.
*
*
* ### Configuration example
*
*
* Below is an example of an _apc_ server configuration.
*
*
* return array(
* 'apc' => array( // Driver group
* 'driver' => 'apc', // using APC driver
* ),
* )
*
*
* In cases where only one cache group is required, if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance.
*
*
* #### General cache group configuration settings
*
*
* Below are the settings available to all types of cache driver.
*
*
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | (_string_) The driver type to use
*
*
* ### System requirements
*
*
* * Kohana 3.0.x
* * PHP 5.2.4 or greater
* * APC PHP extension
*
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Apc extends Cache {
class Kohana_Cache_Apc extends Cache implements Cache_Arithmetic {
/**
* Check for existence of the APC extension This method cannot be invoked externally. The driver must
* be instantiated using the `Cache::instance()` method.
*
* @param array configuration
* @throws Kohana_Cache_Exception
* @param array $config configuration
* @throws Cache_Exception
*/
protected function __construct(array $config)
{
if ( ! extension_loaded('apc'))
{
throw new Kohana_Cache_Exception('PHP APC extension is not available.');
throw new Cache_Exception('PHP APC extension is not available.');
}
parent::__construct($config);
@@ -57,17 +57,17 @@ class Kohana_Cache_Apc extends Cache {
/**
* Retrieve a cached value entry by id.
*
*
* // Retrieve cache entry from apc group
* $data = Cache::instance('apc')->get('foo');
*
*
* // Retrieve cache entry from apc group and return 'bar' if miss
* $data = Cache::instance('apc')->get('foo', 'bar');
*
* @param string id of cache to entry
* @param string default value to return if cache miss
* @param string $id id of cache to entry
* @param string $default default value to return if cache miss
* @return mixed
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function get($id, $default = NULL)
{
@@ -78,18 +78,18 @@ class Kohana_Cache_Apc extends Cache {
/**
* Set a value to cache with id and lifetime
*
*
* $data = 'bar';
*
*
* // Set 'bar' to 'foo' in apc group, using default expiry
* Cache::instance('apc')->set('foo', $data);
*
*
* // Set 'bar' to 'foo' in apc group for 30 seconds
* Cache::instance('apc')->set('foo', $data, 30);
*
* @param string id of cache entry
* @param string data to set to cache
* @param integer lifetime in seconds
* @param string $id id of cache entry
* @param string $data data to set to cache
* @param integer $lifetime lifetime in seconds
* @return boolean
*/
public function set($id, $data, $lifetime = NULL)
@@ -104,11 +104,11 @@ class Kohana_Cache_Apc extends Cache {
/**
* Delete a cache entry based on id
*
*
* // Delete 'foo' entry from the apc group
* Cache::instance('apc')->delete('foo');
*
* @param string id to remove from cache
* @param string $id id to remove from cache
* @return boolean
*/
public function delete($id)
@@ -118,11 +118,11 @@ class Kohana_Cache_Apc extends Cache {
/**
* Delete all cache entries.
*
*
* Beware of using this method when
* using shared memory cache systems, as it will wipe every
* entry within the system for all clients.
*
*
* // Delete all cache entries in the apc group
* Cache::instance('apc')->delete_all();
*
@@ -132,4 +132,35 @@ class Kohana_Cache_Apc extends Cache {
{
return apc_clear_cache('user');
}
}
/**
* Increments a given value by the step value supplied.
* Useful for shared counters and other persistent integer based
* tracking.
*
* @param string id of cache entry to increment
* @param int step value to increment by
* @return integer
* @return boolean
*/
public function increment($id, $step = 1)
{
return apc_inc($id, $step);
}
/**
* Decrements a given value by the step value supplied.
* Useful for shared counters and other persistent integer based
* tracking.
*
* @param string id of cache entry to decrement
* @param int step value to decrement by
* @return integer
* @return boolean
*/
public function decrement($id, $step = 1)
{
return apc_dec($id, $step);
}
} // End Kohana_Cache_Apc

View File

@@ -0,0 +1,39 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Kohana Cache Arithmetic Interface, for basic cache integer based
* arithmetic, addition and subtraction
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
* @since 3.2.0
*/
interface Kohana_Cache_Arithmetic {
/**
* Increments a given value by the step value supplied.
* Useful for shared counters and other persistent integer based
* tracking.
*
* @param string id of cache entry to increment
* @param int step value to increment by
* @return integer
* @return boolean
*/
public function increment($id, $step = 1);
/**
* Decrements a given value by the step value supplied.
* Useful for shared counters and other persistent integer based
* tracking.
*
* @param string id of cache entry to decrement
* @param int step value to decrement by
* @return integer
* @return boolean
*/
public function decrement($id, $step = 1);
} // End Kohana_Cache_Arithmetic

View File

@@ -5,7 +5,7 @@
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Exception extends Kohana_Exception {}

View File

@@ -3,56 +3,56 @@
* [Kohana Cache](api/Kohana_Cache) File driver. Provides a file based
* driver for the Kohana Cache library. This is one of the slowest
* caching methods.
*
*
* ### Configuration example
*
*
* Below is an example of a _file_ server configuration.
*
*
* return array(
* 'file' => array( // File driver group
* 'driver' => 'file', // using File driver
* 'cache_dir' => APPPATH.'cache/.kohana_cache', // Cache location
* ),
* )
*
*
* In cases where only one cache group is required, if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance.
*
*
* #### General cache group configuration settings
*
*
* Below are the settings available to all types of cache driver.
*
*
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | (_string_) The driver type to use
* cache_dir | __NO__ | (_string_) The cache directory to use for this cache instance
*
*
* ### System requirements
*
*
* * Kohana 3.0.x
* * PHP 5.2.4 or greater
*
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
/**
* Creates a hashed filename based on the string. This is used
* to create shorter unique IDs for each cache filename.
*
*
* // Create the cache filename
* $filename = Cache_File::filename($this->_sanitize_id($id));
*
* @param string string to hash into filename
* @param string $string string to hash into filename
* @return string
*/
protected static function filename($string)
{
return sha1($string).'.json';
return sha1($string).'.cache';
}
/**
@@ -64,8 +64,8 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
* Constructs the file cache driver. This method cannot be invoked externally. The file cache driver must
* be instantiated using the `Cache::instance()` method.
*
* @param array config
* @throws Kohana_Cache_Exception
* @param array $config config
* @throws Cache_Exception
*/
protected function __construct(array $config)
{
@@ -91,35 +91,35 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
// If the defined directory is a file, get outta here
if ($this->_cache_dir->isFile())
{
throw new Kohana_Cache_Exception('Unable to create cache directory as a file already exists : :resource', array(':resource' => $this->_cache_dir->getRealPath()));
throw new Cache_Exception('Unable to create cache directory as a file already exists : :resource', array(':resource' => $this->_cache_dir->getRealPath()));
}
// Check the read status of the directory
if ( ! $this->_cache_dir->isReadable())
{
throw new Kohana_Cache_Exception('Unable to read from the cache directory :resource', array(':resource' => $this->_cache_dir->getRealPath()));
throw new Cache_Exception('Unable to read from the cache directory :resource', array(':resource' => $this->_cache_dir->getRealPath()));
}
// Check the write status of the directory
if ( ! $this->_cache_dir->isWritable())
{
throw new Kohana_Cache_Exception('Unable to write to the cache directory :resource', array(':resource' => $this->_cache_dir->getRealPath()));
throw new Cache_Exception('Unable to write to the cache directory :resource', array(':resource' => $this->_cache_dir->getRealPath()));
}
}
/**
* Retrieve a cached value entry by id.
*
*
* // Retrieve cache entry from file group
* $data = Cache::instance('file')->get('foo');
*
*
* // Retrieve cache entry from file group and return 'bar' if miss
* $data = Cache::instance('file')->get('foo', 'bar');
*
* @param string id of cache to entry
* @param string default value to return if cache miss
* @param string $id id of cache to entry
* @param string $default default value to return if cache miss
* @return mixed
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function get($id, $default = NULL)
{
@@ -140,34 +140,44 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
}
else
{
// Open the file and extract the json
$json = $file->openFile()->current();
// Open the file and parse data
$created = $file->getMTime();
$data = $file->openFile();
$lifetime = $data->fgets();
// Decode the json into PHP object
$data = json_decode($json);
// If we're at the EOF at this point, corrupted!
if ($data->eof())
{
throw new Cache_Exception(__METHOD__.' corrupted cache file!');
}
$cache = '';
while ($data->eof() === FALSE)
{
$cache .= $data->fgets();
}
// Test the expiry
if ($data->expiry < time())
if (($created + (int) $lifetime) < time())
{
// Delete the file
$this->_delete_file($file, NULL, TRUE);
// Return default value
return $default;
}
else
{
return ($data->type === 'string') ? $data->payload : unserialize($data->payload);
return unserialize($cache);
}
}
}
catch (ErrorException $e)
{
// Handle ErrorException caused by failed unserialization
if ($e->getCode() === E_NOTICE)
{
throw new Kohana_Cache_Exception(__METHOD__.' failed to unserialize cached object with message : '.$e->getMessage());
throw new Cache_Exception(__METHOD__.' failed to unserialize cached object with message : '.$e->getMessage());
}
// Otherwise throw the exception
@@ -177,18 +187,18 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
/**
* Set a value to cache with id and lifetime
*
*
* $data = 'bar';
*
*
* // Set 'bar' to 'foo' in file group, using default expiry
* Cache::instance('file')->set('foo', $data);
*
*
* // Set 'bar' to 'foo' in file group for 30 seconds
* Cache::instance('file')->set('foo', $data, 30);
*
* @param string id of cache entry
* @param string data to set to cache
* @param integer lifetime in seconds
* @param string $id id of cache entry
* @param string $data data to set to cache
* @param integer $lifetime lifetime in seconds
* @return boolean
*/
public function set($id, $data, $lifetime = NULL)
@@ -209,10 +219,10 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
// If the directory path is not a directory
if ( ! $dir->isDir())
{
// Create the directory
// Create the directory
if ( ! mkdir($directory, 0777, TRUE))
{
throw new Kohana_Cache_Exception(__METHOD__.' unable to create directory : :directory', array(':directory' => $directory));
throw new Cache_Exception(__METHOD__.' unable to create directory : :directory', array(':directory' => $directory));
}
// chmod to solve potential umask issues
@@ -225,16 +235,9 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
try
{
$type = gettype($data);
// Serialize the data
$data = json_encode( (object) array(
'payload' => ($type === 'string') ? $data : serialize($data),
'expiry' => time() + $lifetime,
'type' => $type
));
$size = strlen($data);
$data = $lifetime."\n".serialize($data);
$file->fwrite($data, strlen($data));
return (bool) $file->fflush();
}
catch (ErrorException $e)
{
@@ -242,31 +245,21 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
if ($e->getCode() === E_NOTICE)
{
// Throw a caching error
throw new Kohana_Cache_Exception(__METHOD__.' failed to serialize data for caching with message : '.$e->getMessage());
throw new Cache_Exception(__METHOD__.' failed to serialize data for caching with message : '.$e->getMessage());
}
// Else rethrow the error exception
throw $e;
}
try
{
$file->fwrite($data, $size);
return (bool) $file->fflush();
}
catch (Exception $e)
{
throw $e;
}
}
/**
* Delete a cache entry based on id
*
*
* // Delete 'foo' entry from the file group
* Cache::instance('file')->delete('foo');
*
* @param string id to remove from cache
* @param string $id id to remove from cache
* @return boolean
*/
public function delete($id)
@@ -279,11 +272,11 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
/**
* Delete all cache entries.
*
*
* Beware of using this method when
* using shared memory cache systems, as it will wipe every
* entry within the system for all clients.
*
*
* // Delete all cache entries in the file group
* Cache::instance('file')->delete_all();
*
@@ -308,16 +301,16 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
/**
* Deletes files recursively and returns FALSE on any errors
*
*
* // Delete a file or folder whilst retaining parent directory and ignore all errors
* $this->_delete_file($folder, TRUE, TRUE);
*
* @param SplFileInfo file
* @param boolean retain the parent directory
* @param boolean ignore_errors to prevent all exceptions interrupting exec
* @param boolean only expired files
* @param SplFileInfo $file file
* @param boolean $retain_parent_directory retain the parent directory
* @param boolean $ignore_errors ignore_errors to prevent all exceptions interrupting exec
* @param boolean $only_expired only expired files
* @return boolean
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
protected function _delete_file(SplFileInfo $file, $retain_parent_directory = FALSE, $ignore_errors = FALSE, $only_expired = FALSE)
{
@@ -329,8 +322,13 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
{
try
{
// Handle ignore files
if (in_array($file->getFilename(), $this->config('ignore_on_delete')))
{
$delete = FALSE;
}
// If only expired is not set
if ($only_expired === FALSE)
elseif ($only_expired === FALSE)
{
// We want to delete the file
$delete = TRUE;
@@ -344,19 +342,18 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
$delete = $data->expiry < time();
}
// If the delete flag is set
// If the delete flag is set delete file
if ($delete === TRUE)
{
// Try to delete
unlink($file->getRealPath());
}
return unlink($file->getRealPath());
else
return FALSE;
}
catch (ErrorException $e)
{
// Catch any delete file warnings
if ($e->getCode() === E_WARNING)
{
throw new Kohana_Cache_Exception(__METHOD__.' failed to delete file : :file', array(':file' => $file->getRealPath()));
throw new Cache_Exception(__METHOD__.' failed to delete file : :file', array(':file' => $file->getRealPath()));
}
}
}
@@ -373,7 +370,7 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
$name = $files->getFilename();
// If the name is not a dot
if ($name != '.' AND $name != '..' AND substr($file->getFilename(), 0, 1) == '.')
if ($name != '.' AND $name != '..')
{
// Create new file resource
$fp = new SplFileInfo($files->getRealPath());
@@ -405,10 +402,16 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
// Catch any delete directory warnings
if ($e->getCode() === E_WARNING)
{
throw new Kohana_Cache_Exception(__METHOD__.' failed to delete directory : :directory', array(':directory' => $file->getRealPath()));
throw new Cache_Exception(__METHOD__.' failed to delete directory : :directory', array(':directory' => $file->getRealPath()));
}
throw $e;
}
}
else
{
// We get here if a file has already been deleted
return FALSE;
}
}
// Catch all exceptions
catch (Exception $e)
@@ -426,11 +429,11 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
/**
* Resolves the cache directory real path from the filename
*
*
* // Get the realpath of the cache folder
* $realpath = $this->_resolve_directory($filename);
*
* @param string filename to resolve
* @param string $filename filename to resolve
* @return string
*/
protected function _resolve_directory($filename)
@@ -442,22 +445,22 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect {
* Makes the cache directory if it doesn't exist. Simply a wrapper for
* `mkdir` to ensure DRY principles
*
* @see http://php.net/manual/en/function.mkdir.php
* @param string directory
* @param string mode
* @param string recursive
* @param string context
* @link http://php.net/manual/en/function.mkdir.php
* @param string $directory
* @param integer $mode
* @param boolean $recursive
* @param resource $context
* @return SplFileInfo
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL)
{
if ( ! mkdir($directory, $mode, $recursive, $context))
{
throw new Kohana_Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory));
throw new Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory));
}
chmod($directory, $mode);
return new SplFileInfo($directory);;
return new SplFileInfo($directory);
}
}

View File

@@ -8,7 +8,7 @@
* @category Base
* @version 2.0
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
* @since 3.0.8
*/

View File

@@ -1,16 +1,16 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* [Kohana Cache](api/Kohana_Cache) Memcache driver,
*
*
* ### Supported cache engines
*
*
* * [Memcache](http://www.php.net/manual/en/book.memcache.php)
* * [Memcached-tags](http://code.google.com/p/memcached-tags/)
*
*
* ### Configuration example
*
*
* Below is an example of a _memcache_ server configuration.
*
*
* return array(
* 'default' => array( // Default group
* 'driver' => 'memcache', // using Memcache driver
@@ -37,24 +37,24 @@
* 'compression' => FALSE, // Use compression?
* ),
* )
*
*
* In cases where only one cache group is required, if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance.
*
*
* #### General cache group configuration settings
*
*
* Below are the settings available to all types of cache driver.
*
*
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | (_string_) The driver type to use
* servers | __YES__ | (_array_) Associative array of server details, must include a __host__ key. (see _Memcache server configuration_ below)
* compression | __NO__ | (_boolean_) Use data compression when caching
*
*
* #### Memcache server configuration
*
*
* The following settings should be used when defining each memcache server
*
*
* Name | Required | Description
* ---------------- | -------- | ---------------------------------------------------------------
* host | __YES__ | (_string_) The host of the memcache server, i.e. __localhost__; or __127.0.0.1__; or __memcache.domain.tld__
@@ -65,22 +65,22 @@
* retry_interval | __NO__ | (_integer_) Controls how often a failed server will be retried, the default value is 15 seconds. Setting this parameter to -1 disables automatic retry. Default __15__
* status | __NO__ | (_boolean_) Controls if the server should be flagged as online. Default __TRUE__
* failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback)_) Allows the user to specify a callback function to run upon encountering an error. The callback is run before failover is attempted. The function takes two parameters, the hostname and port of the failed server. Default __NULL__
*
*
* ### System requirements
*
*
* * Kohana 3.0.x
* * PHP 5.2.4 or greater
* * Memcache (plus Memcached-tags for native tagging support)
* * Zlib
*
*
* @package Kohana/Cache
* @category Base
* @version 2.0
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Memcache extends Cache {
class Kohana_Cache_Memcache extends Cache implements Cache_Arithmetic {
// Memcache has a maximum cache lifetime of 30 days
const CACHE_CEILING = 2592000;
@@ -109,15 +109,15 @@ class Kohana_Cache_Memcache extends Cache {
/**
* Constructs the memcache Kohana_Cache object
*
* @param array configuration
* @throws Kohana_Cache_Exception
* @param array $config configuration
* @throws Cache_Exception
*/
protected function __construct(array $config)
{
// Check for the memcache extention
if ( ! extension_loaded('memcache'))
{
throw new Kohana_Cache_Exception('Memcache PHP extention not loaded');
throw new Cache_Exception('Memcache PHP extention not loaded');
}
parent::__construct($config);
@@ -131,7 +131,7 @@ class Kohana_Cache_Memcache extends Cache {
if ( ! $servers)
{
// Throw an exception if no server found
throw new Kohana_Cache_Exception('No Memcache servers defined in configuration');
throw new Cache_Exception('No Memcache servers defined in configuration');
}
// Setup default server configuration
@@ -155,7 +155,7 @@ class Kohana_Cache_Memcache extends Cache {
if ( ! $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'], $server['weight'], $server['timeout'], $server['retry_interval'], $server['status'], $server['failure_callback']))
{
throw new Kohana_Cache_Exception('Memcache could not connect to host \':host\' using port \':port\'', array(':host' => $server['host'], ':port' => $server['port']));
throw new Cache_Exception('Memcache could not connect to host \':host\' using port \':port\'', array(':host' => $server['host'], ':port' => $server['port']));
}
}
@@ -165,17 +165,17 @@ class Kohana_Cache_Memcache extends Cache {
/**
* Retrieve a cached value entry by id.
*
*
* // Retrieve cache entry from memcache group
* $data = Cache::instance('memcache')->get('foo');
*
*
* // Retrieve cache entry from memcache group and return 'bar' if miss
* $data = Cache::instance('memcache')->get('foo', 'bar');
*
* @param string id of cache to entry
* @param string default value to return if cache miss
* @param string $id id of cache to entry
* @param string $default default value to return if cache miss
* @return mixed
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function get($id, $default = NULL)
{
@@ -194,9 +194,9 @@ class Kohana_Cache_Memcache extends Cache {
/**
* Set a value to cache with id and lifetime
*
*
* $data = 'bar';
*
*
* // Set 'bar' to 'foo' in memcache group for 10 minutes
* if (Cache::instance('memcache')->set('foo', $data, 600))
* {
@@ -204,9 +204,9 @@ class Kohana_Cache_Memcache extends Cache {
* return
* }
*
* @param string id of cache entry
* @param mixed data to set to cache
* @param integer lifetime in seconds, maximum value 2592000
* @param string $id id of cache entry
* @param mixed $data data to set to cache
* @param integer $lifetime lifetime in seconds, maximum value 2592000
* @return boolean
*/
public function set($id, $data, $lifetime = 3600)
@@ -235,15 +235,15 @@ class Kohana_Cache_Memcache extends Cache {
/**
* Delete a cache entry based on id
*
*
* // Delete the 'foo' cache entry immediately
* Cache::instance('memcache')->delete('foo');
*
*
* // Delete the 'bar' cache entry after 30 seconds
* Cache::instance('memcache')->delete('bar', 30);
*
* @param string id of entry to delete
* @param integer timeout of entry, if zero item is deleted immediately, otherwise the item will delete after the specified value in seconds
* @param string $id id of entry to delete
* @param integer $timeout timeout of entry, if zero item is deleted immediately, otherwise the item will delete after the specified value in seconds
* @return boolean
*/
public function delete($id, $timeout = 0)
@@ -254,11 +254,11 @@ class Kohana_Cache_Memcache extends Cache {
/**
* Delete all cache entries.
*
*
* Beware of using this method when
* using shared memory cache systems, as it will wipe every
* entry within the system for all clients.
*
*
* // Delete all cache entries in the default group
* Cache::instance('memcache')->delete_all();
*
@@ -280,15 +280,15 @@ class Kohana_Cache_Memcache extends Cache {
* on a particular server fails. This method switches off that instance of the
* server if the configuration setting `instant_death` is set to `TRUE`.
*
* @param string hostname
* @param integer port
* @param string $hostname
* @param integer $port
* @return void|boolean
* @since 3.0.8
*/
public function _failed_request($hostname, $port)
{
if ( ! $this->_config['instant_death'])
return;
return;
// Setup non-existent host
$host = FALSE;
@@ -321,4 +321,34 @@ class Kohana_Cache_Memcache extends Cache {
));
}
}
/**
* Increments a given value by the step value supplied.
* Useful for shared counters and other persistent integer based
* tracking.
*
* @param string id of cache entry to increment
* @param int step value to increment by
* @return integer
* @return boolean
*/
public function increment($id, $step = 1)
{
return $this->_memcache->increment($id, $step);
}
/**
* Decrements a given value by the step value supplied.
* Useful for shared counters and other persistent integer based
* tracking.
*
* @param string id of cache entry to decrement
* @param int step value to decrement by
* @return integer
* @return boolean
*/
public function decrement($id, $step = 1)
{
return $this->_memcache->decrement($id, $step);
}
}

View File

@@ -1,21 +1,21 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* See [Kohana_Cache_Memcache]
*
*
* @package Kohana/Cache
* @category Base
* @version 2.0
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Tagging {
class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Cache_Tagging {
/**
/**
* Constructs the memcache object
*
* @param array configuration
* @throws Kohana_Cache_Exception
* @param array $config configuration
* @throws Cache_Exception
*/
protected function __construct(array $config)
{
@@ -23,21 +23,23 @@ class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Ta
if ( ! method_exists($this->_memcache, 'tag_add'))
{
throw new Kohana_Cache_Exception('Memcached-tags PHP plugin not present. Please see http://code.google.com/p/memcached-tags/ for more information');
throw new Cache_Exception('Memcached-tags PHP plugin not present. Please see http://code.google.com/p/memcached-tags/ for more information');
}
}
/**
* Set a value based on an id with tags
*
* @param string id
* @param mixed data
* @param integer lifetime [Optional]
* @param array tags [Optional]
*
* @param string $id id
* @param mixed $data data
* @param integer $lifetime lifetime [Optional]
* @param array $tags tags [Optional]
* @return boolean
*/
public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL)
{
$id = $this->_sanitize_id($id);
$result = $this->set($id, $data, $lifetime);
if ($result and $tags)
@@ -54,7 +56,7 @@ class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Ta
/**
* Delete cache entries based on a tag
*
* @param string tag
* @param string $tag tag
* @return boolean
*/
public function delete_tag($tag)
@@ -65,12 +67,12 @@ class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Ta
/**
* Find cache entries based on a tag
*
* @param string tag
* @param string $tag tag
* @return void
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function find($tag)
{
throw new Kohana_Cache_Exception('Memcached-tags does not support finding by tag');
}
throw new Cache_Exception('Memcached-tags does not support finding by tag');
}
}

View File

@@ -1,16 +1,16 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Kohana Cache Sqlite Driver
*
*
* Requires SQLite3 and PDO
*
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_Cache_GarbageCollect {
class Kohana_Cache_Sqlite extends Cache implements Cache_Tagging, Cache_GarbageCollect {
/**
* Database resource
@@ -23,8 +23,8 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
* Sets up the PDO SQLite table and
* initialises the PDO connection
*
* @param array configuration
* @throws Kohana_Cache_Exception
* @param array $config configuration
* @throws Cache_Exception
*/
protected function __construct(array $config)
{
@@ -34,7 +34,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
if ($database === NULL)
{
throw new Kohana_Cache_Exception('Database path not available in Kohana Cache configuration');
throw new Cache_Exception('Database path not available in Kohana Cache configuration');
}
// Load new Sqlite DB
@@ -50,7 +50,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
if ($database_schema === NULL)
{
throw new Kohana_Cache_Exception('Database schema not found in Kohana Cache configuration');
throw new Cache_Exception('Database schema not found in Kohana Cache configuration');
}
try
@@ -60,7 +60,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOException $e)
{
throw new Kohana_Cache_Exception('Failed to create new SQLite caches table with the following error : :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('Failed to create new SQLite caches table with the following error : :error', array(':error' => $e->getMessage()));
}
}
}
@@ -68,10 +68,10 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
/**
* Retrieve a value based on an id
*
* @param string id
* @param string default [Optional] Default value to return if id not found
* @param string $id id
* @param string $default default [Optional] Default value to return if id not found
* @return mixed
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function get($id, $default = NULL)
{
@@ -85,7 +85,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOException $e)
{
throw new Kohana_Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
}
if ( ! $result = $statement->fetch(PDO::FETCH_OBJ))
@@ -105,7 +105,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
{
// Disable notices for unserializing
$ER = error_reporting(~E_NOTICE);
// Return the valid cache data
$data = unserialize($result->cache);
@@ -120,9 +120,9 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
/**
* Set a value based on an id. Optionally add tags.
*
* @param string id
* @param mixed data
* @param integer lifetime [Optional]
* @param string $id id
* @param mixed $data data
* @param integer $lifetime lifetime [Optional]
* @return boolean
*/
public function set($id, $data, $lifetime = NULL)
@@ -133,10 +133,9 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
/**
* Delete a cache entry based on id
*
* @param string id
* @param integer timeout [Optional]
* @param string $id id
* @return boolean
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function delete($id)
{
@@ -150,7 +149,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOException $e)
{
throw new Kohana_Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
}
return (bool) $statement->rowCount();
@@ -181,13 +180,13 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
/**
* Set a value based on an id. Optionally add tags.
*
* @param string id
* @param mixed data
* @param integer lifetime [Optional]
* @param array tags [Optional]
*
* @param string $id id
* @param mixed $data data
* @param integer $lifetime lifetime [Optional]
* @param array $tags tags [Optional]
* @return boolean
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL)
{
@@ -200,7 +199,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
// Setup lifetime
if ($lifetime === NULL)
{
$lifetime = (0 === Arr::get('default_expire', NULL)) ? 0 : (Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE) + time());
$lifetime = (0 === Arr::get($this->_config, 'default_expire', NULL)) ? 0 : (Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE) + time());
}
else
{
@@ -208,7 +207,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
// Prepare statement
// $this->exists() may throw Kohana_Cache_Exception, no need to catch/rethrow
// $this->exists() may throw Cache_Exception, no need to catch/rethrow
$statement = $this->exists($id) ? $this->_db->prepare('UPDATE caches SET expiration = :expiration, cache = :cache, tags = :tags WHERE id = :id') : $this->_db->prepare('INSERT INTO caches (id, cache, expiration, tags) VALUES (:id, :cache, :expiration, :tags)');
// Try to insert
@@ -218,7 +217,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOException $e)
{
throw new Kohana_Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
}
return (bool) $statement->rowCount();
@@ -227,10 +226,9 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
/**
* Delete cache entries based on a tag
*
* @param string tag
* @param integer timeout [Optional]
* @param string $tag tag
* @return boolean
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function delete_tag($tag)
{
@@ -253,9 +251,9 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
/**
* Find cache entries based on a tag
*
* @param string tag
* @param string $tag tag
* @return array
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function find($tag)
{
@@ -272,7 +270,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOException $e)
{
throw new Kohana_Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
}
$result = array();
@@ -308,16 +306,16 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOException $e)
{
throw new Kohana_Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
}
}
/**
* Tests whether an id exists or not
*
* @param string id
* @param string $id id
* @return boolean
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
protected function exists($id)
{
@@ -328,7 +326,7 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_
}
catch (PDOExeption $e)
{
throw new Kohana_Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
}
return (bool) $statement->fetchAll();

View File

@@ -1,25 +1,25 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Kohana Cache Tagging Interface
*
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
interface Kohana_Cache_Tagging {
/**
* Set a value based on an id. Optionally add tags.
*
*
* Note : Some caching engines do not support
* tagging
*
* @param string id
* @param mixed data
* @param integer lifetime [Optional]
* @param array tags [Optional]
* @param string $id id
* @param mixed $data data
* @param integer $lifetime lifetime [Optional]
* @param array $tags tags [Optional]
* @return boolean
*/
public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL);
@@ -27,15 +27,14 @@ interface Kohana_Cache_Tagging {
/**
* Delete cache entries based on a tag
*
* @param string tag
* @param integer timeout [Optional]
* @param string $tag tag
*/
public function delete_tag($tag);
/**
* Find cache entries based on a tag
*
* @param string tag
* @param string $tag tag
* @return array
*/
public function find($tag);

View File

@@ -2,30 +2,30 @@
/**
* [Kohana Cache](api/Kohana_Cache) Wincache driver. Provides an opcode based
* driver for the Kohana Cache library.
*
*
* ### Configuration example
*
*
* Below is an example of an _wincache_ server configuration.
*
*
* return array(
* 'wincache' => array( // Driver group
* 'driver' => 'wincache', // using wincache driver
* ),
* )
*
*
* In cases where only one cache group is required, if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance.
*
*
* #### General cache group configuration settings
*
*
* Below are the settings available to all types of cache driver.
*
*
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | (_string_) The driver type to use
*
*
* ### System requirements
*
*
* * Windows XP SP3 with IIS 5.1 and » FastCGI Extension
* * Windows Server 2003 with IIS 6.0 and » FastCGI Extension
* * Windows Vista SP1 with IIS 7.0 and FastCGI Module
@@ -34,11 +34,11 @@
* * Windows Server 2008 R2 with IIS 7.5 and FastCGI Module
* * PHP 5.2.X, Non-thread-safe build
* * PHP 5.3 X86, Non-thread-safe VC9 build
*
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Wincache extends Cache {
@@ -47,14 +47,14 @@ class Kohana_Cache_Wincache extends Cache {
* Check for existence of the wincache extension This method cannot be invoked externally. The driver must
* be instantiated using the `Cache::instance()` method.
*
* @param array configuration
* @throws Kohana_Cache_Exception
* @param array $config configuration
* @throws Cache_Exception
*/
protected function __construct(array $config)
{
if ( ! extension_loaded('wincache'))
{
throw new Kohana_Cache_Exception('PHP wincache extension is not available.');
throw new Cache_Exception('PHP wincache extension is not available.');
}
parent::__construct($config);
@@ -62,17 +62,17 @@ class Kohana_Cache_Wincache extends Cache {
/**
* Retrieve a cached value entry by id.
*
*
* // Retrieve cache entry from wincache group
* $data = Cache::instance('wincache')->get('foo');
*
*
* // Retrieve cache entry from wincache group and return 'bar' if miss
* $data = Cache::instance('wincache')->get('foo', 'bar');
*
* @param string id of cache to entry
* @param string default value to return if cache miss
* @param string $id id of cache to entry
* @param string $default default value to return if cache miss
* @return mixed
* @throws Kohana_Cache_Exception
* @throws Cache_Exception
*/
public function get($id, $default = NULL)
{
@@ -83,18 +83,18 @@ class Kohana_Cache_Wincache extends Cache {
/**
* Set a value to cache with id and lifetime
*
*
* $data = 'bar';
*
*
* // Set 'bar' to 'foo' in wincache group, using default expiry
* Cache::instance('wincache')->set('foo', $data);
*
*
* // Set 'bar' to 'foo' in wincache group for 30 seconds
* Cache::instance('wincache')->set('foo', $data, 30);
*
* @param string id of cache entry
* @param string data to set to cache
* @param integer lifetime in seconds
* @param string $id id of cache entry
* @param string $data data to set to cache
* @param integer $lifetime lifetime in seconds
* @return boolean
*/
public function set($id, $data, $lifetime = NULL)
@@ -109,11 +109,11 @@ class Kohana_Cache_Wincache extends Cache {
/**
* Delete a cache entry based on id
*
*
* // Delete 'foo' entry from the wincache group
* Cache::instance('wincache')->delete('foo');
*
* @param string id to remove from cache
* @param string $id id to remove from cache
* @return boolean
*/
public function delete($id)
@@ -123,11 +123,11 @@ class Kohana_Cache_Wincache extends Cache {
/**
* Delete all cache entries.
*
*
* Beware of using this method when
* using shared memory cache systems, as it will wipe every
* entry within the system for all clients.
*
*
* // Delete all cache entries in the wincache group
* Cache::instance('wincache')->delete_all();
*

View File

@@ -0,0 +1,503 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* HTTT Caching adaptor class that provides caching services to the
* [Request_Client] class, using HTTP cache control logic as defined in
* RFC 2616.
*
* @package Kohana
* @category Base
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
* @since 3.2.0
*/
class Kohana_HTTP_Cache {
const CACHE_STATUS_KEY = 'x-cache-status';
const CACHE_STATUS_SAVED = 'SAVED';
const CACHE_STATUS_HIT = 'HIT';
const CACHE_STATUS_MISS = 'MISS';
const CACHE_HIT_KEY = 'x-cache-hits';
/**
* Factory method for HTTP_Cache that provides a convenient dependency
* injector for the Cache library.
*
* // Create HTTP_Cache with named cache engine
* $http_cache = HTTP_Cache::factory('memcache', array(
* 'allow_private_cache' => FALSE
* )
* );
*
* // Create HTTP_Cache with supplied cache engine
* $http_cache = HTTP_Cache::factory(Cache::instance('memcache'),
* array(
* 'allow_private_cache' => FALSE
* )
* );
*
* @uses [Cache]
* @param mixed $cache cache engine to use
* @param array $options options to set to this class
* @return HTTP_Cache
*/
public static function factory($cache, array $options = array())
{
if ( ! $cache instanceof Cache)
{
$cache = Cache::instance($cache);
}
$options['cache'] = $cache;
return new HTTP_Cache($options);
}
/**
* Basic cache key generator that hashes the entire request and returns
* it. This is fine for static content, or dynamic content where user
* specific information is encoded into the request.
*
* // Generate cache key
* $cache_key = HTTP_Cache::basic_cache_key_generator($request);
*
* @param Request $request
* @return string
*/
public static function basic_cache_key_generator(Request $request)
{
$uri = $request->uri();
$query = $request->query();
$headers = $request->headers()->getArrayCopy();
$body = $request->body();
return sha1($uri.'?'.http_build_query($query, NULL, '&').'~'.implode('~', $headers).'~'.$body);
}
/**
* @var Cache cache driver to use for HTTP caching
*/
protected $_cache;
/**
* @var callback Cache key generator callback
*/
protected $_cache_key_callback;
/**
* @var boolean Defines whether this client should cache `private` cache directives
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
*/
protected $_allow_private_cache = FALSE;
/**
* @var int The timestamp of the request
*/
protected $_request_time;
/**
* @var int The timestamp of the response
*/
protected $_response_time;
/**
* Constructor method for this class. Allows dependency injection of the
* required components such as `Cache` and the cache key generator.
*
* @param array $options
*/
public function __construct(array $options = array())
{
foreach ($options as $key => $value)
{
if (method_exists($this, $key))
{
$this->$key($value);
}
}
if ($this->_cache_key_callback === NULL)
{
$this->cache_key_callback('HTTP_Cache::basic_cache_key_generator');
}
}
/**
* Executes the supplied [Request] with the supplied [Request_Client].
* Before execution, the HTTP_Cache adapter checks the request type,
* destructive requests such as `POST`, `PUT` and `DELETE` will bypass
* cache completely and ensure the response is not cached. All other
* Request methods will allow caching, if the rules are met.
*
* @param Request_Client $client client to execute with Cache-Control
* @param Request $request request to execute with client
* @return [Response]
*/
public function execute(Request_Client $client, Request $request, Response $response)
{
if ( ! $this->_cache instanceof Cache)
return $client->execute_request($request, $response);
// If this is a destructive request, by-pass cache completely
if (in_array($request->method(), array(
HTTP_Request::POST,
HTTP_Request::PUT,
HTTP_Request::DELETE)))
{
// Kill existing caches for this request
$this->invalidate_cache($request);
$response = $client->execute_request($request, $response);
$cache_control = HTTP_Header::create_cache_control(array(
'no-cache',
'must-revalidate'
));
// Ensure client respects destructive action
return $response->headers('cache-control', $cache_control);
}
// Create the cache key
$cache_key = $this->create_cache_key($request, $this->_cache_key_callback);
// Try and return cached version
if (($cached_response = $this->cache_response($cache_key, $request)) instanceof Response)
return $cached_response;
// Start request time
$this->_request_time = time();
// Execute the request with the Request client
$response = $client->execute_request($request, $response);
// Stop response time
$this->_response_time = (time() - $this->_request_time);
// Cache the response
$this->cache_response($cache_key, $request, $response);
$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
HTTP_Cache::CACHE_STATUS_MISS);
return $response;
}
/**
* Invalidate a cached response for the [Request] supplied.
* This has the effect of deleting the response from the
* [Cache] entry.
*
* @param Request $request Response to remove from cache
* @return void
*/
public function invalidate_cache(Request $request)
{
if (($cache = $this->cache()) instanceof Cache)
{
$cache->delete($this->create_cache_key($request, $this->_cache_key_callback));
}
return;
}
/**
* Getter and setter for the internal caching engine,
* used to cache responses if available and valid.
*
* @param Kohana_Cache $cache engine to use for caching
* @return Kohana_Cache
* @return Kohana_Request_Client
*/
public function cache(Cache $cache = NULL)
{
if ($cache === NULL)
return $this->_cache;
$this->_cache = $cache;
return $this;
}
/**
* Gets or sets the [Request_Client::allow_private_cache] setting.
* If set to `TRUE`, the client will also cache cache-control directives
* that have the `private` setting.
*
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
* @param boolean $setting allow caching of privately marked responses
* @return boolean
* @return [Request_Client]
*/
public function allow_private_cache($setting = NULL)
{
if ($setting === NULL)
return $this->_allow_private_cache;
$this->_allow_private_cache = (bool) $setting;
return $this;
}
/**
* Sets or gets the cache key generator callback for this caching
* class. The cache key generator provides a unique hash based on the
* `Request` object passed to it.
*
* The default generator is [HTTP_Cache::basic_cache_key_generator()], which
* serializes the entire `HTTP_Request` into a unique sha1 hash. This will
* provide basic caching for static and simple dynamic pages. More complex
* algorithms can be defined and then passed into `HTTP_Cache` using this
* method.
*
* // Get the cache key callback
* $callback = $http_cache->cache_key_callback();
*
* // Set the cache key callback
* $http_cache->cache_key_callback('Foo::cache_key');
*
* // Alternatively, in PHP 5.3 use a closure
* $http_cache->cache_key_callback(function (Request $request) {
* return sha1($request->render());
* });
*
* @param callback $callback
* @return mixed
* @throws HTTP_Exception
*/
public function cache_key_callback($callback = NULL)
{
if ($callback === NULL)
return $this->_cache_key_callback;
if ( ! is_callable($callback))
throw new Kohana_Exception('cache_key_callback must be callable!');
$this->_cache_key_callback = $callback;
return $this;
}
/**
* Creates a cache key for the request to use for caching
* [Kohana_Response] returned by [Request::execute].
*
* This is the default cache key generating logic, but can be overridden
* by setting [HTTP_Cache::cache_key_callback()].
*
* @param Request $request request to create key for
* @param callback $callback optional callback to use instead of built-in method
* @return string
*/
public function create_cache_key(Request $request, $callback = FALSE)
{
if (is_callable($callback))
return call_user_func($callback, $request);
else
return HTTP_Cache::basic_cache_key_generator($request);
}
/**
* Controls whether the response can be cached. Uses HTTP
* protocol to determine whether the response can be cached.
*
* @link RFC 2616 http://www.w3.org/Protocols/rfc2616/
* @param Response $response The Response
* @return boolean
*/
public function set_cache(Response $response)
{
$headers = $response->headers()->getArrayCopy();
if ($cache_control = Arr::get($headers, 'cache-control'))
{
// Parse the cache control
$cache_control = HTTP_Header::parse_cache_control($cache_control);
// If the no-cache or no-store directive is set, return
if (array_intersect($cache_control, array('no-cache', 'no-store')))
return FALSE;
// Check for private cache and get out of here if invalid
if ( ! $this->_allow_private_cache AND in_array('private', $cache_control))
{
if ( ! isset($cache_control['s-maxage']))
return FALSE;
// If there is a s-maxage directive we can use that
$cache_control['max-age'] = $cache_control['s-maxage'];
}
// Check that max-age has been set and if it is valid for caching
if (isset($cache_control['max-age']) AND $cache_control['max-age'] < 1)
return FALSE;
}
if ($expires = Arr::get($headers, 'expires') AND ! isset($cache_control['max-age']))
{
// Can't cache things that have expired already
if (strtotime($expires) <= time())
return FALSE;
}
return TRUE;
}
/**
* Caches a [Response] using the supplied [Cache]
* and the key generated by [Request_Client::_create_cache_key].
*
* If not response is supplied, the cache will be checked for an existing
* one that is available.
*
* @param string $key the cache key to use
* @param Request $request the HTTP Request
* @param Response $response the HTTP Response
* @return mixed
*/
public function cache_response($key, Request $request, Response $response = NULL)
{
if ( ! $this->_cache instanceof Cache)
return FALSE;
// Check for Pragma: no-cache
if ($pragma = $request->headers('pragma'))
{
if ($pragma == 'no-cache')
return FALSE;
elseif (is_array($pragma) AND in_array('no-cache', $pragma))
return FALSE;
}
// If there is no response, lookup an existing cached response
if ($response === NULL)
{
$response = $this->_cache->get($key);
if ( ! $response instanceof Response)
return FALSE;
// Do cache hit arithmetic, using fast arithmetic if available
if ($this->_cache instanceof Cache_Arithmetic)
{
$hit_count = $this->_cache->increment(HTTP_Cache::CACHE_HIT_KEY.$key);
}
else
{
$hit_count = $this->_cache->get(HTTP_Cache::CACHE_HIT_KEY.$key);
$this->_cache->set(HTTP_Cache::CACHE_HIT_KEY.$key, ++$hit_count);
}
// Update the header to have correct HIT status and count
$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
HTTP_Cache::CACHE_STATUS_HIT)
->headers(HTTP_Cache::CACHE_HIT_KEY, $hit_count);
return $response;
}
else
{
if (($ttl = $this->cache_lifetime($response)) === FALSE)
return FALSE;
$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
HTTP_Cache::CACHE_STATUS_SAVED);
// Set the hit count to zero
$this->_cache->set(HTTP_Cache::CACHE_HIT_KEY.$key, 0);
return $this->_cache->set($key, $response, $ttl);
}
}
/**
* Calculates the total Time To Live based on the specification
* RFC 2616 cache lifetime rules.
*
* @param Response $response Response to evaluate
* @return mixed TTL value or false if the response should not be cached
*/
public function cache_lifetime(Response $response)
{
// Get out of here if this cannot be cached
if ( ! $this->set_cache($response))
return FALSE;
// Calculate apparent age
if ($date = $response->headers('date'))
{
$apparent_age = max(0, $this->_response_time - strtotime($date));
}
else
{
$apparent_age = max(0, $this->_response_time);
}
// Calculate corrected received age
if ($age = $response->headers('age'))
{
$corrected_received_age = max($apparent_age, intval($age));
}
else
{
$corrected_received_age = $apparent_age;
}
// Corrected initial age
$corrected_initial_age = $corrected_received_age + $this->request_execution_time();
// Resident time
$resident_time = time() - $this->_response_time;
// Current age
$current_age = $corrected_initial_age + $resident_time;
// Prepare the cache freshness lifetime
$ttl = NULL;
// Cache control overrides
if ($cache_control = $response->headers('cache-control'))
{
// Parse the cache control header
$cache_control = HTTP_Header::parse_cache_control($cache_control);
if (isset($cache_control['max-age']))
{
$ttl = $cache_control['max-age'];
}
if (isset($cache_control['s-maxage']) AND isset($cache_control['private']) AND $this->_allow_private_cache)
{
$ttl = $cache_control['s-maxage'];
}
if (isset($cache_control['max-stale']) AND ! isset($cache_control['must-revalidate']))
{
$ttl = $current_age + $cache_control['max-stale'];
}
}
// If we have a TTL at this point, return
if ($ttl !== NULL)
return $ttl;
if ($expires = $response->headers('expires'))
return strtotime($expires) - $current_age;
return FALSE;
}
/**
* Returns the duration of the last request execution.
* Either returns the time of completed requests or
* `FALSE` if the request hasn't finished executing, or
* is yet to be run.
*
* @return mixed
*/
public function request_execution_time()
{
if ($this->_request_time === NULL OR $this->_response_time === NULL)
return FALSE;
return $this->_response_time - $this->_request_time;
}
} // End Kohana_HTTP_Cache

View File

@@ -1,133 +0,0 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* [Kohana Cache](api/Kohana_Cache) Eaccelerator driver. Provides an opcode based
* driver for the Kohana Cache library.
*
* ### Configuration example
*
* Below is an example of an _eaccelerator_ server configuration.
*
* return array(
* 'eaccelerator' => array( // Driver group
* 'driver' => 'eaccelerator', // using Eaccelerator driver
* ),
* )
*
* In cases where only one cache group is required, if the group is named `default` there is
* no need to pass the group name when instantiating a cache instance.
*
* #### General cache group configuration settings
*
* Below are the settings available to all types of cache driver.
*
* Name | Required | Description
* -------------- | -------- | ---------------------------------------------------------------
* driver | __YES__ | (_string_) The driver type to use
*
* ### System requirements
*
* * Kohana 3.0.x
* * PHP 5.2.4 or greater
* * Eaccelerator PHP extension
*
* @package Kohana/Cache
* @category Base
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Eaccelerator extends Cache {
/**
* Check for existence of the eAccelerator extension This method cannot be invoked externally. The driver must
* be instantiated using the `Cache::instance()` method.
*
* @param array configuration
* @throws Kohana_Cache_Exception
*/
protected function __construct(array $config)
{
if ( ! extension_loaded('eaccelerator'))
{
throw new Kohana_Cache_Exception('PHP eAccelerator extension is not available.');
}
parent::__construct($config);
}
/**
* Retrieve a cached value entry by id.
*
* // Retrieve cache entry from eaccelerator group
* $data = Cache::instance('eaccelerator')->get('foo');
*
* // Retrieve cache entry from eaccelerator group and return 'bar' if miss
* $data = Cache::instance('eaccelerator')->get('foo', 'bar');
*
* @param string id of cache to entry
* @param string default value to return if cache miss
* @return mixed
* @throws Kohana_Cache_Exception
*/
public function get($id, $default = NULL)
{
return (($data = eaccelerator_get($this->_sanitize_id($id))) === FALSE) ? $default : $data;
}
/**
* Set a value to cache with id and lifetime
*
* $data = 'bar';
*
* // Set 'bar' to 'foo' in eaccelerator group, using default expiry
* Cache::instance('eaccelerator')->set('foo', $data);
*
* // Set 'bar' to 'foo' in eaccelerator group for 30 seconds
* Cache::instance('eaccelerator')->set('foo', $data, 30);
*
* @param string id of cache entry
* @param string data to set to cache
* @param integer lifetime in seconds
* @return boolean
*/
public function set($id, $data, $lifetime = NULL)
{
if ($lifetime === NULL)
{
$lifetime = time() + Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
}
return eaccelerator_put($this->_sanitize_id($id), $data, $lifetime);
}
/**
* Delete a cache entry based on id
*
* // Delete 'foo' entry from the eaccelerator group
* Cache::instance('eaccelerator')->delete('foo');
*
* @param string id to remove from cache
* @return boolean
*/
public function delete($id)
{
return eaccelerator_rm($this->_sanitize_id($id));
}
/**
* Delete all cache entries.
*
* Beware of using this method when
* using shared memory cache systems, as it will wipe every
* entry within the system for all clients.
*
* // Delete all cache entries in the eaccelerator group
* Cache::instance('eaccelerator')->delete_all();
*
* @return boolean
*/
public function delete_all()
{
return eaccelerator_clean();
}
}

View File

@@ -1,84 +0,0 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Kohana Cache Xcache Driver
*
* Requires Xcache
* http://xcache.lighttpd.net/
*
* @package Kohana
* @category Cache
* @author Kohana Team
* @copyright (c) 2009-2010 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_Xcache extends Cache {
/**
* Check for existence of the APC extension
*
* @param array configuration
* @throws Kohana_Cache_Exception
*/
protected function __construct(array $config)
{
if ( ! extension_loaded('xcache'))
{
throw new Kohana_Cache_Exception('PHP Xcache extension is not available.');
}
parent::__construct($config);
}
/**
* Retrieve a value based on an id
*
* @param string id
* @param string default [Optional] Default value to return if id not found
* @return mixed
*/
public function get($id, $default = NULL)
{
return (($data = xcache_get($this->_sanitize_id($id))) === NULL) ? $default : $data;
}
/**
* Set a value based on an id. Optionally add tags.
*
* @param string id
* @param string data
* @param integer lifetime [Optional]
* @return boolean
*/
public function set($id, $data, $lifetime = NULL)
{
if (NULL === $lifetime)
{
$lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
}
return xcache_set($this->_sanitize_id($id), $data, $lifetime);
}
/**
* Delete a cache entry based on id
*
* @param string id
* @param integer timeout [Optional]
* @return boolean
*/
public function delete($id)
{
return xcache_unset($this->_sanitize_id($id));
}
/**
* Delete all cache entries
* To use this method xcache.admin.enable_auth has to be Off in xcache.ini
*
* @return void
*/
public function delete_all()
{
xcache_clear_cache(XC_TYPE_PHP, 0);
}
}

View File

@@ -1,15 +1,12 @@
<?php defined('SYSPATH') or die('No direct script access.');
return array
(
'memcache' => array
(
/* 'memcache' => array(
'driver' => 'memcache',
'default_expire' => 3600,
'compression' => FALSE, // Use Zlib compression (can cause issues with integers)
'servers' => array
(
array
(
'servers' => array(
'local' => array(
'host' => 'localhost', // Memcache Server
'port' => 11211, // Memcache port number
'persistent' => FALSE, // Persistent connection
@@ -21,15 +18,12 @@ return array
),
'instant_death' => TRUE, // Take server offline immediately on first fail (no retry)
),
'memcachetag' => array
(
'memcachetag' => array(
'driver' => 'memcachetag',
'default_expire' => 3600,
'compression' => FALSE, // Use Zlib compression (can cause issues with integers)
'servers' => array
(
array
(
'servers' => array(
'local' => array(
'host' => 'localhost', // Memcache Server
'port' => 11211, // Memcache port number
'persistent' => FALSE, // Persistent connection
@@ -41,36 +35,36 @@ return array
),
'instant_death' => TRUE,
),
'apc' => array
(
'apc' => array(
'driver' => 'apc',
'default_expire' => 3600,
),
'wincache' => array
(
'wincache' => array(
'driver' => 'wincache',
'default_expire' => 3600,
),
'sqlite' => array
(
'sqlite' => array(
'driver' => 'sqlite',
'default_expire' => 3600,
'database' => APPPATH.'cache/kohana-cache.sql3',
'schema' => 'CREATE TABLE caches(id VARCHAR(127) PRIMARY KEY, tags VARCHAR(255), expiration INTEGER, cache TEXT)',
),
'eaccelerator' => array
(
'eaccelerator' => array(
'driver' => 'eaccelerator',
),
'xcache' => array
(
'xcache' => array(
'driver' => 'xcache',
'default_expire' => 3600,
),
'file' => array
(
'file' => array(
'driver' => 'file',
'cache_dir' => APPPATH.'cache',
'default_expire' => 3600,
'ignore_on_delete' => array(
'.gitignore',
'.git',
'.svn'
)
)
);
*/
);

View File

@@ -17,7 +17,7 @@ return array(
'description' => 'Common interface for caching engines.',
// Copyright message, shown in the footer for this module
'copyright' => '&copy; 20082010 Kohana Team',
'copyright' => '&copy; 20082012 Kohana Team',
)
)
);

View File

@@ -67,7 +67,7 @@ Certain cache drivers support setting values with tags. To set a value to cache
$memcache = Cache::instance('memcachetag');
// Test for tagging interface
if ($memcache instanceof Kohana_Cache_Tagging)
if ($memcache instanceof Cache_Tagging)
{
// Set a value with some tags for 30 seconds
$memcache->set('foo', $object, 30, array('snafu', 'stfu', 'fubar'));
@@ -79,7 +79,7 @@ Certain cache drivers support setting values with tags. To set a value to cache
$memcache->set('foo', $object, 30);
}
It is possible to implement custom tagging solutions onto existing or new cache drivers by implementing the [Kohana_Cache_Tagging] interface. Kohana_Cache only applies the interface to drivers that support tagging natively as standard.
It is possible to implement custom tagging solutions onto existing or new cache drivers by implementing the [Cache_Tagging] interface. Kohana_Cache only applies the interface to drivers that support tagging natively as standard.
### Getting a value from cache
@@ -115,7 +115,7 @@ It is possible to retrieve values from cache grouped by tag, using the [Cache::f
// Find values based on tag
return $cache->find('snafu');
}
catch (Kohana_Cache_Exception $e)
catch (Cache_Exception $e)
{
// Handle gracefully
return FALSE;
@@ -170,7 +170,7 @@ Some of the caching drivers support deleting by tag. This will remove all the ca
$cache = Cache::instance();
// Check for tagging interface
if ($cache instanceof Kohana_Cache_Tagging)
if ($cache instanceof Cache_Tagging)
{
// Delete all entries by the tag 'snafu'
$cache->delete_tag('snafu');
@@ -189,7 +189,7 @@ When not automated, garbage collection is the responsibility of the developer. I
$gc = 10;
// If the GC probability is a hit
if (rand(0,99) <= $gc and $cache_file instanceof Kohana_Cache_GarbageCollect)
if (rand(0,99) <= $gc and $cache_file instanceof Cache_GarbageCollect)
{
// Garbage Collect
$cache_file->garbage_collect();
@@ -199,10 +199,10 @@ When not automated, garbage collection is the responsibility of the developer. I
Kohana Cache comes with two interfaces that are implemented where the drivers support them:
- __[Kohana_Cache_Tagging] for tagging support on cache entries__
- __[Cache_Tagging] for tagging support on cache entries__
- [Cache_MemcacheTag]
- [Cache_Sqlite]
- __[Kohana_Cache_GarbageCollect] for garbage collection with drivers without native support__
- __[Cache_GarbageCollect] for garbage collection with drivers without native support__
- [Cache_File]
- [Cache_Sqlite]
@@ -212,7 +212,7 @@ When using interface specific caching features, ensure that code checks for the
$cache = Cache::instance();
// Test for Garbage Collection
if ($cache instanceof Kohana_Cache_GarbageCollect)
if ($cache instanceof Cache_GarbageCollect)
{
// Collect garbage
$cache->garbage_collect();

View File

@@ -58,7 +58,7 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
(can cause issues with integers)
'servers' => array
(
array
'local' => array
(
'host' => 'localhost', // Memcache Server
'port' => 11211, // Memcache port number
@@ -74,7 +74,7 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
(can cause issues with integers)
'servers' => array
(
array
'local' => array
(
'host' => 'localhost', // Memcache Server
'port' => 11211, // Memcache port number
@@ -102,21 +102,6 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
tags VARCHAR(255), expiration INTEGER, cache TEXT)',
),
## Eaccelerator settings
'eaccelerator' array
(
'driver' => 'eaccelerator',
),
## Xcache settings
'xcache' => array
(
'driver' => 'xcache',
'default_expire' => 3600,
),
## File settings
'file' => array
@@ -126,6 +111,15 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
'default_expire' => 3600,
)
## Wincache settings
'wincache' => array
(
'driver' => 'wincache',
'default_expire' => 3600,
),
## Override existing configuration group
The following example demonstrates how to override an existing configuration setting, using the config file in `/application/config/cache.php`.
@@ -165,4 +159,4 @@ The following example demonstrates how to add a new configuration setting, using
'driver' => 'apc', // Use Memcached as the default driver
'default_expire' => 1000, // Overide default expiry
)
);
);

View File

@@ -1,18 +1,17 @@
# About Kohana Cache
[Kohana_Cache] provides a common interface to a variety of caching engines. [Kohana_Cache_Tagging] is
[Kohana_Cache] provides a common interface to a variety of caching engines. [Cache_Tagging] is
supported where available natively to the cache system. Kohana Cache supports multiple
instances of cache engines through a grouped singleton pattern.
## Supported cache engines
* APC ([Cache_Apc])
* eAccelerator ([Cache_Eaccelerator])
* File ([Cache_File])
* Memcached ([Cache_Memcache])
* Memcached-tags ([Cache_Memcachetag])
* SQLite ([Cache_Sqlite])
* Xcache ([Cache_Xcache])
* Wincache
## Introduction to caching
@@ -45,13 +44,12 @@ Getting and setting values to cache is very simple when using the _Kohana Cache_
Driver | Storage | Speed | Tags | Distributed | Automatic Garbage Collection | Notes
---------------- | ------------ | --------- | -------- | ----------- | ---------------------------- | -----------------------
APC | __Memory__ | Excellent | No | No | Yes | Widely available PHP opcode caching solution, improves php execution performance
eAccelerator | __Memory__ | Excellent | No | No | Yes | Limited support and no longer developed. Included for legacy systems
Wincache | __Memory__ | Excellent | No | No | Yes | Windows variant of APC
File | __Disk__ | Poor | No | No | No | Marginally faster than execution
Memcache (tag) | __Memory__ | Good | No (yes) | Yes | Yes | Generally fast distributed solution, but has a speed hit due to variable network latency
Memcache (tag) | __Memory__ | Good | No (yes) | Yes | Yes | Generally fast distributed solution, but has a speed hit due to variable network latency and serialization
Sqlite | __Disk__ | Poor | Yes | No | No | Marginally faster than execution
Xcache | __Memory__ | Excellent | Yes | No | Yes | Very fast memory solution and alternative to APC
It is possible to have hybrid cache solutions that use a combination of the engines above in different contexts. This is supported with _Kohana Cache_ as well.
It is possible to have hybrid cache solutions that use a combination of the engines above in different contexts. This is supported with _Kohana Cache_ as well
## Minimum requirements

View File

@@ -67,7 +67,7 @@ Certain cache drivers support setting values with tags. To set a value to cache
$memcache = Cache::instance('memcachetag');
// Test for tagging interface
if ($memcache instanceof Kohana_Cache_Tagging)
if ($memcache instanceof Cache_Tagging)
{
// Set a value with some tags for 30 seconds
$memcache->set('foo', $object, 30, array('snafu', 'stfu', 'fubar'));
@@ -79,7 +79,7 @@ Certain cache drivers support setting values with tags. To set a value to cache
$memcache->set('foo', $object, 30);
}
It is possible to implement custom tagging solutions onto existing or new cache drivers by implementing the [Kohana_Cache_Tagging] interface. Kohana_Cache only applies the interface to drivers that support tagging natively as standard.
It is possible to implement custom tagging solutions onto existing or new cache drivers by implementing the [Cache_Tagging] interface. Kohana_Cache only applies the interface to drivers that support tagging natively as standard.
### Getting a value from cache
@@ -115,7 +115,7 @@ It is possible to retrieve values from cache grouped by tag, using the [Cache::f
// Find values based on tag
return $cache->find('snafu');
}
catch (Kohana_Cache_Exception $e)
catch (Cache_Exception $e)
{
// Handle gracefully
return FALSE;
@@ -170,7 +170,7 @@ Some of the caching drivers support deleting by tag. This will remove all the ca
$cache = Cache::instance();
// Check for tagging interface
if ($cache instanceof Kohana_Cache_Tagging)
if ($cache instanceof Cache_Tagging)
{
// Delete all entries by the tag 'snafu'
$cache->delete_tag('snafu');
@@ -189,7 +189,7 @@ When not automated, garbage collection is the responsibility of the developer. I
$gc = 10;
// If the GC probability is a hit
if (rand(0,99) <= $gc and $cache_file instanceof Kohana_Cache_GarbageCollect)
if (rand(0,99) <= $gc and $cache_file instanceof Cache_GarbageCollect)
{
// Garbage Collect
$cache_file->garbage_collect();
@@ -199,10 +199,10 @@ When not automated, garbage collection is the responsibility of the developer. I
Kohana Cache comes with two interfaces that are implemented where the drivers support them:
- __[Kohana_Cache_Tagging] for tagging support on cache entries__
- __[Cache_Tagging] for tagging support on cache entries__
- [Cache_MemcacheTag]
- [Cache_Sqlite]
- __[Kohana_Cache_GarbageCollect] for garbage collection with drivers without native support__
- __[Cache_GarbageCollect] for garbage collection with drivers without native support__
- [Cache_File]
- [Cache_Sqlite]
@@ -212,7 +212,7 @@ When using interface specific caching features, ensure that code checks for the
$cache = Cache::instance();
// Test for Garbage Collection
if ($cache instanceof Kohana_Cache_GarbageCollect)
if ($cache instanceof Cache_GarbageCollect)
{
// Collect garbage
$cache->garbage_collect();

View File

@@ -0,0 +1,299 @@
<?php
/**
* @package Kohana/Cache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_CacheBasicMethodsTest extends PHPUnit_Framework_TestCase {
/**
* @var Cache driver for this test
*/
protected $_cache_driver;
/**
* This method MUST be implemented by each driver to setup the `Cache`
* instance for each test.
*
* This method should do the following tasks for each driver test:
*
* - Test the Cache instance driver is available, skip test otherwise
* - Setup the Cache instance
* - Call the parent setup method, `parent::setUp()`
*
* @return void
*/
public function setUp()
{
parent::setUp();
}
/**
* Accessor method to `$_cache_driver`.
*
* @return Cache
* @return self
*/
public function cache(Cache $cache = NULL)
{
if ($cache === NULL)
return $this->_cache_driver;
$this->_cache_driver = $cache;
return $this;
}
/**
* Data provider for test_set_get()
*
* @return array
*/
public function provider_set_get()
{
$object = new StdClass;
$object->foo = 'foo';
$object->bar = 'bar';
$html_text = <<<TESTTEXT
<!doctype html>
<head>
</head>
<body>
</body>
</html>
TESTTEXT;
return array(
array(
array(
'id' => 'string', // Key to set to cache
'value' => 'foobar', // Value to set to key
'ttl' => 0, // Time to live
'wait' => FALSE, // Test wait time to let cache expire
'type' => 'string', // Type test
'default' => NULL // Default value get should return
),
'foobar'
),
array(
array(
'id' => 'integer',
'value' => 101010,
'ttl' => 0,
'wait' => FALSE,
'type' => 'integer',
'default' => NULL
),
101010
),
array(
array(
'id' => 'float',
'value' => 10.00,
'ttl' => 0,
'wait' => FALSE,
'type' => 'float',
'default' => NULL
),
10.00
),
array(
array(
'id' => 'array',
'value' => array(
'key' => 'foo',
'value' => 'bar'
),
'ttl' => 0,
'wait' => FALSE,
'type' => 'array',
'default' => NULL
),
array(
'key' => 'foo',
'value' => 'bar'
)
),
array(
array(
'id' => 'boolean',
'value' => TRUE,
'ttl' => 0,
'wait' => FALSE,
'type' => 'boolean',
'default' => NULL
),
TRUE
),
array(
array(
'id' => 'null',
'value' => NULL,
'ttl' => 0,
'wait' => FALSE,
'type' => 'null',
'default' => NULL
),
NULL
),
array(
array(
'id' => 'object',
'value' => $object,
'ttl' => 0,
'wait' => FALSE,
'type' => 'object',
'default' => NULL
),
$object
),
array(
array(
'id' => 'bar\\ with / troublesome key',
'value' => 'foo bar snafu',
'ttl' => 0,
'wait' => FALSE,
'type' => 'string',
'default' => NULL
),
'foo bar snafu'
),
array(
array(
'id' => 'bar',
'value' => 'foo',
'ttl' => 3,
'wait' => 5,
'type' => 'null',
'default' => NULL
),
NULL
),
array(
array(
'id' => 'snafu',
'value' => 'fubar',
'ttl' => 3,
'wait' => 5,
'type' => 'string',
'default' => 'something completely different!'
),
'something completely different!'
),
array(
array(
'id' => 'new line test with HTML',
'value' => $html_text,
'ttl' => 10,
'wait' => FALSE,
'type' => 'string',
'default' => NULL,
),
$html_text
)
);
}
/**
* Tests the [Cache::set()] method, testing;
*
* - The value is cached
* - The lifetime is respected
* - The returned value type is as expected
* - The default not-found value is respected
*
* @dataProvider provider_set_get
*
* @param array data
* @param mixed expected
* @return void
*/
public function test_set_get(array $data, $expected)
{
$cache = $this->cache();
extract($data);
$this->assertTrue($cache->set($id, $value, $ttl));
if ($wait !== FALSE)
{
// Lets let the cache expire
sleep($wait);
}
$result = $cache->get($id, $default);
$this->assertEquals($expected, $result);
$this->assertInternalType($type, $result);
unset($id, $value, $ttl, $wait, $type, $default);
}
/**
* Tests the [Cache::delete()] method, testing;
*
* - The a cached value is deleted from cache
* - The cache returns a TRUE value upon deletion
* - The cache returns a FALSE value if no value exists to delete
*
* @return void
*/
public function test_delete()
{
// Init
$cache = $this->cache();
$cache->delete_all();
// Test deletion if real cached value
if ( ! $cache->set('test_delete_1', 'This should not be here!', 0))
{
$this->fail('Unable to set cache value to delete!');
}
// Test delete returns TRUE and check the value is gone
$this->assertTrue($cache->delete('test_delete_1'));
$this->assertNull($cache->get('test_delete_1'));
// Test non-existant cache value returns FALSE if no error
$this->assertFalse($cache->delete('test_delete_1'));
}
/**
* Tests [Cache::delete_all()] works as specified
*
* @return void
* @uses Kohana_CacheBasicMethodsTest::provider_set_get()
*/
public function test_delete_all()
{
// Init
$cache = $this->cache();
$data = $this->provider_set_get();
foreach ($data as $key => $values)
{
extract($values[0]);
if ( ! $cache->set($id, $value))
{
$this->fail('Unable to set: '.$key.' => '.$value.' to cache');
}
unset($id, $value, $ttl, $wait, $type, $default);
}
// Test delete_all is successful
$this->assertTrue($cache->delete_all());
foreach ($data as $key => $values)
{
// Verify data has been purged
$this->assertSame('Cache Deleted!', $cache->get($values[0]['id'],
'Cache Deleted!'));
}
}
} // End Kohana_CacheBasicMethodsTest

View File

@@ -0,0 +1,242 @@
<?php
/**
* @package Kohana/Cache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_CacheTest extends PHPUnit_Framework_TestCase {
const BAD_GROUP_DEFINITION = 1010;
const EXPECT_SELF = 1001;
/**
* Data provider for test_instance
*
* @return array
*/
public function provider_instance()
{
$tmp = realpath(sys_get_temp_dir());
$base = array();
if (Kohana::$config->load('cache.file'))
{
$base = array(
// Test default group
array(
NULL,
Cache::instance('file')
),
// Test defined group
array(
'file',
Cache::instance('file')
),
);
}
return array(
// Test bad group definition
$base+array(
Kohana_CacheTest::BAD_GROUP_DEFINITION,
'Failed to load Kohana Cache group: 1010'
),
);
}
/**
* Tests the [Cache::factory()] method behaves as expected
*
* @dataProvider provider_instance
*
* @return void
*/
public function test_instance($group, $expected)
{
if (in_array($group, array(
Kohana_CacheTest::BAD_GROUP_DEFINITION,
)
))
{
$this->setExpectedException('Cache_Exception');
}
try
{
$cache = Cache::instance($group);
}
catch (Cache_Exception $e)
{
$this->assertSame($expected, $e->getMessage());
throw $e;
}
$this->assertInstanceOf(get_class($expected), $cache);
$this->assertSame($expected->config(), $cache->config());
}
/**
* Tests that `clone($cache)` will be prevented to maintain singleton
*
* @return void
* @expectedException Cache_Exception
*/
public function test_cloning_fails()
{
if ( ! Kohana::$config->load('cache.file'))
{
$this->markTestSkipped('Unable to load File configuration');
}
try
{
$cache_clone = clone(Cache::instance('file'));
}
catch (Cache_Exception $e)
{
$this->assertSame('Cloning of Kohana_Cache objects is forbidden',
$e->getMessage());
throw $e;
}
}
/**
* Data provider for test_config
*
* @return array
*/
public function provider_config()
{
return array(
array(
array(
'server' => 'otherhost',
'port' => 5555,
'persistent' => TRUE,
),
NULL,
Kohana_CacheTest::EXPECT_SELF,
array(
'server' => 'otherhost',
'port' => 5555,
'persistent' => TRUE,
),
),
array(
'foo',
'bar',
Kohana_CacheTest::EXPECT_SELF,
array(
'foo' => 'bar'
)
),
array(
'server',
NULL,
NULL,
array()
),
array(
NULL,
NULL,
array(),
array()
)
);
}
/**
* Tests the config method behaviour
*
* @dataProvider provider_config
*
* @param mixed key value to set or get
* @param mixed value to set to key
* @param mixed expected result from [Cache::config()]
* @param array expected config within cache
* @return void
*/
public function test_config($key, $value, $expected_result, array $expected_config)
{
$cache = $this->getMock('Cache_File', NULL, array(), '', FALSE);
if ($expected_result === Kohana_CacheTest::EXPECT_SELF)
{
$expected_result = $cache;
}
$this->assertSame($expected_result, $cache->config($key, $value));
$this->assertSame($expected_config, $cache->config());
}
/**
* Data provider for test_sanitize_id
*
* @return array
*/
public function provider_sanitize_id()
{
return array(
array(
'foo',
'foo'
),
array(
'foo+-!@',
'foo+-!@'
),
array(
'foo/bar',
'foo_bar',
),
array(
'foo\\bar',
'foo_bar'
),
array(
'foo bar',
'foo_bar'
),
array(
'foo\\bar snafu/stfu',
'foo_bar_snafu_stfu'
)
);
}
/**
* Tests the [Cache::_sanitize_id()] method works as expected.
* This uses some nasty reflection techniques to access a protected
* method.
*
* @dataProvider provider_sanitize_id
*
* @param string id
* @param string expected
* @return void
*/
public function test_sanitize_id($id, $expected)
{
$cache = $this->getMock('Cache', array(
'get',
'set',
'delete',
'delete_all'
), array(array()),
'', FALSE
);
$cache_reflection = new ReflectionClass($cache);
$sanitize_id = $cache_reflection->getMethod('_sanitize_id');
$sanitize_id->setAccessible(TRUE);
$this->assertSame($expected, $sanitize_id->invoke($cache, $id));
}
} // End Kohana_CacheTest

View File

@@ -0,0 +1,98 @@
<?php
include_once(Kohana::find_file('tests/cache', 'CacheBasicMethodsTest'));
/**
* @package Kohana/Cache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Cache_FileTest extends Kohana_CacheBasicMethodsTest {
/**
* This method MUST be implemented by each driver to setup the `Cache`
* instance for each test.
*
* This method should do the following tasks for each driver test:
*
* - Test the Cache instance driver is available, skip test otherwise
* - Setup the Cache instance
* - Call the parent setup method, `parent::setUp()`
*
* @return void
*/
public function setUp()
{
parent::setUp();
if ( ! Kohana::$config->load('cache.file'))
{
$this->markTestSkipped('Unable to load File configuration');
}
$this->cache(Cache::instance('file'));
}
/**
* Tests that ignored files are not removed from file cache
*
* @return void
*/
public function test_ignore_delete_file()
{
$cache = $this->cache();
$config = Kohana::$config->load('cache')->file;
$file = $config['cache_dir'].'/.gitignore';
// Lets pollute the cache folder
file_put_contents($file, 'foobar');
$this->assertTrue($cache->delete_all());
$this->assertTrue(file_exists($file));
$this->assertEquals('foobar', file_get_contents($file));
unlink($file);
}
/**
* Provider for test_utf8
*
* @return array
*/
public function provider_utf8()
{
return array(
array(
'This is â ütf-8 Ӝ☃ string',
'This is â ütf-8 Ӝ☃ string'
),
array(
'㆓㆕㆙㆛',
'㆓㆕㆙㆛'
),
array(
'அஆஇஈஊ',
'அஆஇஈஊ'
)
);
}
/**
* Tests the file driver supports utf-8 strings
*
* @dataProvider provider_utf8
*
* @return void
*/
public function test_utf8($input, $expected)
{
$cache = $this->cache();
$cache->set('utf8', $input);
$this->assertSame($expected, $cache->get('utf8'));
}
} // End Kohana_SqliteTest

View File

@@ -1,91 +0,0 @@
<?php
class KohanaCacheTest extends PHPUnit_Framework_TestCase {
static protected $test_instance;
public function setUp()
{
self::$test_instance = Cache::instance('file');
self::$test_instance->delete_all();
self::$test_instance->set('testGet1', 'foo', 3600);
}
public function tearDown()
{
self::$test_instance->delete_all();
self::$test_instance = NULL;
}
/**
* Tests the cache static instance method
*/
public function testInstance()
{
$file_instance = Cache::instance('file');
$file_instance2 = Cache::instance('file');
// Try and load a Cache instance
$this->assertType('Kohana_Cache', Cache::instance());
$this->assertType('Kohana_Cache_File', $file_instance);
// Test instances are only initialised once
$this->assertTrue(spl_object_hash($file_instance) == spl_object_hash($file_instance2));
// Test the publically accessible Cache instance store
$this->assertTrue(spl_object_hash(Cache::$instances['file']) == spl_object_hash($file_instance));
// Get the constructor method
$constructorMethod = new ReflectionMethod($file_instance, '__construct');
// Test the constructor for hidden visibility
$this->assertTrue($constructorMethod->isProtected(), '__construct is does not have protected visibility');
}
public function testGet()
{
// Try and get a non property
$this->assertNull(self::$test_instance->get('testGet0'));
// Try and get a non property with default return value
$this->assertEquals('bar', self::$test_instance->get('testGet0', 'bar'));
// Try and get a real cached property
$this->assertEquals('foo', self::$test_instance->get('testGet1'));
}
public function testSet()
{
$value = 'foobar';
$value2 = 'snafu';
// Set a new property
$this->assertTrue(self::$test_instance->set('testSet1', $value));
// Test the property exists
$this->assertEquals(self::$test_instance->get('testSet1'), $value);
// Test short set
$this->assertTrue(self::$test_instance->set('testSet2', $value2, 3));
// Test the property exists
$this->assertEquals(self::$test_instance->get('testSet2'), $value2);
// Allow test2 to expire
sleep(4);
// Test the property has expired
$this->assertNull(self::$test_instance->get('testSet2'));
}
public function testDelete()
{
}
public function testDeleteAll()
{
}
}

View File

@@ -0,0 +1,44 @@
<?php
include_once(Kohana::find_file('tests/cache', 'CacheBasicMethodsTest'));
/**
* @package Kohana/Cache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_SqliteTest extends Kohana_CacheBasicMethodsTest {
/**
* This method MUST be implemented by each driver to setup the `Cache`
* instance for each test.
*
* This method should do the following tasks for each driver test:
*
* - Test the Cache instance driver is available, skip test otherwise
* - Setup the Cache instance
* - Call the parent setup method, `parent::setUp()`
*
* @return void
*/
public function setUp()
{
parent::setUp();
if ( ! extension_loaded('pdo_sqlite'))
{
$this->markTestSkipped('SQLite PDO PHP Extension is not available');
}
if ( ! Kohana::$config->load('cache.sqlite'))
{
$this->markTestIncomplete('Unable to load sqlite configuration');
}
$this->cache(Cache::instance('sqlite'));
}
} // End Kohana_SqliteTest

View File

@@ -0,0 +1,39 @@
<?php
include_once(Kohana::find_file('tests/cache', 'CacheBasicMethodsTest'));
/**
* @package Kohana/Cache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_WincacheTest extends Kohana_CacheBasicMethodsTest {
/**
* This method MUST be implemented by each driver to setup the `Cache`
* instance for each test.
*
* This method should do the following tasks for each driver test:
*
* - Test the Cache instance driver is available, skip test otherwise
* - Setup the Cache instance
* - Call the parent setup method, `parent::setUp()`
*
* @return void
*/
public function setUp()
{
parent::setUp();
if ( ! extension_loaded('wincache'))
{
$this->markTestSkipped('Wincache PHP Extension is not available');
}
$this->cache(Cache::instance('wincache'));
}
} // End Kohana_WincacheTest

View File

@@ -0,0 +1,75 @@
<?php
include_once(Kohana::find_file('tests/cache/arithmetic', 'CacheArithmeticMethods'));
/**
* @package Kohana/Cache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_ApcTest extends Kohana_CacheArithmeticMethodsTest {
/**
* This method MUST be implemented by each driver to setup the `Cache`
* instance for each test.
*
* This method should do the following tasks for each driver test:
*
* - Test the Cache instance driver is available, skip test otherwise
* - Setup the Cache instance
* - Call the parent setup method, `parent::setUp()`
*
* @return void
*/
public function setUp()
{
parent::setUp();
if ( ! extension_loaded('apc'))
{
$this->markTestSkipped('APC PHP Extension is not available');
}
if (ini_get('apc.enable_cli') != '1')
{
$this->markTestSkipped('Unable to test APC in CLI mode. To fix '.
'place "apc.enable_cli=1" in your php.ini file');
}
$this->cache(Cache::instance('apc'));
}
/**
* Tests the [Cache::set()] method, testing;
*
* - The value is cached
* - The lifetime is respected
* - The returned value type is as expected
* - The default not-found value is respected
*
* This test doesn't test the TTL as there is a known bug/feature
* in APC that prevents the same request from killing cache on timeout.
*
* @link http://pecl.php.net/bugs/bug.php?id=16814
*
* @dataProvider provider_set_get
*
* @param array data
* @param mixed expected
* @return void
*/
public function test_set_get(array $data, $expected)
{
if ($data['wait'] !== FALSE)
{
$this->markTestSkipped('Unable to perform TTL test in CLI, see: '.
'http://pecl.php.net/bugs/bug.php?id=16814 for more info!');
}
parent::test_set_get($data, $expected);
}
} // End Kohana_ApcTest

View File

@@ -0,0 +1,173 @@
<?php
include_once(Kohana::find_file('tests/cache', 'CacheBasicMethodsTest'));
/**
* @package Kohana/Cache/Memcache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_CacheArithmeticMethodsTest extends Kohana_CacheBasicMethodsTest {
public function tearDown()
{
parent::tearDown();
// Cleanup
$cache = $this->cache();
if ($cache instanceof Cache)
{
$cache->delete_all();
}
}
/**
* Provider for test_increment
*
* @return array
*/
public function provider_increment()
{
return array(
array(
0,
array(
'id' => 'increment_test_1',
'step' => 1
),
1
),
array(
1,
array(
'id' => 'increment_test_2',
'step' => 1
),
2
),
array(
5,
array(
'id' => 'increment_test_3',
'step' => 5
),
10
),
array(
NULL,
array(
'id' => 'increment_test_4',
'step' => 1
),
FALSE
),
);
}
/**
* Test for [Cache_Arithmetic::increment()]
*
* @dataProvider provider_increment
*
* @param integer start state
* @param array increment arguments
* @return void
*/
public function test_increment(
$start_state = NULL,
array $inc_args,
$expected)
{
$cache = $this->cache();
if ($start_state !== NULL)
{
$cache->set($inc_args['id'], $start_state, 0);
}
$this->assertSame(
$expected,
$cache->increment(
$inc_args['id'],
$inc_args['step']
)
);
}
/**
* Provider for test_decrement
*
* @return array
*/
public function provider_decrement()
{
return array(
array(
10,
array(
'id' => 'decrement_test_1',
'step' => 1
),
9
),
array(
10,
array(
'id' => 'decrement_test_2',
'step' => 2
),
8
),
array(
50,
array(
'id' => 'decrement_test_3',
'step' => 5
),
45
),
array(
NULL,
array(
'id' => 'decrement_test_4',
'step' => 1
),
FALSE
),
); }
/**
* Test for [Cache_Arithmetic::decrement()]
*
* @dataProvider provider_decrement
*
* @param integer start state
* @param array decrement arguments
* @return void
*/
public function test_decrement(
$start_state = NULL,
array $dec_args,
$expected)
{
$cache = $this->cache();
if ($start_state !== NULL)
{
$cache->set($dec_args['id'], $start_state, 0);
}
$this->assertSame(
$expected,
$cache->decrement(
$dec_args['id'],
$dec_args['step']
)
);
}
} // End Kohana_CacheArithmeticMethodsTest

View File

@@ -0,0 +1,103 @@
<?php
include_once(Kohana::find_file('tests/cache/arithmetic', 'CacheArithmeticMethods'));
/**
* @package Kohana/Cache/Memcache
* @group kohana
* @group kohana.cache
* @category Test
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_CacheArithmeticMemcacheTest extends Kohana_CacheArithmeticMethodsTest {
/**
* This method MUST be implemented by each driver to setup the `Cache`
* instance for each test.
*
* This method should do the following tasks for each driver test:
*
* - Test the Cache instance driver is available, skip test otherwise
* - Setup the Cache instance
* - Call the parent setup method, `parent::setUp()`
*
* @return void
*/
public function setUp()
{
parent::setUp();
if ( ! extension_loaded('memcache'))
{
$this->markTestSkipped('Memcache PHP Extension is not available');
}
if ( ! $config = Kohana::$config->load('cache.memcache'))
{
$this->markTestSkipped('Unable to load Memcache configuration');
}
$memcache = new Memcache;
if ( ! $memcache->connect($config['servers']['local']['host'],
$config['servers']['local']['port']))
{
$this->markTestSkipped('Unable to connect to memcache server @ '.
$config['servers']['local']['host'].':'.
$config['servers']['local']['port']);
}
if ($memcache->getVersion() === FALSE)
{
$this->markTestSkipped('Memcache server @ '.
$config['servers']['local']['host'].':'.
$config['servers']['local']['port'].
' not responding!');
}
unset($memcache);
$this->cache(Cache::instance('memcache'));
}
/**
* Tests that multiple values set with Memcache do not cause unexpected
* results. For accurate results, this should be run with a memcache
* configuration that includes multiple servers.
*
* This is to test #4110
*
* @link http://dev.kohanaframework.org/issues/4110
* @return void
*/
public function test_multiple_set()
{
$cache = $this->cache();
$id_set = 'set_id';
$ttl = 300;
$data = array(
'foobar',
0,
1.0,
new stdClass,
array('foo', 'bar' => 1),
TRUE,
NULL,
FALSE
);
$previous_set = $cache->get($id_set, NULL);
foreach ($data as $value)
{
// Use Equals over Sames as Objects will not be equal
$this->assertEquals($previous_set, $cache->get($id_set, NULL));
$cache->set($id_set, $value, $ttl);
$previous_set = $value;
}
}
} // End Kohana_CacheArithmeticMemcacheTest

View File

@@ -0,0 +1,265 @@
<?php defined('SYSPATH') OR die('Kohana bootstrap needs to be included before tests run');
/**
* Unit tests for request client cache logic
*
* @group kohana
* @group kohana.request
* @group kohana.request.client
* @group kohana.request.client.cache
*
* @package Kohana
* @category Tests
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Request_Client_CacheTest extends Unittest_TestCase {
/**
* Sets up a test route for caching
*
* @return void
*/
public function setUp()
{
Route::set('welcome', 'welcome/index')
->defaults(array(
'controller' => 'welcome',
'action' => 'index'
));
parent::setUp();
}
/**
* Tests the Client does not attempt to load cache if no Cache library
* is present
*
* @return void
*/
public function test_cache_not_called_with_no_cache()
{
$request = new Request('welcome/index');
$response = new Response;
$client_mock = $this->getMock('Request_Client_Internal');
$request->client($client_mock);
$client_mock->expects($this->exactly(0))
->method('execute_request');
$client_mock->expects($this->once())
->method('execute')
->will($this->returnValue($response));
$this->assertSame($response, $request->execute());
}
/**
* Tests that the client attempts to load a cached response from the
* cache library, but fails.
*
* @return void
*/
public function test_cache_miss()
{
$route = new Route('welcome/index');
$route->defaults(array(
'controller' => 'Kohana_Request_CacheTest_Dummy',
'action' => 'index',
));
$request = new Request('welcome/index', NULL, array($route));
$cache_mock = $this->_get_cache_mock();
$request->client()->cache(HTTP_Cache::factory($cache_mock));
$cache_mock->expects($this->once())
->method('get')
->with($request->client()->cache()->create_cache_key($request))
->will($this->returnValue(FALSE));
$response = $request->client()->execute($request);
$this->assertSame(HTTP_Cache::CACHE_STATUS_MISS,
$response->headers(HTTP_Cache::CACHE_STATUS_KEY));
}
/**
* Tests the client saves a response if the correct headers are set
*
* @return void
*/
public function test_cache_save()
{
$lifetime = 800;
$request = new Request('welcome/index');
$cache_mock = $this->_get_cache_mock();
$response = Response::factory();
$request->client()->cache(new HTTP_Cache(array(
'cache' => $cache_mock
)
));
$response->headers('cache-control', 'max-age='.$lifetime);
$key = $request->client()->cache()->create_cache_key($request);
$cache_mock->expects($this->at(0))
->method('set')
->with($this->stringEndsWith($key), $this->identicalTo(0));
$cache_mock->expects($this->at(1))
->method('set')
->with($this->identicalTo($key), $this->anything(), $this->identicalTo($lifetime))
->will($this->returnValue(TRUE));
$this->assertTrue(
$request->client()->cache()
->cache_response($key, $request, $response)
);
$this->assertSame(HTTP_Cache::CACHE_STATUS_SAVED,
$response->headers(HTTP_Cache::CACHE_STATUS_KEY));
}
/**
* Tests the client handles a cache HIT event correctly
*
* @return void
*/
public function test_cache_hit()
{
$lifetime = 800;
$request = new Request('welcome/index');
$cache_mock = $this->_get_cache_mock();
$request->client()->cache(new HTTP_Cache(array(
'cache' => $cache_mock
)
));
$response = Response::factory();
$response->headers(array(
'cache-control' => 'max-age='.$lifetime,
HTTP_Cache::CACHE_STATUS_KEY =>
HTTP_Cache::CACHE_STATUS_HIT
));
$key = $request->client()->cache()->create_cache_key($request);
$cache_mock->expects($this->exactly(2))
->method('get')
->with($this->stringContains($key))
->will($this->returnValue($response));
$request->client()->cache()->cache_response($key, $request);
$this->assertSame(HTTP_Cache::CACHE_STATUS_HIT,
$response->headers(HTTP_Cache::CACHE_STATUS_KEY));
}
/**
* Data provider for test_set_cache
*
* @return array
*/
public function provider_set_cache()
{
return array(
array(
new HTTP_Header(array('cache-control' => 'no-cache')),
array('no-cache' => NULL),
FALSE,
),
array(
new HTTP_Header(array('cache-control' => 'no-store')),
array('no-store' => NULL),
FALSE,
),
array(
new HTTP_Header(array('cache-control' => 'max-age=100')),
array('max-age' => '100'),
TRUE
),
array(
new HTTP_Header(array('cache-control' => 'private')),
array('private' => NULL),
FALSE
),
array(
new HTTP_Header(array('cache-control' => 'private, max-age=100')),
array('private' => NULL, 'max-age' => '100'),
FALSE
),
array(
new HTTP_Header(array('cache-control' => 'private, s-maxage=100')),
array('private' => NULL, 's-maxage' => '100'),
TRUE
),
array(
new HTTP_Header(array(
'expires' => date('m/d/Y', strtotime('-1 day')),
)),
array(),
FALSE
),
array(
new HTTP_Header(array(
'expires' => date('m/d/Y', strtotime('+1 day')),
)),
array(),
TRUE
),
array(
new HTTP_Header(array()),
array(),
TRUE
),
);
}
/**
* Tests the set_cache() method
*
* @test
* @dataProvider provider_set_cache
*
* @return null
*/
public function test_set_cache($headers, $cache_control, $expected)
{
/**
* Set up a mock response object to test with
*/
$response = $this->getMock('Response');
$response->expects($this->any())
->method('headers')
->will($this->returnValue($headers));
$request = new Request_Client_Internal;
$request->cache(new HTTP_Cache);
$this->assertEquals($request->cache()->set_cache($response), $expected);
}
/**
* Returns a mock object for Cache
*
* @return Cache
*/
protected function _get_cache_mock()
{
return $this->getMock('Cache_File', array(), array(), '', FALSE);
}
} // End Kohana_Request_Client_CacheTest
class Controller_Kohana_Request_CacheTest_Dummy extends Controller
{
public function action_index()
{
}
}

View File

@@ -7,7 +7,10 @@
Any options you specify when calling phpunit will override the ones in here
-->
<phpunit colors="true" bootstrap="../../../articles/public/index.php">
<php>
<includePath>./cache</includePath>
</php>
<phpunit colors="true" bootstrap="/path/to/your/unittest/bootstrap.php">
<testsuites>
<testsuite name="Kohana Cache Tests">
<directory suffix=".php">cache/</directory>