Merge pull request #143 from Skyscanner/ttl-feature

Implementation of TTL for caching
This commit is contained in:
Behrooz Shabani 2016-07-26 10:51:07 +02:00 committed by GitHub
commit a00af06cac
7 changed files with 187 additions and 19 deletions

View File

@ -9,6 +9,7 @@
* @package Handlebars * @package Handlebars
* @author fzerorubigd <fzerorubigd@gmail.com> * @author fzerorubigd <fzerorubigd@gmail.com>
* @author Behrooz Shabani <everplays@gmail.com> * @author Behrooz Shabani <everplays@gmail.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2012 (c) ParsPooyesh Co * @copyright 2012 (c) ParsPooyesh Co
* @copyright 2013 (c) Behrooz Shabani * @copyright 2013 (c) Behrooz Shabani
* @license MIT <http://opensource.org/licenses/MIT> * @license MIT <http://opensource.org/licenses/MIT>
@ -46,14 +47,17 @@ interface Cache
public function get($name); 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 string $name cache id
* @param mixed $value data to store * @param mixed $value data to store
* @param int $ttl time to live in seconds
* *
* @return void * @return void
*/ */
public function set($name, $value); public function set($name, $value, $ttl = 0);
/** /**
* Remove cache * Remove cache

View File

@ -9,6 +9,7 @@
* @package Handlebars * @package Handlebars
* @author Joey Baker <joey@byjoeybaker.com> * @author Joey Baker <joey@byjoeybaker.com>
* @author Behrooz Shabani <everplays@gmail.com> * @author Behrooz Shabani <everplays@gmail.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2013 (c) Meraki, LLP * @copyright 2013 (c) Meraki, LLP
* @copyright 2013 (c) Behrooz Shabani * @copyright 2013 (c) Behrooz Shabani
* @license MIT <http://opensource.org/licenses/MIT> * @license MIT <http://opensource.org/licenses/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 * @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) 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 string $name cache id
* @param mixed $value data to store * @param mixed $value data to store
* @param int $ttl time to live in seconds
* *
* @return void * @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);
} }
/** /**

View File

@ -9,6 +9,7 @@
* @package Handlebars * @package Handlebars
* @author Alex Soncodi <alex@brokerloop.com> * @author Alex Soncodi <alex@brokerloop.com>
* @author Behrooz Shabani <everplays@gmail.com> * @author Behrooz Shabani <everplays@gmail.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2013 (c) Brokerloop, Inc. * @copyright 2013 (c) Brokerloop, Inc.
* @copyright 2013 (c) Behrooz Shabani * @copyright 2013 (c) Behrooz Shabani
* @license MIT <http://opensource.org/licenses/MIT> * @license MIT <http://opensource.org/licenses/MIT>
@ -25,6 +26,7 @@ use Handlebars\Cache;
* @category Xamin * @category Xamin
* @package Handlebars * @package Handlebars
* @author Alex Soncodi <alex@brokerloop.com> * @author Alex Soncodi <alex@brokerloop.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2013 (c) Brokerloop, Inc. * @copyright 2013 (c) Brokerloop, Inc.
* @license MIT <http://opensource.org/licenses/MIT> * @license MIT <http://opensource.org/licenses/MIT>
* @version Release: @package_version@ * @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 * @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) public function get($name)
{ {
$path = $this->_getPath($name); $path = $this->_getPath($name);
$output = false;
return (file_exists($path)) ? if (file_exists($path)) {
unserialize(file_get_contents($path)) : false; $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 string $name cache id
* @param mixed $value data to store * @param mixed $value data to store
* @param int $ttl time to live in seconds
* *
* @return void * @return void
*/ */
public function set($name, $value) public function set($name, $value, $ttl = 0)
{ {
$path = $this->_getPath($name); $path = $this->_getPath($name);
file_put_contents($path, serialize($value)); file_put_contents($path, $ttl.PHP_EOL.serialize($value));
} }
/** /**

View File

@ -9,6 +9,7 @@
* @package Handlebars * @package Handlebars
* @author fzerorubigd <fzerorubigd@gmail.com> * @author fzerorubigd <fzerorubigd@gmail.com>
* @author Behrooz Shabani <everplays@gmail.com> * @author Behrooz Shabani <everplays@gmail.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2012 (c) ParsPooyesh Co * @copyright 2012 (c) ParsPooyesh Co
* @copyright 2013 (c) Behrooz Shabani * @copyright 2013 (c) Behrooz Shabani
* @license MIT <http://opensource.org/licenses/MIT> * @license MIT <http://opensource.org/licenses/MIT>
@ -55,10 +56,14 @@ class Dummy implements Cache
* *
* @param string $name cache id * @param string $name cache id
* @param mixed $value data to store * @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 * @return void
*/ */
public function set($name, $value) public function set($name, $value, $ttl = 0)
{ {
$this->_cache[$name] = $value; $this->_cache[$name] = $value;
} }

View File

@ -10,6 +10,7 @@
* @author fzerorubigd <fzerorubigd@gmail.com> * @author fzerorubigd <fzerorubigd@gmail.com>
* @author Behrooz Shabani <everplays@gmail.com> * @author Behrooz Shabani <everplays@gmail.com>
* @author Jeff Turcotte <jeff.turcotte@gmail.com> * @author Jeff Turcotte <jeff.turcotte@gmail.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2010-2012 (c) Justin Hileman * @copyright 2010-2012 (c) Justin Hileman
* @copyright 2012 (c) ParsPooyesh Co * @copyright 2012 (c) ParsPooyesh Co
* @copyright 2013 (c) Behrooz Shabani * @copyright 2013 (c) Behrooz Shabani
@ -37,7 +38,7 @@ use Handlebars\Cache\Dummy;
class Handlebars class Handlebars
{ {
private static $_instance = false; private static $_instance = false;
const VERSION = '1.0.0'; const VERSION = '1.1.0';
/** /**
* factory method * factory method
@ -85,6 +86,13 @@ class Handlebars
*/ */
private $_cache; 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 * @var string the class to use for the template
*/ */
@ -138,6 +146,10 @@ class Handlebars
$this->setCache($options['cache']); $this->setCache($options['cache']);
} }
if (isset($options['ttl'])) {
$this->setTtl($options['ttl']);
}
if (isset($options['template_class'])) { if (isset($options['template_class'])) {
$this->setTemplateClass($options['template_class']); $this->setTemplateClass($options['template_class']);
} }
@ -337,6 +349,28 @@ class Handlebars
return $this->_cache; 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 * 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 * @param string $source handlebars source code
* *
@ -558,7 +592,7 @@ class Handlebars
if ($tree === false) { if ($tree === false) {
$tokens = $this->getTokenizer()->scan($source); $tokens = $this->getTokenizer()->scan($source);
$tree = $this->getParser()->parse($tokens); $tree = $this->getParser()->parse($tokens);
$this->getCache()->set($hash, $tree); $this->getCache()->set($hash, $tree, $this->_ttl);
} }
return $tree; return $tree;

View File

@ -9,6 +9,7 @@
* @package Handlebars * @package Handlebars
* @author fzerorubigd <fzerorubigd@gmail.com> * @author fzerorubigd <fzerorubigd@gmail.com>
* @author Dmitriy Simushev <simushevds@gmail.com> * @author Dmitriy Simushev <simushevds@gmail.com>
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2013 (c) f0ruD A * @copyright 2013 (c) f0ruD A
* @license MIT <http://opensource.org/licenses/MIT> * @license MIT <http://opensource.org/licenses/MIT>
* @version GIT: $Id$ * @version GIT: $Id$
@ -92,9 +93,26 @@ class APCTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(20, $driver->get('foo')); $this->assertEquals(20, $driver->get('foo'));
$driver->set('foo', array(22)); $driver->set('foo', array(22));
$this->assertEquals(array(22), $driver->get('foo')); $this->assertEquals(array(22), $driver->get('foo'));
$driver->remove('foo'); $driver->remove('foo');
$this->assertEquals(false, $driver->get('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'));
}
} }

View File

@ -0,0 +1,84 @@
<?php
/**
* This file is part of Handlebars-php
* Base on mustache-php https://github.com/bobthecow/mustache.php
*
* PHP version 5.3
*
* @category Xamin
* @package Handlebars
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @copyright 2016 (c) Mária Šormanová
* @license MIT <http://opensource.org/licenses/MIT>
* @version GIT: $Id$
* @link http://xamin.ir
*/
/**
* Test of Disk cache driver
*
* @category Xamin
* @package Handlebars
* @subpackage Test
* @author Mária Šormanová <maria.sormanova@gmail.com>
* @license MIT <http://opensource.org/licenses/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);
}
}
?>