From 51f8a3056b6b2ed71c83280d525f5b261171c766 Mon Sep 17 00:00:00 2001 From: Maria Sormanova Date: Mon, 25 Jul 2016 16:14:39 +0200 Subject: [PATCH 1/2] Implementation of TTL for caching --- README.markdown | 6 +++ src/Handlebars/Cache.php | 8 +++- src/Handlebars/Cache/APC.php | 15 ++++-- src/Handlebars/Cache/Disk.php | 34 ++++++++++---- src/Handlebars/Cache/Dummy.php | 7 ++- src/Handlebars/Handlebars.php | 38 ++++++++++++++- tests/Xamin/Cache/APCTest.php | 18 ++++++++ tests/Xamin/Cache/DiskTest.php | 84 ++++++++++++++++++++++++++++++++++ 8 files changed, 192 insertions(+), 18 deletions(-) create mode 100644 tests/Xamin/Cache/DiskTest.php diff --git a/README.markdown b/README.markdown index 8fcda16..91f4182 100644 --- a/README.markdown +++ b/README.markdown @@ -83,6 +83,12 @@ echo $engine->render( ) ); ``` +upgrading to newer versions +----- + +If you are upgrading to the new library version which uses TTL with Disk cache, +first do not forget to delete all the files in the cache directory +created by older versions, since the data structure has changed. contribution ------------ diff --git a/src/Handlebars/Cache.php b/src/Handlebars/Cache.php index 579f9d9..0911479 100755 --- a/src/Handlebars/Cache.php +++ b/src/Handlebars/Cache.php @@ -9,6 +9,7 @@ * @package Handlebars * @author fzerorubigd * @author Behrooz Shabani + * @author Mária Šormanová * @copyright 2012 (c) ParsPooyesh Co * @copyright 2013 (c) Behrooz Shabani * @license MIT @@ -46,14 +47,17 @@ interface Cache public function get($name); /** - * Set a cache + * Set a cache with $ttl, if present + * If $ttl set to -1, the cache expires immediately + * If $ttl set to 0 (default), cache is never purged * * @param string $name cache id * @param mixed $value data to store + * @param int $ttl time to live in seconds * * @return void */ - public function set($name, $value); + public function set($name, $value, $ttl = 0); /** * Remove cache diff --git a/src/Handlebars/Cache/APC.php b/src/Handlebars/Cache/APC.php index 5c4469f..69ce1b4 100755 --- a/src/Handlebars/Cache/APC.php +++ b/src/Handlebars/Cache/APC.php @@ -9,6 +9,7 @@ * @package Handlebars * @author Joey Baker * @author Behrooz Shabani + * @author Mária Šormanová * @copyright 2013 (c) Meraki, LLP * @copyright 2013 (c) Behrooz Shabani * @license MIT @@ -50,11 +51,12 @@ class APC implements Cache } /** - * Get cache for $name if exist. + * Get cache for $name if exist + * and if the cache is not older than defined TTL. * * @param string $name Cache id * - * @return mixed data on hit, boolean false on cache not found + * @return mixed data on hit, boolean false on cache not found/expired */ public function get($name) { @@ -66,16 +68,19 @@ class APC implements Cache } /** - * Set a cache + * Set a cache with $ttl, if present + * If $ttl set to -1, the cache expires immediately + * If $ttl set to 0 (default), cache is never purged * * @param string $name cache id * @param mixed $value data to store + * @param int $ttl time to live in seconds * * @return void */ - public function set($name, $value) + public function set($name, $value, $ttl = 0) { - apc_store($this->_getKey($name), $value); + apc_store($this->_getKey($name), $value, $ttl); } /** diff --git a/src/Handlebars/Cache/Disk.php b/src/Handlebars/Cache/Disk.php index 8d6625b..9f7e7a7 100644 --- a/src/Handlebars/Cache/Disk.php +++ b/src/Handlebars/Cache/Disk.php @@ -9,6 +9,7 @@ * @package Handlebars * @author Alex Soncodi * @author Behrooz Shabani + * @author Mária Šormanová * @copyright 2013 (c) Brokerloop, Inc. * @copyright 2013 (c) Behrooz Shabani * @license MIT @@ -25,6 +26,7 @@ use Handlebars\Cache; * @category Xamin * @package Handlebars * @author Alex Soncodi + * @author Mária Šormanová * @copyright 2013 (c) Brokerloop, Inc. * @license MIT * @version Release: @package_version@ @@ -81,33 +83,49 @@ class Disk implements Cache } /** - * Get cache for $name if it exists. + * Get cache for $name if it exists + * and if the cache is not older than defined TTL. * * @param string $name Cache id * - * @return mixed data on hit, boolean false on cache not found + * @return mixed data on hit, boolean false on cache not found/expired */ public function get($name) { $path = $this->_getPath($name); - - return (file_exists($path)) ? - unserialize(file_get_contents($path)) : false; + $output = false; + if (file_exists($path)) { + $file = fopen($path, "r"); + $ttl = fgets($file); + $ctime = filectime($path); + $time = time(); + if ($ttl == -1 || ($ttl > 0 && $time - $ctime > $ttl)) { + unlink($path); + } else { + $serialized_data = fread($file, filesize($path)); + $output = unserialize($serialized_data); + } + fclose($file); + } + return $output; } /** - * Set a cache + * Set a cache with $ttl, if present + * If $ttl set to -1, the cache expires immediately + * If $ttl set to 0 (default), cache is never purged * * @param string $name cache id * @param mixed $value data to store + * @param int $ttl time to live in seconds * * @return void */ - public function set($name, $value) + public function set($name, $value, $ttl = 0) { $path = $this->_getPath($name); - file_put_contents($path, serialize($value)); + file_put_contents($path, $ttl.PHP_EOL.serialize($value)); } /** diff --git a/src/Handlebars/Cache/Dummy.php b/src/Handlebars/Cache/Dummy.php index b18266c..470e911 100755 --- a/src/Handlebars/Cache/Dummy.php +++ b/src/Handlebars/Cache/Dummy.php @@ -9,6 +9,7 @@ * @package Handlebars * @author fzerorubigd * @author Behrooz Shabani + * @author Mária Šormanová * @copyright 2012 (c) ParsPooyesh Co * @copyright 2013 (c) Behrooz Shabani * @license MIT @@ -55,10 +56,14 @@ class Dummy implements Cache * * @param string $name cache id * @param mixed $value data to store + * @param int $ttl time to live in seconds + * + * $ttl is ignored since the cache is implemented + * by an array and lives only inside one request * * @return void */ - public function set($name, $value) + public function set($name, $value, $ttl = 0) { $this->_cache[$name] = $value; } diff --git a/src/Handlebars/Handlebars.php b/src/Handlebars/Handlebars.php index 20f296d..9824846 100755 --- a/src/Handlebars/Handlebars.php +++ b/src/Handlebars/Handlebars.php @@ -10,6 +10,7 @@ * @author fzerorubigd * @author Behrooz Shabani * @author Jeff Turcotte + * @author Mária Šormanová * @copyright 2010-2012 (c) Justin Hileman * @copyright 2012 (c) ParsPooyesh Co * @copyright 2013 (c) Behrooz Shabani @@ -85,6 +86,13 @@ class Handlebars */ private $_cache; + /** + * @var int time to live parameter in seconds for the cache usage + * default set to 0 which means that entries stay in cache + * forever and are never purged + */ + private $_ttl = 0; + /** * @var string the class to use for the template */ @@ -138,6 +146,10 @@ class Handlebars $this->setCache($options['cache']); } + if (isset($options['ttl'])) { + $this->setTtl($options['ttl']); + } + if (isset($options['template_class'])) { $this->setTemplateClass($options['template_class']); } @@ -337,6 +349,28 @@ class Handlebars return $this->_cache; } + /** + * Set time to live for the used cache + * + * @param int $ttl time to live in seconds + * + * @return void + */ + public function setTtl($ttl) + { + $this->_ttl = $ttl; + } + + /** + * Get ttl + * + * @return int + */ + public function getTtl() + { + return $this->_ttl; + } + /** * Get current escape function * @@ -545,7 +579,7 @@ class Handlebars } /** - * try to tokenize source, or get them from cache if available + * Try to tokenize source, or get them from cache if available * * @param string $source handlebars source code * @@ -558,7 +592,7 @@ class Handlebars if ($tree === false) { $tokens = $this->getTokenizer()->scan($source); $tree = $this->getParser()->parse($tokens); - $this->getCache()->set($hash, $tree); + $this->getCache()->set($hash, $tree, $this->_ttl); } return $tree; diff --git a/tests/Xamin/Cache/APCTest.php b/tests/Xamin/Cache/APCTest.php index a215678..8947a7f 100644 --- a/tests/Xamin/Cache/APCTest.php +++ b/tests/Xamin/Cache/APCTest.php @@ -9,6 +9,7 @@ * @package Handlebars * @author fzerorubigd * @author Dmitriy Simushev + * @author Mária Šormanová * @copyright 2013 (c) f0ruD A * @license MIT * @version GIT: $Id$ @@ -92,9 +93,26 @@ class APCTest extends \PHPUnit_Framework_TestCase $this->assertEquals(20, $driver->get('foo')); $driver->set('foo', array(22)); + $this->assertEquals(array(22), $driver->get('foo')); $driver->remove('foo'); $this->assertEquals(false, $driver->get('foo')); } + + /** + * Test ttl + * + * @return void + */ + public function testTtl() + { + $driver = $this->_getCacheDriver(); + + $driver->set('foo', 10, -1); + $this->assertEquals(false, $driver->get('foo')); + + $driver->set('foo', 20, 3600); + $this->assertEquals(20, $driver->get('foo')); + } } \ No newline at end of file diff --git a/tests/Xamin/Cache/DiskTest.php b/tests/Xamin/Cache/DiskTest.php new file mode 100644 index 0000000..abd9661 --- /dev/null +++ b/tests/Xamin/Cache/DiskTest.php @@ -0,0 +1,84 @@ + + * @copyright 2016 (c) Mária Šormanová + * @license MIT + * @version GIT: $Id$ + * @link http://xamin.ir + */ + +/** + * Test of Disk cache driver + * + * @category Xamin + * @package Handlebars + * @subpackage Test + * @author Mária Šormanová + * @license MIT + * @version Release: @package_version@ + * @link http://xamin.ir + */ + +class DiskTest extends \PHPUnit_Framework_TestCase +{ + /** + * {@inheritdoc} + * + * @return void + */ + public function setUp() + { + \Handlebars\Autoloader::register(); + } + + /** + * Return the new driver + * + * @param string $path folder where the cache is located + * + * @return \Handlebars\Cache\Disk + */ + private function _getCacheDriver( $path = '') + { + return new \Handlebars\Cache\Disk($path); + } + + /** + * Test the Disk cache + * + * @return void + */ + public function testDiskCache() + { + $cache_dir = getcwd().'/tests/cache'; + $driver = $this->_getCacheDriver($cache_dir); + + $this->assertEquals(false, $driver->get('foo')); + + $driver->set('foo', "hello world"); + $this->assertEquals("hello world", $driver->get('foo')); + + $driver->set('foo', "hello world", -1); + $this->assertEquals(false, $driver->get('foo')); + + $driver->set('foo', "hello world", 3600); + $this->assertEquals("hello world", $driver->get('foo')); + + $driver->set('foo', array(12)); + $this->assertEquals(array(12), $driver->get('foo')); + + $driver->remove('foo'); + $this->assertEquals(false, $driver->get('foo')); + + rmdir($cache_dir); + } +} + +?> \ No newline at end of file From 3a25d9bf17f2f882b14402bed87d2befd7300c37 Mon Sep 17 00:00:00 2001 From: Maria Sormanova Date: Tue, 26 Jul 2016 10:43:18 +0200 Subject: [PATCH 2/2] added versioning to prevent breaking existing projects --- README.markdown | 6 ------ src/Handlebars/Handlebars.php | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/README.markdown b/README.markdown index 91f4182..8fcda16 100644 --- a/README.markdown +++ b/README.markdown @@ -83,12 +83,6 @@ echo $engine->render( ) ); ``` -upgrading to newer versions ------ - -If you are upgrading to the new library version which uses TTL with Disk cache, -first do not forget to delete all the files in the cache directory -created by older versions, since the data structure has changed. contribution ------------ diff --git a/src/Handlebars/Handlebars.php b/src/Handlebars/Handlebars.php index 9824846..17b41c8 100755 --- a/src/Handlebars/Handlebars.php +++ b/src/Handlebars/Handlebars.php @@ -38,7 +38,7 @@ use Handlebars\Cache\Dummy; class Handlebars { private static $_instance = false; - const VERSION = '1.0.0'; + const VERSION = '1.1.0'; /** * factory method