diff --git a/framework/yii/caching/ApcCache.php b/framework/yii/caching/ApcCache.php index 6c2754a..688c3f1 100644 --- a/framework/yii/caching/ApcCache.php +++ b/framework/yii/caching/ApcCache.php @@ -72,6 +72,17 @@ class ApcCache extends Cache } /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + return array_keys(apc_store($data, null, $expire)); + } + + /** * Stores a value identified by a key into cache if the cache does not contain this key. * This is the implementation of the method declared in the parent class. * @param string $key the key identifying the value to be cached @@ -85,6 +96,17 @@ class ApcCache extends Cache } /** + * Adds multiple key-value pairs to cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + return array_keys(apc_add($data, null, $expire)); + } + + /** * Deletes a value with the specified key from cache * This is the implementation of the method declared in the parent class. * @param string $key the key of the value to be deleted diff --git a/framework/yii/caching/Cache.php b/framework/yii/caching/Cache.php index 6471e5d..41a25b2 100644 --- a/framework/yii/caching/Cache.php +++ b/framework/yii/caching/Cache.php @@ -220,14 +220,62 @@ abstract class Cache extends Component implements \ArrayAccess * If the cache already contains such a key, the existing value and * expiration time will be replaced with the new ones, respectively. * - * @param array $items the items to be cached, as key-value pairs. Each key can be a simple string or - * a complex data structure consisting of factors representing the key. - * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. + * @param array $items the items to be cached, as key-value pairs. + * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. + * @param Dependency $dependency dependency of the cached items. If the dependency changes, + * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. + * This parameter is ignored if [[serializer]] is false. + * @return boolean whether the items are successfully stored into cache + */ + public function mset($items, $expire = 0, $dependency = null) + { + if ($dependency !== null && $this->serializer !== false) { + $dependency->evaluateDependency($this); + } + + $data = []; + foreach ($items as $key => $value) { + $itemKey = $this->buildKey($key); + if ($this->serializer === null) { + $itemValue = serialize([$value, $dependency]); + } elseif ($this->serializer !== false) { + $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); + } + + $data[$itemKey] = $itemValue; + } + return $this->setValues($data, $expire); + } + + /** + * Stores multiple items in cache. Each item contains a value identified by a key. + * If the cache already contains such a key, the existing value and expiration time will be preserved. + * + * @param array $items the items to be cached, as key-value pairs. + * @param integer $expire default number of seconds in which the cached values will expire. 0 means never expire. + * @param Dependency $dependency dependency of the cached items. If the dependency changes, + * the corresponding values in the cache will be invalidated when it is fetched via [[get()]]. + * This parameter is ignored if [[serializer]] is false. * @return boolean whether the items are successfully stored into cache */ - public function mset($items, $expire = 0) + public function madd($items, $expire = 0, $dependency = null) { - return false; + if ($dependency !== null && $this->serializer !== false) { + $dependency->evaluateDependency($this); + } + + $data = []; + foreach ($items as $key => $value) { + $itemKey = $this->buildKey($key); + if ($this->serializer === null) { + $itemValue = serialize([$value, $dependency]); + } elseif ($this->serializer !== false) { + $itemValue = call_user_func($this->serializer[0], [$value, $dependency]); + } + + $data[$itemKey] = $itemValue; + } + return $this->addValues($data, $expire); } /** @@ -342,6 +390,46 @@ abstract class Cache extends Component implements \ArrayAccess } /** + * Stores multiple key-value pairs in cache. + * The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache + * storage supports multiset, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + $failedKeys = []; + foreach ($data as $key => $value) + { + if ($this->setValue($key, $value, $expire) === false) { + $failedKeys[] = $key; + } + } + return $failedKeys; + } + + /** + * Adds multiple key-value pairs to cache. + * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache + * storage supports multiadd, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + $failedKeys = []; + foreach ($data as $key => $value) + { + if ($this->addValue($key, $value, $expire) === false) { + $failedKeys[] = $key; + } + } + return $failedKeys; + } + + /** * Returns whether there is a cache entry with a specified key. * This method is required by the interface ArrayAccess. * @param string $key a key identifying the cached value diff --git a/framework/yii/caching/MemCache.php b/framework/yii/caching/MemCache.php index 6f7a760..3391796 100644 --- a/framework/yii/caching/MemCache.php +++ b/framework/yii/caching/MemCache.php @@ -202,6 +202,27 @@ class MemCache extends Cache } /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys. Always empty in case of using memcached. + */ + protected function setValues($data, $expire) + { + if ($this->useMemcached) { + if ($expire > 0) { + $expire += time(); + } else { + $expire = 0; + } + $this->_cache->setMulti($data, $expire); + return []; + } else { + return parent::setValues($data, $expire); + } + } + + /** * Stores a value identified by a key into cache if the cache does not contain this key. * This is the implementation of the method declared in the parent class. * diff --git a/framework/yii/caching/WinCache.php b/framework/yii/caching/WinCache.php index 3679884..7f1eca8 100644 --- a/framework/yii/caching/WinCache.php +++ b/framework/yii/caching/WinCache.php @@ -72,6 +72,17 @@ class WinCache extends Cache } /** + * Stores multiple key-value pairs in cache. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function setValues($data, $expire) + { + return wincache_ucache_set($data, null, $expire); + } + + /** * Stores a value identified by a key into cache if the cache does not contain this key. * This is the implementation of the method declared in the parent class. * @@ -86,6 +97,19 @@ class WinCache extends Cache } /** + * Adds multiple key-value pairs to cache. + * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache + * storage supports multiadd, this method should be overridden to exploit that feature. + * @param array $data array where key corresponds to cache key while value is the value stored + * @param integer $expire the number of seconds in which the cached values will expire. 0 means never expire. + * @return array array of failed keys + */ + protected function addValues($data, $expire) + { + return wincache_ucache_add($data, null, $expire); + } + + /** * Deletes a value with the specified key from cache * This is the implementation of the method declared in the parent class. * @param string $key the key of the value to be deleted diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index d51cebd..849cad0 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -93,15 +93,14 @@ abstract class CacheTestCase extends TestCase public function testMset() { - $this->markTestIncomplete('Work in progress'); - $cache = $this->getCacheInstance(); $cache->flush(); - $this->assertTrue($cache->mset(['string_test' => 'string_test', - 'number_test' => 42, - 'array_test' => ['array_test' => 'array_test'], - ])); + $cache->mset([ + 'string_test' => 'string_test', + 'number_test' => 42, + 'array_test' => ['array_test' => 'array_test'], + ]); $this->assertEquals('string_test', $cache->get('string_test')); @@ -185,6 +184,21 @@ abstract class CacheTestCase extends TestCase $this->assertEquals(13, $cache->get('add_test')); } + public function testMadd() + { + $cache = $this->prepare(); + + $this->assertFalse($cache->get('add_test')); + + $cache->madd([ + 'number_test' => 13, + 'add_test' => 13, + ]); + + $this->assertEquals(42, $cache->get('number_test')); + $this->assertEquals(13, $cache->get('add_test')); + } + public function testDelete() { $cache = $this->prepare();