diff --git a/src/Illuminate/Cache/RedisTaggedCache.php b/src/Illuminate/Cache/RedisTaggedCache.php index 349627e34b18..faf7d7ebea68 100644 --- a/src/Illuminate/Cache/RedisTaggedCache.php +++ b/src/Illuminate/Cache/RedisTaggedCache.php @@ -4,6 +4,34 @@ class RedisTaggedCache extends TaggedCache { + /** + * Forever reference key. + * + * @var string + */ + const REFERENCE_KEY_FOREVER = 'forever'; + /** + * Standard reference key. + * + * @var string + */ + const REFERENCE_KEY_STANDARD = 'standard'; + + /** + * Store an item in the cache. + * + * @param string $key + * @param mixed $value + * @param \DateTime|int $minutes + * @return void + */ + public function put($key, $value, $minutes = null) + { + $this->pushStandardKeys($this->tags->getNamespace(), $key); + + parent::put($key, $value, $minutes); + } + /** * Store an item in the cache indefinitely. * @@ -26,23 +54,49 @@ public function forever($key, $value) public function flush() { $this->deleteForeverKeys(); + $this->deleteStandardKeys(); parent::flush(); } /** - * Store a copy of the full key for each namespace segment. + * Store standard key references into store. + * + * @param string $namespace + * @param string $key + * @return void + */ + protected function pushStandardKeys($namespace, $key) + { + $this->pushKeys($namespace, $key, self::REFERENCE_KEY_STANDARD); + } + + /** + * Store forever key references into store. * * @param string $namespace * @param string $key * @return void */ protected function pushForeverKeys($namespace, $key) + { + $this->pushKeys($namespace, $key, self::REFERENCE_KEY_FOREVER); + } + + /** + * Store a reference to the cache key against the reference key. + * + * @param string $namespace + * @param string $key + * @param string $reference + * @return void + */ + protected function pushKeys($namespace, $key, $reference) { $fullKey = $this->getPrefix().sha1($namespace).':'.$key; foreach (explode('|', $namespace) as $segment) { - $this->store->connection()->lpush($this->foreverKey($segment), $fullKey); + $this->store->connection()->lpush($this->referenceKey($segment, $reference), $fullKey); } } @@ -52,37 +106,59 @@ protected function pushForeverKeys($namespace, $key) * @return void */ protected function deleteForeverKeys() + { + $this->deleteKeysByReference(self::REFERENCE_KEY_FOREVER); + } + + /** + * Delete all standard items. + * + * @return void + */ + protected function deleteStandardKeys() + { + $this->deleteKeysByReference(self::REFERENCE_KEY_STANDARD); + } + + /** + * Find and delete all of the items that were stored against a reference. + * + * @param string $reference + * @return void + */ + protected function deleteKeysByReference($reference) { foreach (explode('|', $this->tags->getNamespace()) as $segment) { - $this->deleteForeverValues($segment = $this->foreverKey($segment)); + $this->deleteValues($segment = $this->referenceKey($segment, $reference)); $this->store->connection()->del($segment); } } /** - * Delete all of the keys that have been stored forever. + * Delete item keys that have been stored against a reference. * - * @param string $foreverKey + * @param string $referenceKey * @return void */ - protected function deleteForeverValues($foreverKey) + protected function deleteValues($referenceKey) { - $forever = array_unique($this->store->connection()->lrange($foreverKey, 0, -1)); + $values = array_unique($this->store->connection()->lrange($referenceKey, 0, -1)); - if (count($forever) > 0) { - call_user_func_array([$this->store->connection(), 'del'], $forever); + if (count($values) > 0) { + call_user_func_array([$this->store->connection(), 'del'], $values); } } /** - * Get the forever reference key for the segment. + * Get the reference key for the segment. * * @param string $segment + * @param string $suffix * @return string */ - protected function foreverKey($segment) + protected function referenceKey($segment, $suffix) { - return $this->getPrefix().$segment.':forever'; + return $this->getPrefix().$segment.':'.$suffix; } } diff --git a/tests/Cache/CacheTaggedCacheTest.php b/tests/Cache/CacheTaggedCacheTest.php index e255171af180..2ef809c09b6c 100644 --- a/tests/Cache/CacheTaggedCacheTest.php +++ b/tests/Cache/CacheTaggedCacheTest.php @@ -71,7 +71,23 @@ public function testRedisCacheTagsPushForeverKeysCorrectly() $redis->forever('key1', 'key1:value'); } - public function testRedisCacheForeverTagsCanBeFlushed() + public function testRedisCacheTagsPushStandardKeysCorrectly() + { + $store = m::mock('Illuminate\Contracts\Cache\Store'); + $tagSet = m::mock('Illuminate\Cache\TagSet', [$store, ['foo', 'bar']]); + $tagSet->shouldReceive('getNamespace')->andReturn('foo|bar'); + $tagSet->shouldReceive('getNames')->andReturn(['foo', 'bar']); + $redis = new Illuminate\Cache\RedisTaggedCache($store, $tagSet); + $store->shouldReceive('getPrefix')->andReturn('prefix:'); + $store->shouldReceive('connection')->andReturn($conn = m::mock('StdClass')); + $conn->shouldReceive('lpush')->once()->with('prefix:foo:standard', 'prefix:'.sha1('foo|bar').':key1'); + $conn->shouldReceive('lpush')->once()->with('prefix:bar:standard', 'prefix:'.sha1('foo|bar').':key1'); + $store->shouldReceive('push')->with(sha1('foo|bar').':key1', 'key1:value'); + + $redis->put('key1', 'key1:value'); + } + + public function testRedisCacheTagsCanBeFlushed() { $store = m::mock('Illuminate\Contracts\Cache\Store'); $tagSet = m::mock('Illuminate\Cache\TagSet', [$store, ['foo', 'bar']]); @@ -79,12 +95,23 @@ public function testRedisCacheForeverTagsCanBeFlushed() $redis = new Illuminate\Cache\RedisTaggedCache($store, $tagSet); $store->shouldReceive('getPrefix')->andReturn('prefix:'); $store->shouldReceive('connection')->andReturn($conn = m::mock('StdClass')); + + // Forever tag keys $conn->shouldReceive('lrange')->once()->with('prefix:foo:forever', 0, -1)->andReturn(['key1', 'key2']); $conn->shouldReceive('lrange')->once()->with('prefix:bar:forever', 0, -1)->andReturn(['key3']); $conn->shouldReceive('del')->once()->with('key1', 'key2'); $conn->shouldReceive('del')->once()->with('key3'); $conn->shouldReceive('del')->once()->with('prefix:foo:forever'); $conn->shouldReceive('del')->once()->with('prefix:bar:forever'); + + // Standard tag keys + $conn->shouldReceive('lrange')->once()->with('prefix:foo:standard', 0, -1)->andReturn(['key4', 'key5']); + $conn->shouldReceive('lrange')->once()->with('prefix:bar:standard', 0, -1)->andReturn(['key6']); + $conn->shouldReceive('del')->once()->with('key4', 'key5'); + $conn->shouldReceive('del')->once()->with('key6'); + $conn->shouldReceive('del')->once()->with('prefix:foo:standard'); + $conn->shouldReceive('del')->once()->with('prefix:bar:standard'); + $tagSet->shouldReceive('reset')->once(); $redis->flush();