Passed
Push — master ( c2b4c4...fd18cf )
by Alexander
03:23 queued 01:03
created

TagDependency   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Test Coverage

Coverage 96.88%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 13
eloc 27
c 1
b 0
f 0
dl 0
loc 101
ccs 31
cts 32
cp 0.9688
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 3
A generateDependencyData() 0 16 3
A buildCacheKeys() 0 9 2
A invalidate() 0 3 1
A buildCacheKey() 0 9 2
A isChanged() 0 4 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Cache\Dependency;
6
7
use Yiisoft\Cache\CacheInterface;
8
use Yiisoft\Cache\Exception\InvalidArgumentException;
9
10
use function json_encode;
11
use function json_last_error_msg;
12
use function md5;
13
14
/**
15
 * TagDependency associates a cached value with one or multiple {@see TagDependency::$tags}.
16
 *
17
 * By calling {@see TagDependency::invalidate()}, you can invalidate all
18
 * cached values that are associated with the specified tag name(s).
19
 *
20
 * ```php
21
 * // setting multiple cache keys to store data forever and tagging them with "user-123"
22
 * $cache->getOrSet('user_42_profile', '', null, new TagDependency('user-123'));
23
 * $cache->getOrSet('user_42_stats', '', null, new TagDependency('user-123'));
24
 *
25
 *  // setting a cache key to store data and tagging them with "user-123" with the specified TTL for the tag
26
 * $cache->getOrSet('user_42_profile', '', null, new TagDependency('user-123', 3600));
27
 *
28
 * // invalidating all keys tagged with "user-123"
29
 * TagDependency::invalidate($cache, 'user-123');
30
 * ```
31
 */
32
final class TagDependency extends Dependency
33
{
34
    /**
35
     * @var array List of tag names for this dependency.
36
     */
37
    private array $tags;
38
39
    /**
40
     * @var int|null The TTL value of this item. null means infinity.
41
     */
42
    private ?int $ttl;
43
44
    /**
45
     * @param array|string $tags List of tag names for this dependency.
46
     * For a single tag, you may specify it as a string.
47
     * @param int|null $ttl The TTL value of this item. null means infinity.
48
     */
49 24
    public function __construct($tags, int $ttl = null)
50
    {
51 24
        $this->tags = (array) $tags;
52
53 24
        if ($ttl !== null && $ttl < 1) {
54 1
            throw new InvalidArgumentException(
55
                'TTL must be a positive number or null, to invalidate tags, use the'
56 1
                . ' static `\Yiisoft\Cache\Dependency\TagDependency::invalidate()` method.',
57
            );
58
        }
59
60 23
        $this->ttl = $ttl;
61 23
    }
62
63 22
    protected function generateDependencyData(CacheInterface $cache): array
64
    {
65 22
        if (empty($this->tags)) {
66 1
            return [];
67
        }
68
69 21
        $tags = [];
70
71 21
        foreach ($this->tags as $tag) {
72 21
            $tag = (string) $tag;
73 21
            $tags[self::buildCacheKey($tag)] = $tag;
74
        }
75
76 21
        $cache->psr()->setMultiple($tags, $this->ttl);
77
78 21
        return $tags;
79
    }
80
81 17
    public function isChanged(CacheInterface $cache): bool
82
    {
83 17
        $tags = empty($this->tags) ? [] : $cache->psr()->getMultiple(self::buildCacheKeys($this->tags));
84 16
        return $this->data !== $tags;
85
    }
86
87
    /**
88
     * Invalidates all of the cached values that are associated with any of the specified {@see tags}.
89
     *
90
     * @param CacheInterface $cache The cache component that caches the values.
91
     * @param array|string $tags
92
     */
93 8
    public static function invalidate(CacheInterface $cache, $tags): void
94
    {
95 8
        $cache->psr()->deleteMultiple(self::buildCacheKeys($tags));
96 8
    }
97
98
    /**
99
     * Builds a normalized cache key from a given tag, making sure it is short enough and safe
100
     * for any particular cache storage.
101
     *
102
     * @param string $tag The tag name.
103
     *
104
     * @return string The cache key.
105
     */
106 22
    private static function buildCacheKey(string $tag): string
107
    {
108 22
        $jsonTag = json_encode([__CLASS__, $tag]);
109
110 22
        if ($jsonTag === false) {
111
            throw new InvalidArgumentException('Invalid tag. ' . json_last_error_msg());
112
        }
113
114 22
        return md5($jsonTag);
115
    }
116
117
    /**
118
     * Builds array of keys from a given tags.
119
     *
120
     * @param mixed $tags
121
     *
122
     * @return array
123
     */
124 17
    private static function buildCacheKeys($tags): array
125
    {
126 17
        $keys = [];
127
128 17
        foreach ((array) $tags as $tag) {
129 17
            $keys[] = self::buildCacheKey((string) $tag);
130
        }
131
132 16
        return $keys;
133
    }
134
}
135