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\behaviors; |
||||
9 | |||||
10 | use yii\base\Behavior; |
||||
11 | use yii\base\InvalidConfigException; |
||||
12 | use yii\base\Widget; |
||||
13 | use yii\base\WidgetEvent; |
||||
14 | use yii\caching\CacheInterface; |
||||
15 | use yii\caching\Dependency; |
||||
16 | use yii\di\Instance; |
||||
17 | |||||
18 | /** |
||||
19 | * Cacheable widget behavior automatically caches widget contents according to duration and dependencies specified. |
||||
20 | * |
||||
21 | * The behavior may be used without any configuration if an application has `cache` component configured. |
||||
22 | * By default the widget will be cached for one minute. |
||||
23 | * |
||||
24 | * The following example will cache the posts widget for an indefinite duration until any post is modified. |
||||
25 | * |
||||
26 | * ```php |
||||
27 | * use yii\behaviors\CacheableWidgetBehavior; |
||||
28 | * |
||||
29 | * public function behaviors() |
||||
30 | * { |
||||
31 | * return [ |
||||
32 | * [ |
||||
33 | * 'class' => CacheableWidgetBehavior::class, |
||||
34 | * 'cacheDuration' => 0, |
||||
35 | * 'cacheDependency' => [ |
||||
36 | * 'class' => 'yii\caching\DbDependency', |
||||
37 | * 'sql' => 'SELECT MAX(updated_at) FROM posts', |
||||
38 | * ], |
||||
39 | * ], |
||||
40 | * ]; |
||||
41 | * } |
||||
42 | * ``` |
||||
43 | * |
||||
44 | * @author Nikolay Oleynikov <[email protected]> |
||||
45 | * @since 2.0.14 |
||||
46 | */ |
||||
47 | class CacheableWidgetBehavior extends Behavior |
||||
48 | { |
||||
49 | /** |
||||
50 | * @var CacheInterface|string|array a cache object or a cache component ID |
||||
51 | * or a configuration array for creating a cache object. |
||||
52 | * Defaults to the `cache` application component. |
||||
53 | */ |
||||
54 | public $cache = 'cache'; |
||||
55 | /** |
||||
56 | * @var int cache duration in seconds. |
||||
57 | * Set to `0` to indicate that the cached data will never expire. |
||||
58 | * Defaults to 60 seconds or 1 minute. |
||||
59 | */ |
||||
60 | public $cacheDuration = 60; |
||||
61 | /** |
||||
62 | * @var Dependency|array|null a cache dependency or a configuration array |
||||
63 | * for creating a cache dependency or `null` meaning no cache dependency. |
||||
64 | * |
||||
65 | * For example, |
||||
66 | * |
||||
67 | * ```php |
||||
68 | * [ |
||||
69 | * 'class' => 'yii\caching\DbDependency', |
||||
70 | * 'sql' => 'SELECT MAX(updated_at) FROM posts', |
||||
71 | * ] |
||||
72 | * ``` |
||||
73 | * |
||||
74 | * would make the widget cache depend on the last modified time of all posts. |
||||
75 | * If any post has its modification time changed, the cached content would be invalidated. |
||||
76 | */ |
||||
77 | public $cacheDependency; |
||||
78 | /** |
||||
79 | * @var string[]|string an array of strings or a single string which would cause |
||||
80 | * the variation of the content being cached (e.g. an application language, a GET parameter). |
||||
81 | * |
||||
82 | * The following variation setting will cause the content to be cached in different versions |
||||
83 | * according to the current application language: |
||||
84 | * |
||||
85 | * ```php |
||||
86 | * [ |
||||
87 | * Yii::$app->language, |
||||
88 | * ] |
||||
89 | * ``` |
||||
90 | */ |
||||
91 | public $cacheKeyVariations = []; |
||||
92 | /** |
||||
93 | * @var bool whether to enable caching or not. Allows to turn the widget caching |
||||
94 | * on and off according to specific conditions. |
||||
95 | * The following configuration will disable caching when a special GET parameter is passed: |
||||
96 | * |
||||
97 | * ```php |
||||
98 | * empty(Yii::$app->request->get('disable-caching')) |
||||
99 | * ``` |
||||
100 | */ |
||||
101 | public $cacheEnabled = true; |
||||
102 | |||||
103 | |||||
104 | /** |
||||
105 | * {@inheritdoc} |
||||
106 | */ |
||||
107 | 3 | public function attach($owner) |
|||
108 | { |
||||
109 | 3 | parent::attach($owner); |
|||
110 | |||||
111 | 3 | $this->initializeEventHandlers(); |
|||
112 | 3 | } |
|||
113 | |||||
114 | /** |
||||
115 | * Begins fragment caching. Prevents owner widget from execution |
||||
116 | * if its contents can be retrieved from the cache. |
||||
117 | * |
||||
118 | * @param WidgetEvent $event `Widget::EVENT_BEFORE_RUN` event. |
||||
119 | */ |
||||
120 | 3 | public function beforeRun($event) |
|||
121 | { |
||||
122 | 3 | $cacheKey = $this->getCacheKey(); |
|||
123 | 3 | $fragmentCacheConfiguration = $this->getFragmentCacheConfiguration(); |
|||
124 | |||||
125 | 3 | if (!$this->owner->view->beginCache($cacheKey, $fragmentCacheConfiguration)) { |
|||
126 | 2 | $event->isValid = false; |
|||
127 | } |
||||
128 | 3 | } |
|||
129 | |||||
130 | /** |
||||
131 | * Outputs widget contents and ends fragment caching. |
||||
132 | * |
||||
133 | * @param WidgetEvent $event `Widget::EVENT_AFTER_RUN` event. |
||||
134 | */ |
||||
135 | 3 | public function afterRun($event) |
|||
136 | { |
||||
137 | 3 | echo $event->result; |
|||
138 | 3 | $event->result = null; |
|||
139 | |||||
140 | 3 | $this->owner->view->endCache(); |
|||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||||
141 | 3 | } |
|||
142 | |||||
143 | /** |
||||
144 | * Initializes widget event handlers. |
||||
145 | */ |
||||
146 | 3 | private function initializeEventHandlers() |
|||
147 | { |
||||
148 | 3 | $this->owner->on(Widget::EVENT_BEFORE_RUN, [$this, 'beforeRun']); |
|||
149 | 3 | $this->owner->on(Widget::EVENT_AFTER_RUN, [$this, 'afterRun']); |
|||
150 | 3 | } |
|||
151 | |||||
152 | /** |
||||
153 | * Returns the cache instance. |
||||
154 | * |
||||
155 | * @return CacheInterface cache instance. |
||||
156 | * @throws InvalidConfigException if cache instance instantiation fails. |
||||
157 | */ |
||||
158 | 3 | private function getCacheInstance() |
|||
159 | { |
||||
160 | 3 | $cacheInterface = 'yii\caching\CacheInterface'; |
|||
161 | 3 | return Instance::ensure($this->cache, $cacheInterface); |
|||
162 | } |
||||
163 | |||||
164 | /** |
||||
165 | * Returns the widget cache key. |
||||
166 | * |
||||
167 | * @return string[] an array of strings representing the cache key. |
||||
168 | */ |
||||
169 | 3 | private function getCacheKey() |
|||
170 | { |
||||
171 | // `$cacheKeyVariations` may be a `string` and needs to be cast to an `array`. |
||||
172 | 3 | $cacheKey = array_merge( |
|||
173 | 3 | (array)get_class($this->owner), |
|||
0 ignored issues
–
show
It seems like
$this->owner can also be of type null ; however, parameter $object of get_class() does only seem to accept object , 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
Loading history...
|
|||||
174 | 3 | (array)$this->cacheKeyVariations |
|||
175 | ); |
||||
176 | |||||
177 | 3 | return $cacheKey; |
|||
178 | } |
||||
179 | |||||
180 | /** |
||||
181 | * Returns a fragment cache widget configuration array. |
||||
182 | * |
||||
183 | * @return array a fragment cache widget configuration array. |
||||
184 | */ |
||||
185 | 3 | private function getFragmentCacheConfiguration() |
|||
186 | { |
||||
187 | 3 | $cache = $this->getCacheInstance(); |
|||
188 | $fragmentCacheConfiguration = [ |
||||
189 | 3 | 'cache' => $cache, |
|||
190 | 3 | 'duration' => $this->cacheDuration, |
|||
191 | 3 | 'dependency' => $this->cacheDependency, |
|||
192 | 3 | 'enabled' => $this->cacheEnabled, |
|||
193 | ]; |
||||
194 | |||||
195 | 3 | return $fragmentCacheConfiguration; |
|||
196 | } |
||||
197 | } |
||||
198 |