GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( bd5521...7c9800 )
by Robert
40:43
created

Cache::setValues()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
ccs 5
cts 7
cp 0.7143
cc 3
eloc 6
nc 3
nop 2
crap 3.2098
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\caching;
9
10
use Yii;
11
use yii\base\Component;
12
use yii\helpers\StringHelper;
13
14
/**
15
 * Cache is the base class for cache classes supporting different cache storage implementations.
16
 *
17
 * A data item can be stored in the cache by calling [[set()]] and be retrieved back
18
 * later (in the same or different request) by [[get()]]. In both operations,
19
 * a key identifying the data item is required. An expiration time and/or a [[Dependency|dependency]]
20
 * can also be specified when calling [[set()]]. If the data item expires or the dependency
21
 * changes at the time of calling [[get()]], the cache will return no data.
22
 *
23
 * A typical usage pattern of cache is like the following:
24
 *
25
 * ```php
26
 * $key = 'demo';
27
 * $data = $cache->get($key);
28
 * if ($data === false) {
29
 *     // ...generate $data here...
30
 *     $cache->set($key, $data, $duration, $dependency);
31
 * }
32
 * ```
33
 *
34
 * Because Cache implements the [[\ArrayAccess]] interface, it can be used like an array. For example,
35
 *
36
 * ```php
37
 * $cache['foo'] = 'some data';
38
 * echo $cache['foo'];
39
 * ```
40
 *
41
 * Derived classes should implement the following methods which do the actual cache storage operations:
42
 *
43
 * - [[getValue()]]: retrieve the value with a key (if any) from cache
44
 * - [[setValue()]]: store the value with a key into cache
45
 * - [[addValue()]]: store the value only if the cache does not have this key before
46
 * - [[deleteValue()]]: delete the value with the specified key from cache
47
 * - [[flushValues()]]: delete all values from cache
48
 *
49
 * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
50
 *
51
 * @author Qiang Xue <[email protected]>
52
 * @since 2.0
53
 */
54
abstract class Cache extends Component implements \ArrayAccess
55
{
56
    /**
57
     * @var string a string prefixed to every cache key so that it is unique globally in the whole cache storage.
58
     * It is recommended that you set a unique cache key prefix for each application if the same cache
59
     * storage is being used by different applications.
60
     *
61
     * To ensure interoperability, only alphanumeric characters should be used.
62
     */
63
    public $keyPrefix;
64
    /**
65
     * @var null|array|false the functions used to serialize and unserialize cached data. Defaults to null, meaning
66
     * using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient
67
     * serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with
68
     * a two-element array. The first element specifies the serialization function, and the second the deserialization
69
     * function. If this property is set false, data will be directly sent to and retrieved from the underlying
70
     * cache component without any serialization or deserialization. You should not turn off serialization if
71
     * you are using [[Dependency|cache dependency]], because it relies on data serialization. Also, some
72
     * implementations of the cache can not correctly save and retrieve data different from a string type.
73
     */
74
    public $serializer;
75
    /**
76
     * @var integer default duration in seconds before a cache entry will expire. Default value is 0, meaning infinity.
77
     * This value is used by [[set()]] if the duration is not explicitly given.
78
     * @since 2.0.11
79
     */
80
    public $defaultDuration = 0;
81
82
83
    /**
84
     * Builds a normalized cache key from a given key.
85
     *
86
     * If the given key is a string containing alphanumeric characters only and no more than 32 characters,
87
     * then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key
88
     * is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]].
89
     *
90
     * @param mixed $key the key to be normalized
91
     * @return string the generated cache key
92 124
     */
93
    public function buildKey($key)
94 124
    {
95 106
        if (is_string($key)) {
96 106
            $key = ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key);
97 26
        } else {
98
            $key = md5(json_encode($key));
99
        }
100 124
101
        return $this->keyPrefix . $key;
102
    }
103
104
    /**
105
     * Retrieves a value from cache with a specified key.
106
     * @param mixed $key a key identifying the cached value. This can be a simple string or
107
     * a complex data structure consisting of factors representing the key.
108
     * @return mixed the value stored in cache, false if the value is not in the cache, expired,
109
     * or the dependency associated with the cached data has changed.
110 90
     */
111
    public function get($key)
112 90
    {
113 90
        $key = $this->buildKey($key);
114 90
        $value = $this->getValue($key);
115 57
        if ($value === false || $this->serializer === false) {
116 71
            return $value;
117 71
        } elseif ($this->serializer === null) {
118 71
            $value = unserialize($value);
119
        } else {
120
            $value = call_user_func($this->serializer[1], $value);
121 71
        }
122 70
        if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->isChanged($this))) {
123
            return $value[0];
124 3
        } else {
125
            return false;
126
        }
127
    }
128
129
    /**
130
     * Checks whether a specified key exists in the cache.
131
     * This can be faster than getting the value from the cache if the data is big.
132
     * In case a cache does not support this feature natively, this method will try to simulate it
133
     * but has no performance improvement over getting it.
134
     * Note that this method does not check whether the dependency associated
135
     * with the cached data, if there is any, has changed. So a call to [[get]]
136
     * may return false while exists returns true.
137
     * @param mixed $key a key identifying the cached value. This can be a simple string or
138
     * a complex data structure consisting of factors representing the key.
139
     * @return bool true if a value exists in cache, false if the value is not in the cache or expired.
140 2
     */
141
    public function exists($key)
142 2
    {
143 2
        $key = $this->buildKey($key);
144
        $value = $this->getValue($key);
145 2
146
        return $value !== false;
147
    }
148
149
    /**
150
     * Retrieves multiple values from cache with the specified keys.
151
     * Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
152
     * which may improve the performance. In case a cache does not support this feature natively,
153
     * this method will try to simulate it.
154
     *
155
     * @param string[] $keys list of string keys identifying the cached values
156
     * @return array list of cached values corresponding to the specified keys. The array
157
     * is returned in terms of (key, value) pairs.
158
     * If a value is not cached or expired, the corresponding array value will be false.
159
     * @deprecated This method is an alias for [[multiGet()]] and will be removed in 2.1.0.
160
     */
161
    public function mget($keys)
162
    {
163
        return $this->multiGet($keys);
164
    }
165
166
    /**
167
     * Retrieves multiple values from cache with the specified keys.
168
     * Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
169
     * which may improve the performance. In case a cache does not support this feature natively,
170
     * this method will try to simulate it.
171
     * @param string[] $keys list of string keys identifying the cached values
172
     * @return array list of cached values corresponding to the specified keys. The array
173
     * is returned in terms of (key, value) pairs.
174
     * If a value is not cached or expired, the corresponding array value will be false.
175
     * @since 2.0.7
176 13
     */
177
    public function multiGet($keys)
178 13
    {
179 13
        $keyMap = [];
180 13
        foreach ($keys as $key) {
181 13
            $keyMap[$key] = $this->buildKey($key);
182 13
        }
183 13
        $values = $this->getValues(array_values($keyMap));
184 13
        $results = [];
185 13
        foreach ($keyMap as $key => $newKey) {
186 13
            $results[$key] = false;
187 13
            if (isset($values[$newKey])) {
188
                if ($this->serializer === false) {
189
                    $results[$key] = $values[$newKey];
190 13
                } else {
191 13
                    $value = $this->serializer === null ? unserialize($values[$newKey])
192
                        : call_user_func($this->serializer[1], $values[$newKey]);
193 13
194 10
                    if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->isChanged($this))) {
195 10
                        $results[$key] = $value[0];
196
                    }
197 13
                }
198 13
            }
199
        }
200 13
201
        return $results;
202
    }
203
204
    /**
205
     * Stores a value identified by a key into cache.
206
     * If the cache already contains such a key, the existing value and
207
     * expiration time will be replaced with the new ones, respectively.
208
     *
209
     * @param mixed $key a key identifying the value to be cached. This can be a simple string or
210
     * a complex data structure consisting of factors representing the key.
211
     * @param mixed $value the value to be cached
212
     * @param int $duration default duration in seconds before the cache will expire. If not set,
213
     * default [[defaultDuration]] value is used.
214
     * @param Dependency $dependency dependency of the cached item. If the dependency changes,
215
     * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
216
     * This parameter is ignored if [[serializer]] is false.
217
     * @return bool whether the value is successfully stored into cache
218 85
     */
219
    public function set($key, $value, $duration = null, $dependency = null)
220 85
    {
221 56
        if ($duration === null) {
222 56
            $duration = $this->defaultDuration;
223
        }
224 85
225 9
        if ($dependency !== null && $this->serializer !== false) {
226 9
            $dependency->evaluateDependency($this);
227 85
        }
228 85
        if ($this->serializer === null) {
229 85
            $value = serialize([$value, $dependency]);
230
        } elseif ($this->serializer !== false) {
231
            $value = call_user_func($this->serializer[0], [$value, $dependency]);
232 85
        }
233
        $key = $this->buildKey($key);
234 85
235
        return $this->setValue($key, $value, $duration);
236
    }
237
238
    /**
239
     * Stores multiple items in cache. Each item contains a value identified by a key.
240
     * If the cache already contains such a key, the existing value and
241
     * expiration time will be replaced with the new ones, respectively.
242
     *
243
     * @param array $items the items to be cached, as key-value pairs.
244
     * @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
245
     * @param Dependency $dependency dependency of the cached items. If the dependency changes,
246
     * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
247
     * This parameter is ignored if [[serializer]] is false.
248
     * @return array array of failed keys
249
     * @deprecated This method is an alias for [[multiSet()]] and will be removed in 2.1.0.
250
     */
251
    public function mset($items, $duration = 0, $dependency = null)
252
    {
253
        return $this->multiSet($items, $duration, $dependency);
254
    }
255
256
    /**
257
     * Stores multiple items in cache. Each item contains a value identified by a key.
258
     * If the cache already contains such a key, the existing value and
259
     * expiration time will be replaced with the new ones, respectively.
260
     *
261
     * @param array $items the items to be cached, as key-value pairs.
262
     * @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
263
     * @param Dependency $dependency dependency of the cached items. If the dependency changes,
264
     * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
265
     * This parameter is ignored if [[serializer]] is false.
266
     * @return array array of failed keys
267
     * @since 2.0.7
268 15
     */
269
    public function multiSet($items, $duration = 0, $dependency = null)
270 15
    {
271
        if ($dependency !== null && $this->serializer !== false) {
272
            $dependency->evaluateDependency($this);
273
        }
274 15
275 15
        $data = [];
276 15
        foreach ($items as $key => $value) {
277 15
            if ($this->serializer === null) {
278 15
                $value = serialize([$value, $dependency]);
279
            } elseif ($this->serializer !== false) {
280
                $value = call_user_func($this->serializer[0], [$value, $dependency]);
281
            }
282 15
283 15
            $key = $this->buildKey($key);
284 15
            $data[$key] = $value;
285
        }
286 15
287
        return $this->setValues($data, $duration);
288
    }
289
290
    /**
291
     * Stores multiple items in cache. Each item contains a value identified by a key.
292
     * If the cache already contains such a key, the existing value and expiration time will be preserved.
293
     *
294
     * @param array $items the items to be cached, as key-value pairs.
295
     * @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
296
     * @param Dependency $dependency dependency of the cached items. If the dependency changes,
297
     * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
298
     * This parameter is ignored if [[serializer]] is false.
299
     * @return array array of failed keys
300
     * @deprecated This method is an alias for [[multiAdd()]] and will be removed in 2.1.0.
301
     */
302
    public function madd($items, $duration = 0, $dependency = null)
303
    {
304
        return $this->multiAdd($items, $duration, $dependency);
305
    }
306
307
    /**
308
     * Stores multiple items in cache. Each item contains a value identified by a key.
309
     * If the cache already contains such a key, the existing value and expiration time will be preserved.
310
     *
311
     * @param array $items the items to be cached, as key-value pairs.
312
     * @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
313
     * @param Dependency $dependency dependency of the cached items. If the dependency changes,
314
     * the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
315
     * This parameter is ignored if [[serializer]] is false.
316
     * @return array array of failed keys
317
     * @since 2.0.7
318 5
     */
319
    public function multiAdd($items, $duration = 0, $dependency = null)
320 5
    {
321
        if ($dependency !== null && $this->serializer !== false) {
322
            $dependency->evaluateDependency($this);
323
        }
324 5
325 5
        $data = [];
326 5
        foreach ($items as $key => $value) {
327 5
            if ($this->serializer === null) {
328 5
                $value = serialize([$value, $dependency]);
329
            } elseif ($this->serializer !== false) {
330
                $value = call_user_func($this->serializer[0], [$value, $dependency]);
331
            }
332 5
333 5
            $key = $this->buildKey($key);
334 5
            $data[$key] = $value;
335
        }
336 5
337
        return $this->addValues($data, $duration);
338
    }
339
340
    /**
341
     * Stores a value identified by a key into cache if the cache does not contain this key.
342
     * Nothing will be done if the cache already contains the key.
343
     * @param mixed $key a key identifying the value to be cached. This can be a simple string or
344
     * a complex data structure consisting of factors representing the key.
345
     * @param mixed $value the value to be cached
346
     * @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
347
     * @param Dependency $dependency dependency of the cached item. If the dependency changes,
348
     * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
349
     * This parameter is ignored if [[serializer]] is false.
350
     * @return bool whether the value is successfully stored into cache
351 8
     */
352
    public function add($key, $value, $duration = 0, $dependency = null)
353 8
    {
354
        if ($dependency !== null && $this->serializer !== false) {
355
            $dependency->evaluateDependency($this);
356 8
        }
357 8
        if ($this->serializer === null) {
358 8
            $value = serialize([$value, $dependency]);
359
        } elseif ($this->serializer !== false) {
360
            $value = call_user_func($this->serializer[0], [$value, $dependency]);
361 8
        }
362
        $key = $this->buildKey($key);
363 8
364
        return $this->addValue($key, $value, $duration);
365
    }
366
367
    /**
368
     * Deletes a value with the specified key from cache
369
     * @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or
370
     * a complex data structure consisting of factors representing the key.
371
     * @return bool if no error happens during deletion
372 33
     */
373
    public function delete($key)
374 33
    {
375
        $key = $this->buildKey($key);
376 33
377
        return $this->deleteValue($key);
378
    }
379
380
    /**
381
     * Deletes all values from cache.
382
     * Be careful of performing this operation if the cache is shared among multiple applications.
383
     * @return bool whether the flush operation was successful.
384 48
     */
385
    public function flush()
386 48
    {
387
        return $this->flushValues();
388
    }
389
390
    /**
391
     * Retrieves a value from cache with a specified key.
392
     * This method should be implemented by child classes to retrieve the data
393
     * from specific cache storage.
394
     * @param string $key a unique key identifying the cached value
395
     * @return mixed|false the value stored in cache, false if the value is not in the cache or expired. Most often
396
     * value is a string. If you have disabled [[serializer]], it could be something else.
397
     */
398
    abstract protected function getValue($key);
399
400
    /**
401
     * Stores a value identified by a key in cache.
402
     * This method should be implemented by child classes to store the data
403
     * in specific cache storage.
404
     * @param string $key the key identifying the value to be cached
405
     * @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
406
     * it could be something else.
407
     * @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
408
     * @return bool true if the value is successfully stored into cache, false otherwise
409
     */
410
    abstract protected function setValue($key, $value, $duration);
411
412
    /**
413
     * Stores a value identified by a key into cache if the cache does not contain this key.
414
     * This method should be implemented by child classes to store the data
415
     * in specific cache storage.
416
     * @param string $key the key identifying the value to be cached
417
     * @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
418
     * it could be something else.
419
     * @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
420
     * @return bool true if the value is successfully stored into cache, false otherwise
421
     */
422
    abstract protected function addValue($key, $value, $duration);
423
424
    /**
425
     * Deletes a value with the specified key from cache
426
     * This method should be implemented by child classes to delete the data from actual cache storage.
427
     * @param string $key the key of the value to be deleted
428
     * @return bool if no error happens during deletion
429
     */
430
    abstract protected function deleteValue($key);
431
432
    /**
433
     * Deletes all values from cache.
434
     * Child classes may implement this method to realize the flush operation.
435
     * @return bool whether the flush operation was successful.
436
     */
437
    abstract protected function flushValues();
438
439
    /**
440
     * Retrieves multiple values from cache with the specified keys.
441
     * The default implementation calls [[getValue()]] multiple times to retrieve
442
     * the cached values one by one. If the underlying cache storage supports multiget,
443
     * this method should be overridden to exploit that feature.
444
     * @param array $keys a list of keys identifying the cached values
445
     * @return array a list of cached values indexed by the keys
446 10
     */
447
    protected function getValues($keys)
448 10
    {
449 10
        $results = [];
450 10
        foreach ($keys as $key) {
451 10
            $results[$key] = $this->getValue($key);
452
        }
453 10
454
        return $results;
455
    }
456
457
    /**
458
     * Stores multiple key-value pairs in cache.
459
     * The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache
460
     * storage supports multi-set, this method should be overridden to exploit that feature.
461
     * @param array $data array where key corresponds to cache key while value is the value stored
462
     * @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
463
     * @return array array of failed keys
464 13
     */
465
    protected function setValues($data, $duration)
466 13
    {
467 13
        $failedKeys = [];
468 13
        foreach ($data as $key => $value) {
469
            if ($this->setValue($key, $value, $duration) === false) {
470
                $failedKeys[] = $key;
471 13
            }
472
        }
473 13
474
        return $failedKeys;
475
    }
476
477
    /**
478
     * Adds multiple key-value pairs to cache.
479
     * The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache
480
     * storage supports multi-add, this method should be overridden to exploit that feature.
481
     * @param array $data array where key corresponds to cache key while value is the value stored.
482
     * @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
483
     * @return array array of failed keys
484 5
     */
485
    protected function addValues($data, $duration)
486 5
    {
487 5
        $failedKeys = [];
488 5
        foreach ($data as $key => $value) {
489 5
            if ($this->addValue($key, $value, $duration) === false) {
490 5
                $failedKeys[] = $key;
491 5
            }
492
        }
493 5
494
        return $failedKeys;
495
    }
496
497
    /**
498
     * Returns whether there is a cache entry with a specified key.
499
     * This method is required by the interface [[\ArrayAccess]].
500
     * @param string $key a key identifying the cached value
501
     * @return bool
502
     */
503
    public function offsetExists($key)
504
    {
505
        return $this->get($key) !== false;
506
    }
507
508
    /**
509
     * Retrieves the value from cache with a specified key.
510
     * This method is required by the interface [[\ArrayAccess]].
511
     * @param string $key a key identifying the cached value
512
     * @return mixed the value stored in cache, false if the value is not in the cache or expired.
513 5
     */
514
    public function offsetGet($key)
515 5
    {
516
        return $this->get($key);
517
    }
518
519
    /**
520
     * Stores the value identified by a key into cache.
521
     * If the cache already contains such a key, the existing value will be
522
     * replaced with the new ones. To add expiration and dependencies, use the [[set()]] method.
523
     * This method is required by the interface [[\ArrayAccess]].
524
     * @param string $key the key identifying the value to be cached
525
     * @param mixed $value the value to be cached
526 40
     */
527
    public function offsetSet($key, $value)
528 40
    {
529 40
        $this->set($key, $value);
530
    }
531
532
    /**
533
     * Deletes the value with the specified key from cache
534
     * This method is required by the interface [[\ArrayAccess]].
535
     * @param string $key the key of the value to be deleted
536
     */
537
    public function offsetUnset($key)
538
    {
539
        $this->delete($key);
540
    }
541
542
    /**
543
     * Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key,
544
     * or to store the result of $closure execution if there is no cache available for the $key.
545
     *
546
     * Usage example:
547
     *
548
     * ```php
549
     * public function getTopProducts($count = 10) {
550
     *     $cache = $this->cache; // Could be Yii::$app->cache
551
     *     return $cache->getOrSet(['top-n-products', 'n' => $count], function ($cache) use ($count) {
552
     *         return Products::find()->mostPopular()->limit(10)->all();
553
     *     }, 1000);
554
     * }
555
     * ```
556
     *
557
     * @param mixed $key a key identifying the value to be cached. This can be a simple string or
558
     * a complex data structure consisting of factors representing the key.
559
     * @param \Closure $closure the closure that will be used to generate a value to be cached.
560
     * In case $closure returns `false`, the value will not be cached.
561
     * @param int $duration default duration in seconds before the cache will expire. If not set,
562
     * [[defaultDuration]] value will be used.
563
     * @param Dependency $dependency dependency of the cached item. If the dependency changes,
564
     * the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
565
     * This parameter is ignored if [[serializer]] is `false`.
566
     * @return mixed result of $closure execution
567
     * @since 2.0.11
568
     */
569
    public function getOrSet($key, \Closure $closure, $duration = null, $dependency = null)
570
    {
571
        if (($value = $this->get($key)) !== false) {
572
            return $value;
573
        }
574
575
        $value = call_user_func($closure, $this);
576
        if (!$this->set($key, $value, $duration, $dependency)) {
577
            Yii::warning('Failed to set cache value for key ' . json_encode($value), __METHOD__);
578
        }
579
580
        return $value;
581
    }
582
}
583