Passed
Push — master ( c03bea...c0a5b3 )
by Rustam
01:44
created

FragmentCache   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Test Coverage

Coverage 81.03%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 53
c 2
b 1
f 0
dl 0
loc 232
ccs 47
cts 58
cp 0.8103
rs 10
wmc 23

12 Methods

Rating   Name   Duplication   Size   Complexity  
A calculateKey() 0 3 1
A dependency() 0 5 1
B getCachedContent() 0 26 7
A __construct() 0 4 1
A cache() 0 5 1
A run() 0 22 5
A start() 0 6 2
A content() 0 5 1
A id() 0 5 1
A variations() 0 5 1
A duration() 0 5 1
A getView() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Widgets;
6
7
use Yiisoft\Cache\CacheInterface;
8
use Yiisoft\Cache\Dependency\Dependency;
9
use Yiisoft\View\DynamicContentAwareInterface;
10
use Yiisoft\View\DynamicContentAwareTrait;
11
use Yiisoft\View\View;
12
use Yiisoft\View\WebView;
13
use Yiisoft\Widget\Widget;
14
15
/**
16
 * FragmentCache is used by {@see \Yiisoft\View\View} to provide caching of page fragments.
17
 *
18
 * @property-read string|false $cachedContent The cached content. False is returned if valid content is not found in the
19
 * cache. This property is read-only.
20
 */
21
class FragmentCache extends Widget implements DynamicContentAwareInterface
22
{
23
    use DynamicContentAwareTrait;
24
25
    private string $id;
26
27
    /**
28
     * @var CacheInterface|null the cache object or the application component ID of the cache object.
29
     *
30
     * After the FragmentCache object is created, if you want to change this property, you should only assign it with
31
     * a cache object.
32
     */
33
    private ?CacheInterface $cache = null;
34
35
    /**
36
     * @var int number of seconds that the data can remain valid in cache.
37
     *
38
     * Use 0 to indicate that the cached data will never expire.
39
     */
40
    private int $duration = 60;
41
42
    /**
43
     * @var Dependency|null the dependency that the cached content depends on.
44
     *
45
     * This can be either a {@see Dependency} object or a configuration array for creating the dependency object.
46
     *
47
     * Would make the output cache depends on the last modified time of all posts. If any post has its modification time
48
     * changed, the cached content would be invalidated.
49
     */
50
    private ?Dependency $dependency = null;
51
52
    /**
53
     * @var string[]|string list of factors that would cause the variation of the content being cached.
54
     *
55
     * Each factor is a string representing a variation (e.g. the language, a GET parameter). The following variation
56
     * setting will cause the content to be cached in different versions according to the current application language:
57
     */
58
    private $variations;
59
60
    /**
61
     * @var string|bool the cached content. Null if the content is not cached.
62
     */
63
    private $content = false;
64
65
    private WebView $webView;
66
67 7
    public function __construct(CacheInterface $cache, WebView $webview)
68
    {
69 7
        $this->cache = $cache;
70 7
        $this->webView = $webview;
71 7
    }
72
73
    /**
74
     * Initializes the FragmentCache object.
75
     */
76 7
    public function start(): void
77
    {
78 7
        if ($this->getCachedContent() === false) {
79 7
            $this->webView->pushDynamicContent($this);
80 7
            ob_start();
81 7
            ob_implicit_flush(0);
82
        }
83 7
    }
84
85
    /**
86
     * Marks the end of content to be cached.
87
     *
88
     * Content displayed before this method call and after {@see init()} will be captured and saved in cache.
89
     *
90
     * This method does nothing if valid content is already found in cache.
91
     *
92
     * @return string the result of widget execution to be outputted.
93
     */
94 7
    public function run(): string
95
    {
96 7
        if (($content = $this->getCachedContent()) !== false) {
97 1
            return $content;
98
        }
99
100 7
        if ($this->cache instanceof CacheInterface) {
101 6
            $this->webView->popDynamicContent();
102
103 6
            $content = ob_get_clean();
104
105 6
            if ($content === false || $content === '') {
106
                return '';
107
            }
108
109 6
            $data = [$content, $this->getDynamicPlaceholders()];
110 6
            $this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency);
111
112 6
            return $this->updateDynamicContent($content, $this->getDynamicPlaceholders());
113
        }
114
115 2
        return '';
116
    }
117
118
    /**
119
     * Returns the cached content if available.
120
     *
121
     * @return string|false the cached content. False is returned if valid content is not found in the cache.
122
     */
123 7
    public function getCachedContent()
124
    {
125 7
        if ($this->content !== null) {
126 7
            return $this->content;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->content also could return the type boolean which is incompatible with the documented return type false|string.
Loading history...
127
        }
128
129 1
        if (!($this->cache instanceof CacheInterface)) {
130
            return $this->content;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->content returns the type void which is incompatible with the documented return type false|string.
Loading history...
131
        }
132
133 1
        $key = $this->calculateKey();
134 1
        $data = $this->cache->get($key);
0 ignored issues
show
Bug introduced by
$key of type array is incompatible with the type string expected by parameter $key of Psr\SimpleCache\CacheInterface::get(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
        $data = $this->cache->get(/** @scrutinizer ignore-type */ $key);
Loading history...
135
136 1
        if (!\is_array($data) || count($data) !== 2) {
137
            return $this->content;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->content returns the type void which is incompatible with the documented return type false|string.
Loading history...
138
        }
139
140 1
        [$this->content, $placeholders] = $data;
141
142 1
        if (!\is_array($placeholders) || count($placeholders) === 0) {
143 1
            return $this->content;
144
        }
145
146
        $this->content = $this->updateDynamicContent($this->content, $placeholders, true);
147
148
        return $this->content;
149
    }
150
151
    /**
152
     * Generates a unique key used for storing the content in cache.
153
     *
154
     * The key generated depends on both {@see id} and {@see variations}.
155
     *
156
     * @return mixed a valid cache key
157
     */
158 6
    public function calculateKey()
159
    {
160 6
        return array_merge([__CLASS__, $this->id], (array) $this->variations);
161
    }
162
163
    /**
164
     * {@see $cache}
165
     *
166
     * @param CacheInterface|null $value
167
     *
168
     * @return FragmentCache
169
     */
170 2
    public function cache(?CacheInterface $value): FragmentCache
171
    {
172 2
        $this->cache = $value;
173
174 2
        return $this;
175
    }
176
177
    /**
178
     * {@see $content}
179
     *
180
     * @param string|bool $value
181
     *
182
     * @return FragmentCache
183
     */
184 1
    public function content($value): FragmentCache
185
    {
186 1
        $this->content = $value;
187
188 1
        return $this;
189
    }
190
191
    /**
192
     * {@see $dependency}
193
     *
194
     * @param Dependency $value
195
     *
196
     * @return FragmentCache
197
     */
198
    public function dependency(Dependency $value): FragmentCache
199
    {
200
        $this->dependency = $value;
201
202
        return $this;
203
    }
204
205
    /**
206
     * {@see $duration}
207
     *
208
     * @param int $value
209
     *
210
     * @return FragmentCache
211
     */
212
    public function duration(int $value): FragmentCache
213
    {
214
        $this->duration = $value;
215
216
        return $this;
217
    }
218
219
    /**
220
     * @see $id
221
     *
222
     * @param string $value
223
     *
224
     * @return FragmentCache
225
     */
226 7
    public function id(string $value): FragmentCache
227
    {
228 7
        $this->id = $value;
229
230 7
        return $this;
231
    }
232
233
    /**
234
     * {@see $variations}
235
     *
236
     * @param string[]|string $value
237
     *
238
     * @return FragmentCache
239
     */
240 1
    public function variations($value): FragmentCache
241
    {
242 1
        $this->variations = $value;
243
244 1
        return $this;
245
    }
246
247
    /**
248
     * @inheritDoc
249
     */
250 3
    protected function getView(): WebView
251
    {
252 3
        return $this->webView;
253
    }
254
}
255