From 08a9b4dc62e3043dfcaf2c5d855f6ab7ad9b8554 Mon Sep 17 00:00:00 2001 From: Falko Joseph Date: Fri, 18 Dec 2020 18:19:26 +0100 Subject: [PATCH] add file system cache --- vendor/jdorn/file-system-cache | 1 - vendor/jdorn/file-system-cache/.gitignore | 4 + vendor/jdorn/file-system-cache/.travis.yml | 6 + vendor/jdorn/file-system-cache/README.md | 200 +++++++++ vendor/jdorn/file-system-cache/composer.json | 27 ++ .../file-system-cache/lib/FileSystemCache.php | 420 ++++++++++++++++++ .../jdorn/file-system-cache/phpunit.xml.dist | 20 + .../tests/FileSystemCacheTest.php | 279 ++++++++++++ 8 files changed, 956 insertions(+), 1 deletion(-) delete mode 160000 vendor/jdorn/file-system-cache create mode 100644 vendor/jdorn/file-system-cache/.gitignore create mode 100644 vendor/jdorn/file-system-cache/.travis.yml create mode 100644 vendor/jdorn/file-system-cache/README.md create mode 100644 vendor/jdorn/file-system-cache/composer.json create mode 100644 vendor/jdorn/file-system-cache/lib/FileSystemCache.php create mode 100644 vendor/jdorn/file-system-cache/phpunit.xml.dist create mode 100644 vendor/jdorn/file-system-cache/tests/FileSystemCacheTest.php diff --git a/vendor/jdorn/file-system-cache b/vendor/jdorn/file-system-cache deleted file mode 160000 index 08f33ff8..00000000 --- a/vendor/jdorn/file-system-cache +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 08f33ff840ec4728a0bd28e4d68d97635584952e diff --git a/vendor/jdorn/file-system-cache/.gitignore b/vendor/jdorn/file-system-cache/.gitignore new file mode 100644 index 00000000..acfe4dfa --- /dev/null +++ b/vendor/jdorn/file-system-cache/.gitignore @@ -0,0 +1,4 @@ +cache/ +examples/cache/ +vendor/ +tests/cache/ diff --git a/vendor/jdorn/file-system-cache/.travis.yml b/vendor/jdorn/file-system-cache/.travis.yml new file mode 100644 index 00000000..4b5255aa --- /dev/null +++ b/vendor/jdorn/file-system-cache/.travis.yml @@ -0,0 +1,6 @@ +language: php +php: + - 5.4 + - 5.3 +before_script: mkdir tests/cache; mkdir tests/cache/test; mkdir tests/cache/test2; mkdir tests/cache/test/test; chmod -R 777 tests/cache; +script: phpunit --coverage-text diff --git a/vendor/jdorn/file-system-cache/README.md b/vendor/jdorn/file-system-cache/README.md new file mode 100644 index 00000000..80c4113c --- /dev/null +++ b/vendor/jdorn/file-system-cache/README.md @@ -0,0 +1,200 @@ +FileSystemCache +=============== + +A simple PHP class for caching data in the filesystem. Major features include: + +* Support for TTL when storing data +* Support for "Newer Than" parameter when retrieving data +* Every call is an atomic operation with proper file locking +* Can group cache keys together for easy invalidation +* Composer support +* PHPUnit tests + +[![Build Status](https://secure.travis-ci.org/jdorn/FileSystemCache.png?branch=master)](http://travis-ci.org/jdorn/FileSystemCache) + +Getting Started +------------------ +FileSystemCache can be installed with Composer or downloaded manually. + +### With Composer + +If you're already using Composer, just add `jdorn/file-system-cache` to your `composer.json` file. +FileSystemCache works with Composer's autoloader out of the bat. +```js +{ + "require": { + "jdorn/file-system-cache": "dev-master" + } +} +``` + +### Manually + +If you aren't using Composer, you just need to include `lib/FileSystemCache.php` in your script. + +```php +require_once("path/to/FileSystemCache.php"); +``` + +Setting the Cache Directory +----------------------- + +By default, all cached data is stored in the `cache` directory relative to the currently executing script. +You can change this by setting the $cacheDir static property. + +```php +1001, + 'ip address'=>'10.1.1.1' +); + +//string +$key_data = 'my_key'; + +//object +$key_data = new SomeObject(); + +//number +$key_data = 1005; + + +//generate a key object +$key = FileSystemCache::generateCacheKey($key_data); +``` + +You can group cache keys together to better organize your data and make invalidation easier. + +```php +'is some data I want to cache', + 'it'=>'can be a string, array, object, or number.' +); + +$key = FileSystemCache::generateCacheKey('mykey'); + +FileSystemCache::store($key, $data); +``` + +If you want the data to expire automatically after a set amount of time, use the optional `ttl` parameter. + +```php +// Expire automatically after 1 hour (3600 seconds) +FileSystemCache::store($key, $data, 3600); +``` + +Retrieve +-------------------- +You retrieve data using the same cache key you used to store it. `False` will be returned if the data was not cached or expired. + +```php +$data = FileSystemCache::retrieve($key); + +// If there was a cache miss +if($data === false) { + ... +} +``` + +You can specify a `newer than` timestamp to only retrieve cached data that was stored after a certain time. +This is useful for storing a compiled version of a source file. + +```php +$file = 'source_file.txt'; +$modified = filemtime($file); + +$key = FileSystemCache::generateCacheKey($file); + +$data = FileSystemCache::retrieve($key, $modified); + +// If there was a cache miss +if($data === false) { + ... +} +``` + +Get and Modify +------------------ +There is an atomic `Get and Modify` method as well. + +```php +FileSystemCache::getAndModify($key, function($value) { + $value->count++; + + return $value; +}); +``` + +If the data was originally cached with a TTL, you can pass `true` as the 3rd parameter to resset the TTL. +Otherwise, it will be based on the original time it was stored. + + +Invalidate +------------------- +You can invalidate a single cache key or a group of cache keys. + +```php +FileSystemCache::invalidate($key); + +FileSystemCache::invalidateGroup('mygroup'); +``` + +Invalidating a group is done recursively by default and all sub-groups will also be invalidated. +If you pass `false` as the 2nd parameter, you can make it non-recursive. + +```php +FileSystemCache::invalidateGroup('mygroup', false); +``` + +Running the Tests +------------------ +You need PHPUnit installed to run the tests. Configuration is defined in `phpunit.xml.dist`. Running the tests is easy: + +``` +phpunit +``` diff --git a/vendor/jdorn/file-system-cache/composer.json b/vendor/jdorn/file-system-cache/composer.json new file mode 100644 index 00000000..09c516a7 --- /dev/null +++ b/vendor/jdorn/file-system-cache/composer.json @@ -0,0 +1,27 @@ +{ + "name": "jdorn/file-system-cache", + "description": "an easy way to cache data in the file system", + "homepage": "https://github.com/jdorn/FileSystemCache/", + "keywords": ["cache", "file system"], + "minimum-stability": "dev", + "license": "LGPL", + "type": "library", + "require": { + "php": ">=5.3.0" + }, + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "http://jeremydorn.com/" + } + ], + "autoload": { + "classmap": ["lib"] + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/jdorn/file-system-cache/lib/FileSystemCache.php b/vendor/jdorn/file-system-cache/lib/FileSystemCache.php new file mode 100644 index 00000000..0e13a054 --- /dev/null +++ b/vendor/jdorn/file-system-cache/lib/FileSystemCache.php @@ -0,0 +1,420 @@ + + * @copyright 2012 Jeremy Dorn + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://github.com/jdorn/FileSystemCache + * @version 1.0.0 + */ +class FileSystemCache { + /** + * The root cache directory. Everything will be cached relative to this directory. + * @var string + */ + public static $cacheDir = 'cache'; + + /** + * Generates a cache key to use with store, retrieve, getAndModify, and invalidate + * @param mixed $key_data Unique data that identifies the key. Can be a string, array, number, or object. + * @param String $group An optional group to put the cache key in. Must be in the format "groupname" or "groupname/subgroupname". + * @return FileSystemCacheKey The cache key object. + */ + public static function generateCacheKey($key_data, $group=null) { + return new FileSystemCacheKey($key_data,$group); + } + + /** + * Stores data in the cache + * @param FileSystemCacheKey $key The cache key + * @param mixed $data The data to store (will be serialized before storing) + * @param int $ttl The number of seconds until the cache expires. (optional) + * @return boolean True on success, false on failure + */ + public static function store(FileSystemCacheKey $key, $data, $ttl=null) { + $filename = $key->getFileName(); + + $data = new FileSystemCacheValue($key,$data,$ttl); + + $fh = self::getFileHandle($filename,'c'); + + if(!$fh) return false; + + if(!self::putContents($fh,$data)) return false; + + return true; + } + + /** + * Retrieve data from cache + * @param FileSystemCacheKey $key The cache key + * @param int $newer_than If passed, only return if the cached value was created after this time + * @return mixed The cached data or FALSE if not found or expired + */ + public static function retrieve(FileSystemCacheKey $key, $newer_than=null) { + $filename = $key->getFileName(); + + if(!file_exists($filename)) return false; + + //if cached data is not newer than $newer_than + if($newer_than && filemtime($filename) < $newer_than) return false; + + $fh = self::getFileHandle($filename,'r'); + if(!$fh) return false; + + $data = self::getContents($fh,$key); + if(!$data) return false; + + + self::closeFile($fh); + return $data->value; + } + + /** + * Atomically retrieve data from cache, modify it, and store it back + * @param FileSystemCacheKey $key The cache key + * @param Closure $callback A closure function to modify the cache value. + * Takes the old value as an argument and returns new value. + * If this function returns false, the cached value will be invalidated. + * @param bool $resetTtl If set to true, the expiration date will be recalculated using the previous TTL + * @return mixed The new value if it was stored successfully or false if it wasn't + * @throws Exception If an invalid callback method is given + */ + public static function getAndModify(FileSystemCacheKey $key, Closure $callback, $resetTtl=false) { + $filename = $key->getFileName(); + + if(!file_exists($filename)) return false; + + //open a file handle + $fh = self::getFileHandle($filename,'c+'); + if(!$fh) return false; + + //get the data + $data = self::getContents($fh,$key); + if(!$data) return false; + + //get new value from callback function + $old_value = $data->value; + $data->value = $callback($data->value); + + //if the callback function returns false + if($data->value === false) { + self::closeFile($fh); + + //delete the cache file + self::invalidate($key); + return false; + } + + //if value didn't change + if(!$resetTtl && $data->value === $old_value) { + self::closeFile($fh); + return $data->value; + } + + //if we're resetting the ttl to now + if($resetTtl) { + $data->created = time(); + if($data->ttl) { + $data->expires = $data->created + $data->ttl; + } + } + + if(!self::emptyFile($fh)) return false; + + //write contents and close the file handle + self::putContents($fh,$data); + + //return the new value after modifying + return $data->value; + } + + /** + * Invalidate a specific cache key + * @param FileSystemCacheKey $key The cache key + * @return boolean True on success. Currently never returns false. + */ + public static function invalidate(FileSystemCacheKey $key) { + $filename = $key->getFileName(); + if(file_exists($filename)) { + unlink($filename); + } + return true; + } + + /** + * Invalidate a group of cache keys + * @param string $name The name of the group to invalidate (e.g. 'groupname', 'groupname/subgroupname', etc.). If null, the entire cache will be invalidated. + * @param boolean $recursive If set to false, none of the subgroups will be invalidated. + * @throws Exception If an invalid group name is given + */ + public static function invalidateGroup($name=null, $recursive=true) { + //if invalidating a group, make sure it's valid + if($name) { + //it needs to have a trailing slash and no leading slashes + $name = trim($name,'/').'/'; + + //make sure the key isn't going up a directory + if(strpos($name,'..') !== false) { + throw new Exception("Invalidate path cannot go up directories."); + } + } + + array_map("unlink", glob(self::$cacheDir.'/'.$name.'*.cache')); + + //if recursively invalidating + if($recursive) { + $subdirs = glob(self::$cacheDir.'/'.$name.'*',GLOB_ONLYDIR); + + foreach($subdirs as $dir) { + $dir = basename($dir); + + //skip all subdirectories that start with '.' + if($dir[0] == '.') continue; + + self::invalidateGroup($name.$dir,true); + } + } + } + + + /** + * Get a file handle from a file name. Will create the directory if it doesn't exist already. Also, automatically locks the file with the proper read or write lock. + * @param String $filename The full file path. + * @param String $mode The file mode. Accepted modes are 'c', 'c+', and 'r'. + * @return resource The file handle + */ + private static function getFileHandle($filename, $mode='c') { + $write = in_array($mode,array('c','c+')); + + if($write) { + //make sure the directory exists and is writable + $directory = dirname($filename); + if(!file_exists($directory)) { + if(!mkdir($directory,0777,true)) { + return false; + } + } + elseif(!is_dir($directory)) { + return false; + } + elseif(!is_writable($directory)) { + return false; + } + } + + //get file pointer + $fh = fopen($filename,$mode); + + if(!$fh) return false; + + //lock file with appropriate lock type + if($write) { + if(!flock($fh,LOCK_EX)) { + self::closeFile($fh); + return false; + } + } + else { + if(!flock($fh,LOCK_SH)) { + self::closeFile($fh); + return false; + } + } + + return $fh; + } + + /** + * Empties a file. If empty fails, the file will be closed and it will return false. + * @param resource $fh The file handle + * @return boolean true for success, false for failure + */ + private static function emptyFile($fh) { + rewind($fh); + if(!ftruncate($fh,0)) { + //release lock + self::closeFile($fh); + return false; + } + else { + return true; + } + } + + /** + * Closes a file. Also releases any locks on the file. + * @param resource $fh The file handle + */ + private static function closeFile($fh) { + flock($fh,LOCK_UN); + fclose($fh); + } + + /** + * Returns the contents of a cache file. If the data is not in the right form or expired, it will be invalidated. + * @param resource $fh The file handle + * @param FileSystemCacheKey $key The cache key. This is used to invalidate the key when the data is expired. + * @return boolean|FileSystemCacheValue FALSE if something went wrong or the data is expired. Otherwise, a FileSystemCacheValue object will be returned. + */ + private static function getContents($fh,FileSystemCacheKey $key) { + //get the existing file contents + $contents = stream_get_contents($fh); + $data = @unserialize($contents); + + //if we can't unserialize the data or if the data is expired + if(!$data || !($data instanceof FileSystemCacheValue) || $data->isExpired()) { + //release lock + self::closeFile($fh); + + //delete the cache file so we don't try to retrieve it again + self::invalidate($key); + + return false; + } + + return $data; + } + + /** + * Writes to a file. Also closes and releases any locks on the file. + * @param resource $fh The file handle + * @param FileSystemCacheValue $data The cache value to store in the file. + * @return boolean True on success. Currently, never returns false. + */ + private static function putContents($fh,FileSystemCacheValue $data) { + fwrite($fh,serialize($data)); + fflush($fh); + + //release lock + self::closeFile($fh); + + return true; + } +} + +/** + * Class that represents a cache key. + * Most of the time, you would get a FileSystemCacheKey object from FileSystemCache::generateCacheKey(); + */ +class FileSystemCacheKey { + /** + * @var mixed The key data used to generate the cache key + */ + public $key; + /** + * @var string The group (if any) that the key will be stored in. Can be null. + */ + public $group; + + /** + * Creates a FileSystemCacheKey object + * @param mixed $key Key data that will be used to generate a cache key + * @param string $group The group (if any) that the key will be stored in. Can be null. + */ + public function __construct($key,$group) { + $this->key = $key; + $this->group = $group; + } + + /** + * Returns the generated cache key. + * Non-string key data will be serialized and hashed + * @return string The generated cache key. + */ + public function __toString() { + $key = $this->key; + + //convert arrays and objects into strings + if(!is_string($key)) { + $key = serialize($key); + } + + //if we can't use the key directly, md5 it + if(preg_match('/[^a-zA-Z0-9_\-\.]/',$key)) { + $key = md5($key); + } + + //if it contains a group + if($this->group) { + //sanitize the group part + $parts = explode('/',$this->group); + foreach($parts as $i=>&$part) { + $part = preg_replace('/[^a-zA-Z0-9_\-]/','',$part); + + if(!$part) unset($parts[$i]); + } + + $group = implode('/',$parts); + + $key = $group.'/'.$key; + } + + return $key; + } + + /** + * Returns the full path to the cache file for this key. + * @return string The full path to the cache file for this key. + */ + public function getFileName() { + return FileSystemCache::$cacheDir . '/' . $this->__toString() . '.cache'; + } +} + +/** + * This class represents the actual data stored in the cache file. + * You should never need to use this class directly. + */ +class FileSystemCacheValue { + /** + * @var FileSystemCacheKey The cache key the file is stored under. + */ + public $key; + /** + * @var mixed The value being cached + */ + public $value; + /** + * @var int The max number of seconds to store the data. If null, the data won't expire. + */ + public $ttl; + /** + * @var int The timestamp of when the data will expire. If null, the data won't expire. + */ + public $expires; + /** + * @var int The timestamp of when the value was created. + */ + public $created; + + /** + * Creates a FileSystemCacheValue object. + * @param FileSystemCacheKey $key The cache key the file is stored under. + * @param mixed $value The data being stored + * @param int $ttl The timestamp of when the data will expire. If null, the data won't expire. + */ + public function __construct($key,$value,$ttl = null) { + $this->key = $key; + $this->value = $value; + $this->ttl = $ttl; + $this->created = time(); + + if($ttl) $this->expires = $this->created + $ttl; + else $this->expires = null; + } + + /** + * Checks if a value is expired + * @return bool True if the value is expired. False if it is not. + */ + public function isExpired() { + //value doesn't expire + if(!$this->expires) return false; + + //if it is after the expire time + return time() > $this->expires; + } +} diff --git a/vendor/jdorn/file-system-cache/phpunit.xml.dist b/vendor/jdorn/file-system-cache/phpunit.xml.dist new file mode 100644 index 00000000..7035b646 --- /dev/null +++ b/vendor/jdorn/file-system-cache/phpunit.xml.dist @@ -0,0 +1,20 @@ + + + + + + ./tests + + + + + + ./ + + ./tests + ./vendor + ./examples + + + + diff --git a/vendor/jdorn/file-system-cache/tests/FileSystemCacheTest.php b/vendor/jdorn/file-system-cache/tests/FileSystemCacheTest.php new file mode 100644 index 00000000..21c3aa8a --- /dev/null +++ b/vendor/jdorn/file-system-cache/tests/FileSystemCacheTest.php @@ -0,0 +1,279 @@ +assertInstanceOf('FileSystemCacheKey', $key); + } + + /** + * @dataProvider dataProvider + */ + function testStoreDataTypes($data) { + $key = FileSystemCache::generateCacheKey('mytestkey'); + + FileSystemCache::invalidate($key); + + $this->assertFalse(FileSystemCache::retrieve($key)); + + FileSystemCache::store($key, $data); + + $this->assertEquals($data, FileSystemCache::retrieve($key)); + + FileSystemCache::invalidate($key); + + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + /** + * @dataProvider keyDataProvider + */ + function testStore($key_data, $group) { + $key = FileSystemCache::generateCacheKey($key_data, $group); + + $data = 'test'.microtime(true); + + FileSystemCache::invalidate($key); + + $this->assertFalse(FileSystemCache::retrieve($key)); + + FileSystemCache::store($key, $data); + + $this->assertEquals($data, FileSystemCache::retrieve($key)); + + FileSystemCache::invalidate($key); + + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + function testStoreTtl() { + $key = FileSystemCache::generateCacheKey('ttl test'); + $data = 'test ttl '.microtime(true); + + FileSystemCache::invalidate($key); + + $this->assertFalse(FileSystemCache::retrieve($key)); + + FileSystemCache::store($key, $data, 1); + + $this->assertEquals($data, FileSystemCache::retrieve($key)); + + sleep(2); + + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + function testRetrieveNewerThan() { + $key = FileSystemCache::generateCacheKey('newer than test'); + $data = 'test newer than data'; + FileSystemCache::store($key, $data); + + $this->assertFalse(FileSystemCache::retrieve($key, time() + 5)); + $this->assertEquals($data, FileSystemCache::retrieve($key, time() - 5)); + + FileSystemCache::invalidate($key); + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + function testGetAndModifyReturnFalse() { + $key = FileSystemCache::generateCacheKey('get and modify key'); + $data = 'get and modify data'; + + FileSystemCache::store($key, $data, 1); + $this->assertEquals($data, FileSystemCache::retrieve($key)); + + FileSystemCache::getAndModify($key, function($value) { + return false; + }); + + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + function testGetAndModify() { + $key = FileSystemCache::generateCacheKey('get and modify key'); + $data = 'get and modify data'; + + FileSystemCache::store($key, $data, 1); + $this->assertEquals($data, FileSystemCache::retrieve($key)); + + FileSystemCache::getAndModify($key, function($value) { + $value .= 'test'; + return $value; + }); + + $this->assertEquals($data.'test', FileSystemCache::retrieve($key)); + + sleep(2); + + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + function testGetAndModifyResetTtl() { + $key = FileSystemCache::generateCacheKey('get and modify reset ttl key'); + $data = 'get and modify reset ttl data'; + + FileSystemCache::store($key, $data, 3); + sleep(2); + // At this point, the key expires in 1 seconds + $this->assertEquals($data, FileSystemCache::retrieve($key)); + + FileSystemCache::getAndModify($key, function($value) { + $value .= 'test'; + return $value; + }, true); + + sleep(2); + + // The original expiration has hit, but getAndModify should have extended it + $this->assertEquals($data.'test', FileSystemCache::retrieve($key)); + + sleep(2); + + $this->assertFalse(FileSystemCache::retrieve($key)); + } + + function testGetAndModifyUnchanged() { + $key = FileSystemCache::generateCacheKey('get and modify unchanged'); + $data = 'get and modify unchanged'; + + FileSystemCache::store($key, $data); + + $return = FileSystemCache::getAndModify($key, function($value) { + return $value; + }); + + $this->assertEquals($data, $return); + + $this->assertEquals($data, FileSystemCache::retrieve($key)); + } + + /** + * @expectedException Exception + */ + function testHackedGroupInvalidation() { + FileSystemCache::invalidateGroup('this/../../is/a/hack'); + } + + function testGroupInvalidation() { + $key_root = FileSystemCache::generateCacheKey('mykey'); + $key_group1 = FileSystemCache::generateCacheKey('mykey1','test'); + $key_group2 = FileSystemCache::generateCacheKey('mykey2','test'); + $key_sub = FileSystemCache::generateCacheKey('mykey','test/test'); + $key_other = FileSystemCache::generateCacheKey('mykey','test2'); + + $data = 'group invalidation'; + + FileSystemCache::store($key_root, $data); + FileSystemCache::store($key_group1, $data); + FileSystemCache::store($key_group2, $data); + FileSystemCache::store($key_sub, $data); + FileSystemCache::store($key_other, $data); + + $this->assertEquals($data, FileSystemCache::retrieve($key_root)); + $this->assertEquals($data, FileSystemCache::retrieve($key_group1)); + $this->assertEquals($data, FileSystemCache::retrieve($key_group2)); + $this->assertEquals($data, FileSystemCache::retrieve($key_sub)); + $this->assertEquals($data, FileSystemCache::retrieve($key_other)); + + FileSystemCache::invalidateGroup('test', false); + + $this->assertEquals($data, FileSystemCache::retrieve($key_root)); + $this->assertFalse(FileSystemCache::retrieve($key_group1)); + $this->assertFalse(FileSystemCache::retrieve($key_group2)); + $this->assertEquals($data, FileSystemCache::retrieve($key_sub)); + $this->assertEquals($data, FileSystemCache::retrieve($key_other)); + + FileSystemCache::invalidate($key_root); + FileSystemCache::invalidate($key_sub); + FileSystemCache::invalidate($key_other); + + $this->assertFalse(FileSystemCache::retrieve($key_root)); + $this->assertFalse(FileSystemCache::retrieve($key_sub)); + $this->assertFalse(FileSystemCache::retrieve($key_other)); + } + + + function testGroupInvalidationRecursive() { + $key_root = FileSystemCache::generateCacheKey('mykey'); + $key_group1 = FileSystemCache::generateCacheKey('mykey1','test'); + $key_group2 = FileSystemCache::generateCacheKey('mykey2','test'); + $key_sub = FileSystemCache::generateCacheKey('mykey','test/test'); + $key_other = FileSystemCache::generateCacheKey('mykey','test2'); + + $data = 'group invalidation recursive'; + + FileSystemCache::store($key_root, $data); + FileSystemCache::store($key_group1, $data); + FileSystemCache::store($key_group2, $data); + FileSystemCache::store($key_sub, $data); + FileSystemCache::store($key_other, $data); + + $this->assertEquals($data, FileSystemCache::retrieve($key_root)); + $this->assertEquals($data, FileSystemCache::retrieve($key_group1)); + $this->assertEquals($data, FileSystemCache::retrieve($key_group2)); + $this->assertEquals($data, FileSystemCache::retrieve($key_sub)); + $this->assertEquals($data, FileSystemCache::retrieve($key_other)); + + FileSystemCache::invalidateGroup('test'); + + $this->assertEquals($data, FileSystemCache::retrieve($key_root)); + $this->assertFalse(FileSystemCache::retrieve($key_group1)); + $this->assertFalse(FileSystemCache::retrieve($key_group2)); + $this->assertFalse(FileSystemCache::retrieve($key_sub)); + $this->assertEquals($data, FileSystemCache::retrieve($key_other)); + + FileSystemCache::invalidate($key_root); + FileSystemCache::invalidate($key_other); + + $this->assertFalse(FileSystemCache::retrieve($key_root)); + $this->assertFalse(FileSystemCache::retrieve($key_other)); + } + + function keyProvider() { + return array( + array(FileSystemCache::generateCacheKey('mykey')), + array(FileSystemCache::generateCacheKey('mykey','test')), + array(FileSystemCache::generateCacheKey('mykey','test/test')), + ); + } + + function keyDataProvider() { + $data = $this->dataProvider(); + $groups = $this->groupProvider(); + + $keys = array(); + foreach($data as $key_data) { + foreach($groups as $group) { + $keys[] = array( + $key_data[0], + $group[0] + ); + } + } + + return $keys; + } + function dataProvider() { + $temp = new DateTime(); + + return array( + array(99), + array('string'), + array(array('an','array','with'=>'data')), + array( $temp ) + ); + } + function groupProvider() { + return array( + array(null), + array('test'), + array('test/test') + ); + } +}