Passed
Pull Request — master (#10)
by Wilmer
01:31
created

FragmentCache   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Test Coverage

Coverage 84.09%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 40
c 2
b 1
f 0
dl 0
loc 149
ccs 37
cts 44
cp 0.8409
rs 10
wmc 16

10 Methods

Rating   Name   Duplication   Size   Complexity  
A id() 0 5 1
A calculateKey() 0 3 1
A dependency() 0 5 1
A variations() 0 5 1
A __construct() 0 4 1
A getCachedContent() 0 15 2
A run() 0 19 4
A duration() 0 5 1
A getView() 0 3 1
A start() 0 6 3
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\WebView;
12
use Yiisoft\Widget\Widget;
13
14
use function array_merge;
15
use function ob_get_clean;
16
use function ob_implicit_flush;
17
use function ob_start;
18
19
final class FragmentCache extends Widget implements DynamicContentAwareInterface
20
{
21
    use DynamicContentAwareTrait;
22
23
    private string $id;
24
    private CacheInterface $cache;
25
    private int $duration = 60;
26
    private ?Dependency $dependency = null;
27
    private $variations;
28
    private ?string $content = null;
29
30
    private WebView $webView;
31
32 5
    public function __construct(CacheInterface $cache, WebView $webview)
33
    {
34 5
        $this->cache = $cache;
35 5
        $this->webView = $webview;
36 5
    }
37
38
    /**
39
     * Initializes the FragmentCache object.
40
     */
41 5
    public function start(): void
42
    {
43 5
        if ($this->getCachedContent() === null) {
44 5
            $this->webView->pushDynamicContent($this);
45 5
            ob_start();
46 5
            PHP_VERSION_ID >= 80000 ? ob_implicit_flush(false) : ob_implicit_flush(0);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $flag of ob_implicit_flush(). ( Ignorable by Annotation )

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

46
            PHP_VERSION_ID >= 80000 ? ob_implicit_flush(/** @scrutinizer ignore-type */ false) : ob_implicit_flush(0);
Loading history...
47
        }
48 5
    }
49
50
    /**
51
     * Marks the end of content to be cached.
52
     *
53
     * Content displayed before this method call and after {@see init()} will be captured and saved in cache.
54
     *
55
     * This method does nothing if valid content is already found in cache.
56
     *
57
     * @return string the result of widget execution to be outputted.
58
     */
59 5
    public function run(): string
60
    {
61 5
        if ($this->getCachedContent() !== null) {
62 4
            return $this->getCachedContent();
63
        }
64
65 5
        $this->webView->popDynamicContent();
66
67 5
        $content = ob_get_clean();
68
69 5
        if ($content === false || $content === '') {
70
            return '';
71
        }
72
73 5
        $data = [$content, $this->getDynamicPlaceholders()];
74
75 5
        $this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency);
76
77 5
        return $this->updateDynamicContent($content, $this->getDynamicPlaceholders());
78
    }
79
80
    /**
81
     * Returns the cached content if available.
82
     *
83
     * @return string|null the cached content. False is returned if valid content is not found in the cache.
84
     */
85 5
    public function getCachedContent(): ?string
86
    {
87 5
        $key = $this->calculateKey();
88
89 5
        if (!$this->cache->has($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::has(). ( Ignorable by Annotation )

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

89
        if (!$this->cache->has(/** @scrutinizer ignore-type */ $key)) {
Loading history...
90 5
            return null;
91
        }
92
93 4
        $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

93
        $data = $this->cache->get(/** @scrutinizer ignore-type */ $key);
Loading history...
94
95 4
        [$this->content, $placeholders] = $data;
96
97 4
        $this->content = $this->updateDynamicContent($this->content, $placeholders, true);
0 ignored issues
show
Bug introduced by
It seems like $this->content can also be of type null; however, parameter $content of Yiisoft\Yii\Widgets\Frag...:updateDynamicContent() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

97
        $this->content = $this->updateDynamicContent(/** @scrutinizer ignore-type */ $this->content, $placeholders, true);
Loading history...
98
99 4
        return $this->content;
100
    }
101
102
    /**
103
     * Generates a unique key used for storing the content in cache.
104
     *
105
     * The key generated depends on both {@see id} and {@see variations}.
106
     *
107
     * @return mixed a valid cache key
108
     */
109 5
    public function calculateKey()
110
    {
111 5
        return array_merge([__CLASS__, $this->id], (array) $this->variations);
112
    }
113
114
    /**
115
     * @param Dependency|null $value the dependency that the cached content depends on.
116
     *
117
     * This can be either a {@see Dependency} object or a configuration array for creating the dependency object.
118
     *
119
     * Would make the output cache depends on the last modified time of all posts. If any post has its modification time
120
     * changed, the cached content would be invalidated.
121
     *
122
     * @return $this
123
     */
124
    public function dependency(?Dependency $value): self
125
    {
126
        $this->dependency = $value;
127
128
        return $this;
129
    }
130
131
    /**
132
     * @param int $value number of seconds that the data can remain valid in cache.
133
     *
134
     * @return $this
135
     */
136
    public function duration(int $value): self
137
    {
138
        $this->duration = $value;
139
140
        return $this;
141
    }
142
143 5
    public function id(string $value): self
144
    {
145 5
        $this->id = $value;
146
147 5
        return $this;
148
    }
149
150
    /**
151
     * @param array|string $value list of factors that would cause the variation of the content being cached.
152
     *
153
     * Each factor is a string representing a variation (e.g. the language, a GET parameter). The following variation
154
     * setting will cause the content to be cached in different versions according to the current application language:
155
     *
156
     * @return $this
157
     */
158 1
    public function variations($value): self
159
    {
160 1
        $this->variations = $value;
161
162 1
        return $this;
163
    }
164
165 3
    protected function getView(): WebView
166
    {
167 3
        return $this->webView;
168
    }
169
}
170