Skip to content

Commit

Permalink
Port Cache::add() to 3.1
Browse files Browse the repository at this point in the history
Port the changes in #7165 to add Cache::add() to 3.x
  • Loading branch information
markstory committed Aug 9, 2015
1 parent 0b5e24e commit f66edff
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 4 deletions.
28 changes: 28 additions & 0 deletions src/Cache/Cache.php
Expand Up @@ -540,4 +540,32 @@ public static function remember($key, $callable, $config = 'default')
self::write($key, $results, $config);
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.
* Or if the key existed already.
*/
public static function add($key, $value, $config = 'default')
{
$engine = static::engine($config);
if (is_resource($value)) {
return false;
}
return $engine->add($key, $value);
}
}
28 changes: 24 additions & 4 deletions src/Cache/CacheEngine.php
Expand Up @@ -165,6 +165,15 @@ abstract public function decrement($key, $offset = 1);
*/
abstract public function delete($key);


/**
* Delete all keys from the cache
*
* @param bool $check if true will check expiration, otherwise delete all
* @return bool True if the cache was successfully cleared, false otherwise
*/
abstract public function clear($check);

/**
* Deletes keys from the cache
*
Expand All @@ -182,12 +191,23 @@ public function deleteMany($keys)
}

/**
* Delete all keys from the cache
* Add a key to the cache if it does not already exist.
*
* @param bool $check if true will check expiration, otherwise delete all
* @return bool True if the cache was successfully cleared, false otherwise
* Defaults to a non-atomic implementation. Subclasses should
* prefer atomic implementations.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @return bool True if the data was successfully cached, false on failure.
*/
abstract public function clear($check);
public function add($key, $value)
{
$cachedValue = $this->read($key);
if ($cachedValue === false) {
return $this->write($key, $value);
}
return false;
}

/**
* Clears all values belonging to a group. Is up to the implementing engine
Expand Down
22 changes: 22 additions & 0 deletions src/Cache/Engine/ApcEngine.php
Expand Up @@ -160,6 +160,28 @@ public function clear($check)
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.
* @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)
{
$key = $this->_key($key);

$expires = 0;
$duration = $this->_config['duration'];
if ($duration) {
$expires = time() + $duration;
}
apc_add($key . '_expires', $expires, $duration);
return apc_add($key, $value, $duration);
}

/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
Expand Down
21 changes: 21 additions & 0 deletions src/Cache/Engine/MemcachedEngine.php
Expand Up @@ -422,6 +422,9 @@ public function clear($check)
}

$keys = $this->_Memcached->getAllKeys();
if ($keys === false) {
return false;
}

foreach ($keys as $key) {
if (strpos($key, $this->_config['prefix']) === 0) {
Expand All @@ -432,6 +435,24 @@ public function clear($check)
return true;
}

/**
* Add a key to the cache if it does not already exist.
*
* @param string $key Identifier for the data.
* @param mixed $value Data to be cached.
* @return bool True if the data was successfully cached, false on failure.
*/
public function add($key, $value)
{
$duration = $this->_config['duration'];
if ($duration > 30 * DAY) {
$duration = 0;
}

$key = $this->_key($key);
return $this->_Memcached->add($key, $value, $duration);
}

/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
Expand Down
25 changes: 25 additions & 0 deletions src/Cache/Engine/RedisEngine.php
Expand Up @@ -214,6 +214,31 @@ public function clear($check)
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.
* @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 = $this->_config['duration'];
$key = $this->_key($key);

if (!is_int($value)) {
$value = serialize($value);
}

// setnx() doesn't have an expiry option, so overwrite the key with one
if ($this->_Redis->setnx($key, $value)) {
return $this->_Redis->setex($key, $duration, $value);
}
return false;
}

/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
Expand Down
21 changes: 21 additions & 0 deletions tests/TestCase/Cache/CacheTest.php
Expand Up @@ -559,4 +559,25 @@ public function testRemember()
$result = Cache::remember('test_key', $cacher, 'tests');
$this->assertEquals($expected, $result);
}

/**
* Test add method.
*
* @return void
*/
public function testAdd()
{
$this->_configCache();
Cache::delete('test_add_key', 'tests');

$result = Cache::add('test_add_key', 'test data', 'tests');
$this->assertTrue($result);

$expected = 'test data';
$result = Cache::read('test_add_key', 'tests');
$this->assertEquals($expected, $result);

$result = Cache::add('test_add_key', 'test data 2', 'tests');
$this->assertFalse($result);
}
}
20 changes: 20 additions & 0 deletions tests/TestCase/Cache/Engine/ApcEngineTest.php
Expand Up @@ -286,4 +286,24 @@ 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);
}
}
20 changes: 20 additions & 0 deletions tests/TestCase/Cache/Engine/FileEngineTest.php
Expand Up @@ -621,4 +621,24 @@ public function testGroupClearNoPrefix()
$this->assertFalse(Cache::read('key_1', '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);
}
}
20 changes: 20 additions & 0 deletions tests/TestCase/Cache/Engine/MemcachedEngineTest.php
Expand Up @@ -916,4 +916,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::delete('test_add_key', 'memcached');

$result = Cache::add('test_add_key', 'test data', 'memcached');
$this->assertTrue($result);

$expected = 'test data';
$result = Cache::read('test_add_key', 'memcached');
$this->assertEquals($expected, $result);

$result = Cache::add('test_add_key', 'test data 2', 'memcached');
$this->assertFalse($result);
}
}
20 changes: 20 additions & 0 deletions tests/TestCase/Cache/Engine/RedisEngineTest.php
Expand Up @@ -410,4 +410,24 @@ public function testGroupClear()
$this->assertTrue(Cache::clearGroup('group_b', '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);
}
}

0 comments on commit f66edff

Please sign in to comment.