Skip to content

Commit

Permalink
Cache add() method added for all Cache engines.
Browse files Browse the repository at this point in the history
  • Loading branch information
nebojsac committed Aug 9, 2015
1 parent 7f6ab82 commit 41d0e1d
Show file tree
Hide file tree
Showing 19 changed files with 333 additions and 1 deletion.
37 changes: 37 additions & 0 deletions lib/Cake/Cache/Cache.php
Expand Up @@ -578,4 +578,41 @@ public static function remember($key, $callable, $config = 'default') {
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;
}
}
12 changes: 11 additions & 1 deletion lib/Cake/Cache/CacheEngine.php
Expand Up @@ -83,6 +83,17 @@ public function gc($expires = null) {
*/
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
*
Expand Down Expand Up @@ -176,5 +187,4 @@ public function key($key) {
$key = preg_replace('/[\s]+/', '_', strtolower(trim(str_replace(array(DS, '/', '.'), '_', strval($key)))));
return $prefix . $key;
}

}
18 changes: 18 additions & 0 deletions lib/Cake/Cache/Engine/ApcEngine.php
Expand Up @@ -188,4 +188,22 @@ public function clearGroup($group) {
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);
}
}
17 changes: 17 additions & 0 deletions lib/Cake/Cache/Engine/FileEngine.php
Expand Up @@ -429,4 +429,21 @@ public function clearGroup($group) {
}
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;
}
}
20 changes: 20 additions & 0 deletions lib/Cake/Cache/Engine/MemcacheEngine.php
Expand Up @@ -289,4 +289,24 @@ public function groups() {
public function clearGroup($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);
}
}
20 changes: 20 additions & 0 deletions lib/Cake/Cache/Engine/MemcachedEngine.php
Expand Up @@ -335,4 +335,24 @@ public function groups() {
public function clearGroup($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);
}
}
19 changes: 19 additions & 0 deletions lib/Cake/Cache/Engine/RedisEngine.php
Expand Up @@ -227,4 +227,23 @@ public function __destruct() {
$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;
}
}
16 changes: 16 additions & 0 deletions lib/Cake/Cache/Engine/WincacheEngine.php
Expand Up @@ -188,4 +188,20 @@ public function clearGroup($group) {
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;
}
}
17 changes: 17 additions & 0 deletions lib/Cake/Cache/Engine/XcacheEngine.php
Expand Up @@ -207,4 +207,21 @@ protected function _auth($reverse = false) {
}
}
}

/**
* 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;
}
}
19 changes: 19 additions & 0 deletions lib/Cake/Test/Case/Cache/CacheTest.php
Expand Up @@ -519,4 +519,23 @@ public function testRemember() {
public function cacher() {
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);
}
}
19 changes: 19 additions & 0 deletions lib/Cake/Test/Case/Cache/Engine/ApcEngineTest.php
Expand Up @@ -273,4 +273,23 @@ public function testGroupClear() {
$this->assertTrue(Cache::clearGroup('group_b', '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);
}
}
18 changes: 18 additions & 0 deletions lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php
Expand Up @@ -550,4 +550,22 @@ public function testGroupClearNoPrefix() {
$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);
}
}
19 changes: 19 additions & 0 deletions lib/Cake/Test/Case/Cache/Engine/MemcacheEngineTest.php
Expand Up @@ -490,4 +490,23 @@ public function testGroupClear() {
$this->assertTrue(Cache::clearGroup('group_b', '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);
}
}
20 changes: 20 additions & 0 deletions lib/Cake/Test/Case/Cache/Engine/MemcachedEngineTest.php
Expand Up @@ -797,4 +797,24 @@ public function testGroupClear() {
$this->assertTrue(Cache::clearGroup('group_b', '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);
}
}
18 changes: 18 additions & 0 deletions lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php
Expand Up @@ -381,4 +381,22 @@ public function testGroupClear() {
$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);
}
}
19 changes: 19 additions & 0 deletions lib/Cake/Test/Case/Cache/Engine/WincacheEngineTest.php
Expand Up @@ -259,4 +259,23 @@ public function testGroupClear() {
$this->assertTrue(Cache::clearGroup('group_b', '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);
}
}

0 comments on commit 41d0e1d

Please sign in to comment.