mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-02 21:41:19 +08:00
Added Cache::getOrSet()
This commit is contained in:
@ -11,8 +11,8 @@
|
|||||||
$data = $cache->get($key);
|
$data = $cache->get($key);
|
||||||
|
|
||||||
if ($data === false) {
|
if ($data === false) {
|
||||||
|
// $data нет в кэше, вычисляем заново
|
||||||
// $data нет в кэше, считаем с нуля.
|
$data = $this->calculateSomething();
|
||||||
|
|
||||||
// Сохраняем значение $data в кэше. Данные можно получить в следующий раз.
|
// Сохраняем значение $data в кэше. Данные можно получить в следующий раз.
|
||||||
$cache->set($key, $data);
|
$cache->set($key, $data);
|
||||||
@ -21,6 +21,33 @@ if ($data === false) {
|
|||||||
// Значение $data доступно здесь.
|
// Значение $data доступно здесь.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Начиная с версии 2.0.11, [компонент кэширования](#cache-components) предоставляет метод
|
||||||
|
[[yii\caching\Cache::getOrSet()|getOrSet()]], который упрощает код при получении, вычислении и сохранении данных.
|
||||||
|
Приведённый ниже код делает в точности то же самое, что и код в предыдущем примере:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$data = $cache->getOrSet($key, function () {
|
||||||
|
return $this->calculateSomething();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Если в кэше есть данные по ключу `$key`, они будут сразу возвращены.
|
||||||
|
Иначе, будет вызвана переданная анонимная функция, вычисляющаяя значение, которое будет сохранено в кэш и возвращено
|
||||||
|
из метода.
|
||||||
|
|
||||||
|
В случае, когда анонимной функции требуются данные из внешней области видимости, можно передать их с помощью
|
||||||
|
оператора `use`. Например:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$user_id = 42;
|
||||||
|
$data = $cache->getOrSet($key, function () use ($user_id) {
|
||||||
|
return $this->calculateSomething($user_id);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: В [[yii\caching\Cache::getOrSet()|getOrSet()]] можно передать срока действия и зависимости кэша.
|
||||||
|
Прочтите [Срок действия кэша](#cache-expiration) и [Зависимости кеша](#cache-dependencies) чтобы узнать больше.
|
||||||
|
|
||||||
|
|
||||||
## Компоненты кэширования <span id="cache-components"></span>
|
## Компоненты кэширования <span id="cache-components"></span>
|
||||||
|
|
||||||
@ -161,8 +188,8 @@ if ($data === false) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Начиная с версии 2.0.11 вы можете изменить значение по умолчанию (бесконечность) для длительности кеширования задав
|
Начиная с версии 2.0.11 вы можете изменить значение по умолчанию (бесконечность) для длительности кэширования задав
|
||||||
[[yii\caching\Cache::$defaultDuration|defaultDuration]] в конфигурации компонента кеша. Таким образом, можно будет
|
[[yii\caching\Cache::$defaultDuration|defaultDuration]] в конфигурации компонента кэша. Таким образом, можно будет
|
||||||
не передавать значение `duration` в [[yii\caching\Cache::set()|set()]] каждый раз.
|
не передавать значение `duration` в [[yii\caching\Cache::set()|set()]] каждый раз.
|
||||||
|
|
||||||
### Зависимости кэша <span id="cache-dependencies"></span>
|
### Зависимости кэша <span id="cache-dependencies"></span>
|
||||||
@ -231,7 +258,7 @@ $result = Customer::getDb()->cache(function ($db) {
|
|||||||
- `yii cache`: отображает список доступных кэширующих компонентов приложения
|
- `yii cache`: отображает список доступных кэширующих компонентов приложения
|
||||||
- `yii cache/flush cache1 cache2`: очищает кэш в компонентах `cache1`, `cache2` (можно передать несколько названий
|
- `yii cache/flush cache1 cache2`: очищает кэш в компонентах `cache1`, `cache2` (можно передать несколько названий
|
||||||
компонентов кэширования, разделяя их пробелом)
|
компонентов кэширования, разделяя их пробелом)
|
||||||
- `yii cache/flush-all`: очищает кэш во всех кеширующих компонентах приложения
|
- `yii cache/flush-all`: очищает кэш во всех кэширующих компонентах приложения
|
||||||
|
|
||||||
> Info: Консольное приложение использует отдельный конфигурационный файл по умолчанию. Для получения должного
|
> Info: Консольное приложение использует отдельный конфигурационный файл по умолчанию. Для получения должного
|
||||||
результата, убедитесь, что в конфигурациях консольного и веб-приложения у вас одинаковые компоненты кэширования.
|
результата, убедитесь, что в конфигурациях консольного и веб-приложения у вас одинаковые компоненты кэширования.
|
||||||
@ -311,4 +338,4 @@ $result = $db->cache(function ($db) {
|
|||||||
|
|
||||||
Кэширование запросов не работает с результатами запросов, которые содержат обработчики ресурсов. Например, при использовании типа столбца `BLOB` в некоторых СУБД, в качестве результата запроса будет выведен ресурс обработчик данных столбца.
|
Кэширование запросов не работает с результатами запросов, которые содержат обработчики ресурсов. Например, при использовании типа столбца `BLOB` в некоторых СУБД, в качестве результата запроса будет выведен ресурс обработчик данных столбца.
|
||||||
|
|
||||||
Некоторые кэш хранилища имеют ограничение в размере данных. Например, Memcache ограничивает максимальный размер каждой записи до 1 Мб. Таким образом, если результат запроса превышает этот предел, данные не будут закешированы.
|
Некоторые кэш хранилища имеют ограничение в размере данных. Например, Memcache ограничивает максимальный размер каждой записи до 1 Мб. Таким образом, если результат запроса превышает этот предел, данные не будут закэшированы.
|
||||||
|
|||||||
@ -13,8 +13,8 @@ a [cache component](#cache-components):
|
|||||||
$data = $cache->get($key);
|
$data = $cache->get($key);
|
||||||
|
|
||||||
if ($data === false) {
|
if ($data === false) {
|
||||||
|
|
||||||
// $data is not found in cache, calculate it from scratch
|
// $data is not found in cache, calculate it from scratch
|
||||||
|
$data = $this->calculateSomething();
|
||||||
|
|
||||||
// store $data in cache so that it can be retrieved next time
|
// store $data in cache so that it can be retrieved next time
|
||||||
$cache->set($key, $data);
|
$cache->set($key, $data);
|
||||||
@ -23,6 +23,32 @@ if ($data === false) {
|
|||||||
// $data is available here
|
// $data is available here
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Since version 2.0.11, [cache component](#cache-components) provides [[yii\caching\Cache::getOrSet()|getOrSet()]] method
|
||||||
|
that simplifies code for data getting, calculating and storing. The following code does exactly the same as the
|
||||||
|
previous example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$data = $cache->getOrSet($key, function () {
|
||||||
|
return $this->calculateSomething();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
When cache has data associated with the `$key`, the cached value will be returned.
|
||||||
|
Otherwise, the passed anonymous function will be executed to calculate the value that will be cached and returned.
|
||||||
|
|
||||||
|
If the anonymous function requires some data from the outer scope, you can pass it with the `use` statement.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$user_id = 42;
|
||||||
|
$data = $cache->getOrSet($key, function () use ($user_id) {
|
||||||
|
return $this->calculateSomething($user_id);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: [[yii\caching\Cache::getOrSet()|getOrSet()]] method supports duration and dependencies as well.
|
||||||
|
See [Cache Expiration](#cache-expiration) and [Cache Dependencies](#cache-dependencies) to know more.
|
||||||
|
|
||||||
|
|
||||||
## Cache Components <span id="cache-components"></span>
|
## Cache Components <span id="cache-components"></span>
|
||||||
|
|
||||||
@ -118,6 +144,8 @@ All cache components have the same base class [[yii\caching\Cache]] and thus sup
|
|||||||
value will be returned if the data item is not found in the cache or is expired/invalidated.
|
value will be returned if the data item is not found in the cache or is expired/invalidated.
|
||||||
* [[yii\caching\Cache::set()|set()]]: stores a data item identified by a key in cache.
|
* [[yii\caching\Cache::set()|set()]]: stores a data item identified by a key in cache.
|
||||||
* [[yii\caching\Cache::add()|add()]]: stores a data item identified by a key in cache if the key is not found in the cache.
|
* [[yii\caching\Cache::add()|add()]]: stores a data item identified by a key in cache if the key is not found in the cache.
|
||||||
|
* [[yii\caching\Cache::getOrSet()|getOrSet()]]: retrieves a data item from cache with a specified key or executes passed
|
||||||
|
callback, stores return of the callback in a cache by a key and returns that data.
|
||||||
* [[yii\caching\Cache::multiGet()|multiGet()]]: retrieves multiple data items from cache with the specified keys.
|
* [[yii\caching\Cache::multiGet()|multiGet()]]: retrieves multiple data items from cache with the specified keys.
|
||||||
* [[yii\caching\Cache::multiSet()|multiSet()]]: stores multiple data items in cache. Each item is identified by a key.
|
* [[yii\caching\Cache::multiSet()|multiSet()]]: stores multiple data items in cache. Each item is identified by a key.
|
||||||
* [[yii\caching\Cache::multiAdd()|multiAdd()]]: stores multiple data items in cache. Each item is identified by a key.
|
* [[yii\caching\Cache::multiAdd()|multiAdd()]]: stores multiple data items in cache. Each item is identified by a key.
|
||||||
@ -128,7 +156,7 @@ All cache components have the same base class [[yii\caching\Cache]] and thus sup
|
|||||||
|
|
||||||
> Note: Do not cache a `false` boolean value directly because the [[yii\caching\Cache::get()|get()]] method uses
|
> Note: Do not cache a `false` boolean value directly because the [[yii\caching\Cache::get()|get()]] method uses
|
||||||
`false` return value to indicate the data item is not found in the cache. You may put `false` in an array and cache
|
`false` return value to indicate the data item is not found in the cache. You may put `false` in an array and cache
|
||||||
this array instead to avoid this problem.
|
this array instead to avoid this problem.
|
||||||
|
|
||||||
Some cache storage, such as MemCache, APC, support retrieving multiple cached values in a batch mode,
|
Some cache storage, such as MemCache, APC, support retrieving multiple cached values in a batch mode,
|
||||||
which may reduce the overhead involved in retrieving cached data. The APIs [[yii\caching\Cache::multiGet()|multiGet()]]
|
which may reduce the overhead involved in retrieving cached data. The APIs [[yii\caching\Cache::multiGet()|multiGet()]]
|
||||||
|
|||||||
@ -85,9 +85,11 @@ Yii Framework 2 Change Log
|
|||||||
- Enh #13074: Improved `yii\log\SyslogTarget` with `$options` to be able to change the default `openlog` options (timbeks)
|
- Enh #13074: Improved `yii\log\SyslogTarget` with `$options` to be able to change the default `openlog` options (timbeks)
|
||||||
- Bug: #12969: Improved unique ID generation for `yii\widgets\Pjax` widgets (dynasource, samdark, rob006)
|
- Bug: #12969: Improved unique ID generation for `yii\widgets\Pjax` widgets (dynasource, samdark, rob006)
|
||||||
- Enh #13122: Optimized query for information about foreign keys in `yii\db\oci` (zlakomanoff)
|
- Enh #13122: Optimized query for information about foreign keys in `yii\db\oci` (zlakomanoff)
|
||||||
|
- Enh #11959: Added `yii\caching\Cache::getOrSet()` method (silverfire)
|
||||||
- Enh #13202: Refactor validateAttribute method in UniqueValidator (developeruz)
|
- Enh #13202: Refactor validateAttribute method in UniqueValidator (developeruz)
|
||||||
- Enh: Added constants for specifying `yii\validators\CompareValidator::$type` (cebe)
|
- Enh: Added constants for specifying `yii\validators\CompareValidator::$type` (cebe)
|
||||||
|
|
||||||
|
- Enh #11959: Added `yii\caching\Cache::closure()` method to cache closures (silverfire)
|
||||||
|
|
||||||
2.0.10 October 20, 2016
|
2.0.10 October 20, 2016
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
namespace yii\caching;
|
namespace yii\caching;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
use yii\base\Component;
|
use yii\base\Component;
|
||||||
use yii\helpers\StringHelper;
|
use yii\helpers\StringHelper;
|
||||||
|
|
||||||
@ -537,4 +538,45 @@ abstract class Cache extends Component implements \ArrayAccess
|
|||||||
{
|
{
|
||||||
$this->delete($key);
|
$this->delete($key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key,
|
||||||
|
* or to store the result of $closure execution if there is no cache available for the $key.
|
||||||
|
*
|
||||||
|
* Usage example:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* public function getTopProducts($count = 10) {
|
||||||
|
* $cache = $this->cache; // Could be Yii::$app->cache
|
||||||
|
* return $cache->getOrSet(['top-n-products', 'n' => $count], function ($cache) use ($count) {
|
||||||
|
* return Products::find()->mostPopular()->limit(10)->all();
|
||||||
|
* }, 1000);
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||||
|
* a complex data structure consisting of factors representing the key.
|
||||||
|
* @param \Closure $closure the closure that will be used to generate a value to be cached.
|
||||||
|
* In case $closure returns `false`, the value will not be cached.
|
||||||
|
* @param int $duration default duration in seconds before the cache will expire. If not set,
|
||||||
|
* [[defaultDuration]] value will be used.
|
||||||
|
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||||
|
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||||
|
* This parameter is ignored if [[serializer]] is `false`.
|
||||||
|
* @return mixed result of $closure execution
|
||||||
|
* @since 2.0.11
|
||||||
|
*/
|
||||||
|
public function getOrSet($key, \Closure $closure, $duration = null, $dependency = null)
|
||||||
|
{
|
||||||
|
if (($value = $this->get($key)) !== false) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = call_user_func($closure, $this);
|
||||||
|
if (!$this->set($key, $value, $duration, $dependency)) {
|
||||||
|
Yii::warning('Failed to set cache value for key ' . json_encode($value), __METHOD__);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ function microtime($float = false)
|
|||||||
namespace yiiunit\framework\caching;
|
namespace yiiunit\framework\caching;
|
||||||
|
|
||||||
use yii\caching\Cache;
|
use yii\caching\Cache;
|
||||||
|
use yii\caching\TagDependency;
|
||||||
use yiiunit\TestCase;
|
use yiiunit\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,22 +100,22 @@ abstract class CacheTestCase extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array testing mset with and without expiry
|
* @return array testing multiSet with and without expiry
|
||||||
*/
|
*/
|
||||||
public function msetExpiry()
|
public function multiSetExpiry()
|
||||||
{
|
{
|
||||||
return [[0], [2]];
|
return [[0], [2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider msetExpiry
|
* @dataProvider multiSetExpiry
|
||||||
*/
|
*/
|
||||||
public function testMset($expiry)
|
public function testMultiset($expiry)
|
||||||
{
|
{
|
||||||
$cache = $this->getCacheInstance();
|
$cache = $this->getCacheInstance();
|
||||||
$cache->flush();
|
$cache->flush();
|
||||||
|
|
||||||
$cache->mset([
|
$cache->multiSet([
|
||||||
'string_test' => 'string_test',
|
'string_test' => 'string_test',
|
||||||
'number_test' => 42,
|
'number_test' => 42,
|
||||||
'array_test' => ['array_test' => 'array_test'],
|
'array_test' => ['array_test' => 'array_test'],
|
||||||
@ -167,14 +168,14 @@ abstract class CacheTestCase extends TestCase
|
|||||||
$this->assertTrue($cache->get('bool_value'));
|
$this->assertTrue($cache->get('bool_value'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMget()
|
public function testMultiGet()
|
||||||
{
|
{
|
||||||
$cache = $this->prepare();
|
$cache = $this->prepare();
|
||||||
|
|
||||||
$this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->mget(['string_test', 'number_test']));
|
$this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->multiGet(['string_test', 'number_test']));
|
||||||
// ensure that order does not matter
|
// ensure that order does not matter
|
||||||
$this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->mget(['number_test', 'string_test']));
|
$this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->multiGet(['number_test', 'string_test']));
|
||||||
$this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->mget(['number_test', 'non_existent_key']));
|
$this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->multiGet(['number_test', 'non_existent_key']));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDefaultTtl()
|
public function testDefaultTtl()
|
||||||
@ -220,13 +221,13 @@ abstract class CacheTestCase extends TestCase
|
|||||||
$this->assertEquals(13, $cache->get('add_test'));
|
$this->assertEquals(13, $cache->get('add_test'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMadd()
|
public function testMultiAdd()
|
||||||
{
|
{
|
||||||
$cache = $this->prepare();
|
$cache = $this->prepare();
|
||||||
|
|
||||||
$this->assertFalse($cache->get('add_test'));
|
$this->assertFalse($cache->get('add_test'));
|
||||||
|
|
||||||
$cache->madd([
|
$cache->multiAdd([
|
||||||
'number_test' => 13,
|
'number_test' => 13,
|
||||||
'add_test' => 13,
|
'add_test' => 13,
|
||||||
]);
|
]);
|
||||||
@ -250,4 +251,22 @@ abstract class CacheTestCase extends TestCase
|
|||||||
$this->assertTrue($cache->flush());
|
$this->assertTrue($cache->flush());
|
||||||
$this->assertFalse($cache->get('number_test'));
|
$this->assertFalse($cache->get('number_test'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetOrSet()
|
||||||
|
{
|
||||||
|
$cache = $this->prepare();
|
||||||
|
$dependency = new TagDependency(['tags' => 'test']);
|
||||||
|
|
||||||
|
$expected = 'SilverFire';
|
||||||
|
$loginClosure = function ($cache) use (&$login) { return 'SilverFire'; };
|
||||||
|
$this->assertEquals($expected, $cache->getOrSet('some-login', $loginClosure, null, $dependency));
|
||||||
|
|
||||||
|
// Call again with another login to make sure that value is cached
|
||||||
|
$loginClosure = function ($cache) use (&$login) { return 'SamDark'; };
|
||||||
|
$this->assertEquals($expected, $cache->getOrSet('some-login', $loginClosure, null, $dependency));
|
||||||
|
|
||||||
|
$dependency->invalidate($cache, 'test');
|
||||||
|
$expected = 'SamDark';
|
||||||
|
$this->assertEquals($expected, $cache->getOrSet('some-login', $loginClosure, null, $dependency));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user