Cache add() method added for all Cache engines.

This commit is contained in:
Nick Cinger 2015-07-27 23:42:00 +02:00
parent 7f6ab82c9b
commit 41d0e1df19
19 changed files with 333 additions and 1 deletions

View file

@ -578,4 +578,41 @@ class Cache {
return $results; return $results;
} }
/**
* Write data for key into a cache engine if it doesn't exist already.
*
* ### Usage:
*
* Writing to the active cache config:
*
* `Cache::add('cached_data', $data);`
*
* Writing to a specific cache config:
*
* `Cache::add('cached_data', $data, 'long_term');`
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached - anything except a resource.
* @param string $config Optional string configuration name to write to. Defaults to 'default'.
* @return bool True if the data was successfully cached, false on failure.
*/
public static function add($key, $value, $config = 'default') {
$settings = self::settings($config);
if (empty($settings)) {
return false;
}
if (!self::isInitialized($config)) {
return false;
}
$key = self::$_engines[$config]->key($key);
if (!$key || is_resource($value)) {
return false;
}
$success = self::$_engines[$config]->add($settings['prefix'] . $key, $value, $settings['duration']);
self::set(null, $config);
return $success;
}
} }

View file

@ -83,6 +83,17 @@ abstract class CacheEngine {
*/ */
abstract public function write($key, $value, $duration); abstract public function write($key, $value, $duration);
/**
* Write value for a key into cache if it doesn't already exist
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param int $duration How long to cache for.
* @return bool True if the data was successfully cached, false on failure
*/
public function add($key, $value, $duration) {
}
/** /**
* Read a key from the cache * Read a key from the cache
* *
@ -176,5 +187,4 @@ abstract class CacheEngine {
$key = preg_replace('/[\s]+/', '_', strtolower(trim(str_replace(array(DS, '/', '.'), '_', strval($key))))); $key = preg_replace('/[\s]+/', '_', strtolower(trim(str_replace(array(DS, '/', '.'), '_', strval($key)))));
return $prefix . $key; return $prefix . $key;
} }
} }

View file

@ -188,4 +188,22 @@ class ApcEngine extends CacheEngine {
return $success; return $success;
} }
/**
* Write data for key into cache if it doesn't exist already.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
* @link http://php.net/manual/en/function.apc-add.php
*/
public function add($key, $value, $duration) {
$expires = 0;
if ($duration) {
$expires = time() + $duration;
}
apc_add($key . '_expires', $expires, $duration);
return apc_add($key, $value, $duration);
}
} }

View file

@ -429,4 +429,21 @@ class FileEngine extends CacheEngine {
} }
return true; return true;
} }
/**
* Write data for key into cache if it doesn't exist already.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
*/
public function add($key, $value, $duration) {
$cachedValue = $this->read($key);
if ($cachedValue === false) {
return $this->write($key, $value, $duration);
}
return false;
}
} }

View file

@ -289,4 +289,24 @@ class MemcacheEngine extends CacheEngine {
public function clearGroup($group) { public function clearGroup($group) {
return (bool)$this->_Memcache->increment($this->settings['prefix'] . $group); return (bool)$this->_Memcache->increment($this->settings['prefix'] . $group);
} }
/**
* Write data for key into cache if it doesn't exist already. When using memcached as your cache engine
* remember that the Memcached pecl extension does not support cache expiry times greater
* than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
* @link http://php.net/manual/en/memcache.add.php
*/
public function add($key, $value, $duration) {
if ($duration > 30 * DAY) {
$duration = 0;
}
return $this->_Memcache->add($key, $value, $this->settings['compress'], $duration);
}
} }

View file

@ -335,4 +335,24 @@ class MemcachedEngine extends CacheEngine {
public function clearGroup($group) { public function clearGroup($group) {
return (bool)$this->_Memcached->increment($this->settings['prefix'] . $group); return (bool)$this->_Memcached->increment($this->settings['prefix'] . $group);
} }
/**
* Write data for key into cache if it doesn't exist already. When using memcached as your cache engine
* remember that the Memcached pecl extension does not support cache expiry times greater
* than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
* @link http://php.net/manual/en/memcached.add.php
*/
public function add($key, $value, $duration) {
if ($duration > 30 * DAY) {
$duration = 0;
}
return $this->_Memcached->add($key, $value, $duration);
}
} }

View file

@ -227,4 +227,23 @@ class RedisEngine extends CacheEngine {
$this->_Redis->close(); $this->_Redis->close();
} }
} }
/**
* Write data for key into cache if it doesn't exist already.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
* @link https://github.com/phpredis/phpredis#setnx
*/
public function add($key, $value, $duration) {
$result = $this->_Redis->setnx($key, $value);
// setnx() doesn't have an expiry option, so overwrite the key with one
if ($result) {
return $this->_Redis->setex($key, $value, $duration);
}
return false;
}
} }

View file

@ -188,4 +188,20 @@ class WincacheEngine extends CacheEngine {
return $success; return $success;
} }
/**
* Write data for key into cache if it doesn't exist already.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
*/
public function add($key, $value, $duration) {
$cachedValue = $this->read($key);
if ($cachedValue === false) {
return $this->write($key, $value, $duration);
}
return false;
}
} }

View file

@ -207,4 +207,21 @@ class XcacheEngine extends CacheEngine {
} }
} }
} }
/**
* Write data for key into cache if it doesn't exist already.
* If it already exists, it fails and returns false.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @param int $duration How long to cache the data, in seconds.
* @return bool True if the data was successfully cached, false on failure.
*/
public function add($key, $value, $duration) {
$cachedValue = $this->read($key);
if ($cachedValue === false) {
return $this->write($key, $value, $duration);
}
return false;
}
} }

View file

@ -519,4 +519,23 @@ class CacheTest extends CakeTestCase {
public function cacher() { public function cacher() {
return 'This is some data ' . $this->_count; return 'This is some data ' . $this->_count;
} }
/**
* Test add method.
*
* @return void
*/
public function testAdd() {
Cache::delete('test_add_key', 'default');
$result = Cache::add('test_add_key', 'test data', 'default');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'default');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'default');
$this->assertFalse($result);
}
} }

View file

@ -273,4 +273,23 @@ class ApcEngineTest extends CakeTestCase {
$this->assertTrue(Cache::clearGroup('group_b', 'apc_groups')); $this->assertTrue(Cache::clearGroup('group_b', 'apc_groups'));
$this->assertFalse(Cache::read('test_groups', 'apc_groups')); $this->assertFalse(Cache::read('test_groups', 'apc_groups'));
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::delete('test_add_key', 'apc');
$result = Cache::add('test_add_key', 'test data', 'apc');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'apc');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'apc');
$this->assertFalse($result);
}
} }

View file

@ -550,4 +550,22 @@ class FileEngineTest extends CakeTestCase {
$this->assertFalse(Cache::read('key_2', 'file_groups'), 'Did not delete'); $this->assertFalse(Cache::read('key_2', 'file_groups'), 'Did not delete');
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::delete('test_add_key', 'file_test');
$result = Cache::add('test_add_key', 'test data', 'file_test');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'file_test');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'file_test');
$this->assertFalse($result);
}
} }

View file

@ -490,4 +490,23 @@ class MemcacheEngineTest extends CakeTestCase {
$this->assertTrue(Cache::clearGroup('group_b', 'memcache_groups')); $this->assertTrue(Cache::clearGroup('group_b', 'memcache_groups'));
$this->assertFalse(Cache::read('test_groups', 'memcache_groups')); $this->assertFalse(Cache::read('test_groups', 'memcache_groups'));
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::delete('test_add_key', 'memcache');
$result = Cache::add('test_add_key', 'test data', 'memcache');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'memcache');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'memcache');
$this->assertFalse($result);
}
} }

View file

@ -797,4 +797,24 @@ class MemcachedEngineTest extends CakeTestCase {
$this->assertTrue(Cache::clearGroup('group_b', 'memcached_groups')); $this->assertTrue(Cache::clearGroup('group_b', 'memcached_groups'));
$this->assertFalse(Cache::read('test_groups', 'memcached_groups')); $this->assertFalse(Cache::read('test_groups', 'memcached_groups'));
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::set(array('duration' => 1), null, 'memcached');
Cache::delete('test_add_key', 'default');
$result = Cache::add('test_add_key', 'test data', 'default');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'default');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'default');
$this->assertFalse($result);
}
} }

View file

@ -381,4 +381,22 @@ class RedisEngineTest extends CakeTestCase {
$this->assertFalse(Cache::read('test_groups', 'redis_groups')); $this->assertFalse(Cache::read('test_groups', 'redis_groups'));
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::delete('test_add_key', 'redis');
$result = Cache::add('test_add_key', 'test data', 'redis');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'redis');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'redis');
$this->assertFalse($result);
}
} }

View file

@ -259,4 +259,23 @@ class WincacheEngineTest extends CakeTestCase {
$this->assertTrue(Cache::clearGroup('group_b', 'wincache_groups')); $this->assertTrue(Cache::clearGroup('group_b', 'wincache_groups'));
$this->assertFalse(Cache::read('test_groups', 'wincache_groups')); $this->assertFalse(Cache::read('test_groups', 'wincache_groups'));
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::delete('test_add_key', 'wincache');
$result = Cache::add('test_add_key', 'test data', 'wincache');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'wincache');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'wincache');
$this->assertFalse($result);
}
} }

View file

@ -268,4 +268,24 @@ class XcacheEngineTest extends CakeTestCase {
$this->assertTrue(Cache::clearGroup('group_b', 'xcache_groups')); $this->assertTrue(Cache::clearGroup('group_b', 'xcache_groups'));
$this->assertFalse(Cache::read('test_groups', 'xcache_groups')); $this->assertFalse(Cache::read('test_groups', 'xcache_groups'));
} }
/**
* Test that failed add write return false.
*
* @return void
*/
public function testAdd() {
Cache::set(array('duration' => 1), null);
Cache::delete('test_add_key', 'default');
$result = Cache::add('test_add_key', 'test data', 'default');
$this->assertTrue($result);
$expected = 'test data';
$result = Cache::read('test_add_key', 'default');
$this->assertEquals($expected, $result);
$result = Cache::add('test_add_key', 'test data 2', 'default');
$this->assertFalse($result);
}
} }

View file

@ -46,4 +46,7 @@ class TestAppCacheEngine extends CacheEngine {
public function clearGroup($group) { public function clearGroup($group) {
} }
public function add($key, $value, $duration) {
}
} }

View file

@ -43,4 +43,7 @@ class TestPluginCacheEngine extends CacheEngine {
public function clearGroup($group) { public function clearGroup($group) {
} }
public function add($key, $value, $duration) {
}
} }