Dependency::isChanged()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 13
ccs 6
cts 6
cp 1
rs 10
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Cache\Dependency;
6
7
use Traversable;
8
use Yiisoft\Cache\CacheInterface;
9
10
use function array_key_exists;
11
use function iterator_to_array;
12
use function serialize;
13
use function sha1;
14
15
/**
16
 * Dependency is the base class for cache dependency classes.
17
 *
18
 * Child classes should override its {@see Dependency::generateDependencyData()}
19
 * for generating the actual dependency data.
20
 */
21
abstract class Dependency
22
{
23
    /**
24
     * @var mixed The dependency data that is saved in cache and later is compared with the latest dependency data.
25
     */
26
    protected mixed $data = null;
27
28
    /**
29
     * @var bool Whether this dependency is reusable or not. True value means that dependent
30
     * data for this cache dependency will be generated only once per request. This allows you
31
     * to use the same cache dependency for multiple separate cache calls while generating the same
32
     * page without an overhead of re-evaluating dependency data each time. Defaults to false.
33
     */
34
    protected bool $isReusable = false;
35
36
    /**
37
     * @var array Static storage of cached data for reusable dependencies.
38
     * @psalm-var array<string, mixed>
39
     */
40
    private static array $reusableData = [];
41
42
    /**
43
     * Changes dependency behavior so dependent data for this cache dependency will be generated only once per request.
44
     * This allows you to use the same cache dependency for multiple separate cache calls while generating the same
45
     * page without an overhead of re-evaluating dependency data each time.
46
     */
47 3
    public function markAsReusable(): void
48
    {
49 3
        $this->isReusable = true;
50
    }
51
52
    /**
53
     * Evaluates the dependency by generating and saving the data related with dependency.
54
     *
55
     * This method is invoked by cache before writing data into it.
56
     *
57
     * @param CacheInterface $cache The cache component that is currently evaluating this dependency.
58
     */
59 27
    public function evaluateDependency(CacheInterface $cache): void
60
    {
61 27
        if (!$this->isReusable) {
62 25
            $this->data = $this->generateDependencyData($cache);
63 24
            return;
64
        }
65
66 2
        $hash = $this->generateReusableHash();
67
68 2
        if (!array_key_exists($hash, self::$reusableData)) {
69
            self::$reusableData[$hash] = $this->generateDependencyData($cache);
70 2
        }
71
72
        $this->data = self::$reusableData[$hash];
73 2
    }
74
75
    /**
76
     * Checks whether the dependency is changed.
77
     *
78
     * @param CacheInterface $cache The cache component that is currently evaluating this dependency
79
     *
80
     * @return bool Whether the dependency has changed.
81
     */
82
    public function isChanged(CacheInterface $cache): bool
83 17
    {
84
        if (!$this->isReusable) {
85 17
            return $this->data !== $this->generateDependencyData($cache);
86 15
        }
87
88
        $hash = $this->generateReusableHash();
89 2
90
        if (!array_key_exists($hash, self::$reusableData)) {
91 2
            self::$reusableData[$hash] = $this->generateDependencyData($cache);
92
        }
93 1
94
        return $this->data !== self::$reusableData[$hash];
95
    }
96 2
97
    /**
98
     * Resets all cached data for reusable dependencies.
99
     */
100
    public static function resetReusableData(): void
101
    {
102 1
        self::$reusableData = [];
103
    }
104 1
105
    /**
106
     * Generates a unique hash that can be used for retrieving reusable dependency data.
107
     *
108
     * @return string A unique hash value for this cache dependency.
109
     *
110
     * @see isReusable()
111
     */
112
    protected function generateReusableHash(): string
113
    {
114 4
        $data = $this->data;
115
        $this->data = null; // https://github.com/yiisoft/yii2/issues/3052
116
        $key = sha1(serialize($this));
117 4
        $this->data = $data;
118 4
        return $key;
119 4
    }
120 4
121 4
    /**
122
     * Converts iterable to array.
123
     *
124
     * @return array
125
     */
126
    protected function iterableToArray(iterable $iterable): array
127
    {
128
        /** @psalm-suppress RedundantCast */
129
        return $iterable instanceof Traversable ? iterator_to_array($iterable) : (array) $iterable;
130
    }
131 22
132
    /**
133
     * Generates the data needed to determine if dependency is changed.
134 22
     *
135
     * Derived classes should override this method to generate the actual dependency data.
136
     *
137
     * @param CacheInterface $cache The cache component that is currently evaluating this dependency.
138
     *
139
     * @return mixed The data needed to determine if dependency has been changed.
140
     */
141
    abstract protected function generateDependencyData(CacheInterface $cache): mixed;
142
}
143