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\console\controllers; |
||||
9 | |||||
10 | use Yii; |
||||
11 | use yii\caching\ApcCache; |
||||
12 | use yii\caching\CacheInterface; |
||||
13 | use yii\console\Controller; |
||||
14 | use yii\console\Exception; |
||||
15 | use yii\console\ExitCode; |
||||
16 | use yii\helpers\Console; |
||||
17 | |||||
18 | /** |
||||
19 | * Allows you to flush cache. |
||||
20 | * |
||||
21 | * see list of available components to flush: |
||||
22 | * |
||||
23 | * yii cache |
||||
24 | * |
||||
25 | * flush particular components specified by their names: |
||||
26 | * |
||||
27 | * yii cache/flush first second third |
||||
28 | * |
||||
29 | * flush all cache components that can be found in the system |
||||
30 | * |
||||
31 | * yii cache/flush-all |
||||
32 | * |
||||
33 | * Note that the command uses cache components defined in your console application configuration file. If components |
||||
34 | * configured are different from web application, web application cache won't be cleared. In order to fix it please |
||||
35 | * duplicate web application cache components in console config. You can use any component names. |
||||
36 | * |
||||
37 | * APC is not shared between PHP processes so flushing cache from command line has no effect on web. |
||||
38 | * Flushing web cache could be either done by: |
||||
39 | * |
||||
40 | * - Putting a php file under web root and calling it via HTTP |
||||
41 | * - Using [Cachetool](http://gordalina.github.io/cachetool/) |
||||
42 | * |
||||
43 | * @author Alexander Makarov <[email protected]> |
||||
44 | * @author Mark Jebri <[email protected]> |
||||
45 | * @since 2.0 |
||||
46 | */ |
||||
47 | class CacheController extends Controller |
||||
48 | { |
||||
49 | /** |
||||
50 | * Lists the caches that can be flushed. |
||||
51 | */ |
||||
52 | public function actionIndex() |
||||
53 | { |
||||
54 | $caches = $this->findCaches(); |
||||
55 | |||||
56 | if (!empty($caches)) { |
||||
57 | $this->notifyCachesCanBeFlushed($caches); |
||||
58 | } else { |
||||
59 | $this->notifyNoCachesFound(); |
||||
60 | } |
||||
61 | } |
||||
62 | |||||
63 | /** |
||||
64 | * Flushes given cache components. |
||||
65 | * |
||||
66 | * For example, |
||||
67 | * |
||||
68 | * ``` |
||||
69 | * # flushes caches specified by their id: "first", "second", "third" |
||||
70 | * yii cache/flush first second third |
||||
71 | * ``` |
||||
72 | */ |
||||
73 | 4 | public function actionFlush() |
|||
74 | { |
||||
75 | 4 | $cachesInput = func_get_args(); |
|||
76 | |||||
77 | 4 | if (empty($cachesInput)) { |
|||
78 | 1 | throw new Exception('You should specify cache components names'); |
|||
79 | } |
||||
80 | |||||
81 | 3 | $caches = $this->findCaches($cachesInput); |
|||
82 | 3 | $cachesInfo = []; |
|||
83 | |||||
84 | 3 | $foundCaches = array_keys($caches); |
|||
85 | 3 | $notFoundCaches = array_diff($cachesInput, array_keys($caches)); |
|||
86 | |||||
87 | 3 | if ($notFoundCaches !== []) { |
|||
88 | 1 | $this->notifyNotFoundCaches($notFoundCaches); |
|||
89 | } |
||||
90 | |||||
91 | 3 | if ($foundCaches === []) { |
|||
92 | 1 | $this->notifyNoCachesFound(); |
|||
93 | 1 | return ExitCode::OK; |
|||
94 | } |
||||
95 | |||||
96 | 2 | if (!$this->confirmFlush($foundCaches)) { |
|||
97 | return ExitCode::OK; |
||||
98 | } |
||||
99 | |||||
100 | 2 | foreach ($caches as $name => $class) { |
|||
101 | 2 | $cachesInfo[] = [ |
|||
102 | 2 | 'name' => $name, |
|||
103 | 2 | 'class' => $class, |
|||
104 | 2 | 'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false, |
|||
105 | ]; |
||||
106 | } |
||||
107 | |||||
108 | 2 | $this->notifyFlushed($cachesInfo); |
|||
109 | 2 | } |
|||
110 | |||||
111 | /** |
||||
112 | * Flushes all caches registered in the system. |
||||
113 | */ |
||||
114 | 1 | public function actionFlushAll() |
|||
115 | { |
||||
116 | 1 | $caches = $this->findCaches(); |
|||
117 | 1 | $cachesInfo = []; |
|||
118 | |||||
119 | 1 | if (empty($caches)) { |
|||
120 | $this->notifyNoCachesFound(); |
||||
121 | return ExitCode::OK; |
||||
122 | } |
||||
123 | |||||
124 | 1 | foreach ($caches as $name => $class) { |
|||
125 | 1 | $cachesInfo[] = [ |
|||
126 | 1 | 'name' => $name, |
|||
127 | 1 | 'class' => $class, |
|||
128 | 1 | 'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false, |
|||
129 | ]; |
||||
130 | } |
||||
131 | |||||
132 | 1 | $this->notifyFlushed($cachesInfo); |
|||
133 | 1 | } |
|||
134 | |||||
135 | /** |
||||
136 | * Clears DB schema cache for a given connection component. |
||||
137 | * |
||||
138 | * ``` |
||||
139 | * # clears cache schema specified by component id: "db" |
||||
140 | * yii cache/flush-schema db |
||||
141 | * ``` |
||||
142 | * |
||||
143 | * @param string $db id connection component |
||||
144 | * @return int exit code |
||||
145 | * @throws Exception |
||||
146 | * @throws \yii\base\InvalidConfigException |
||||
147 | * |
||||
148 | * @since 2.0.1 |
||||
149 | */ |
||||
150 | 1 | public function actionFlushSchema($db = 'db') |
|||
151 | { |
||||
152 | 1 | $connection = Yii::$app->get($db, false); |
|||
153 | 1 | if ($connection === null) { |
|||
154 | $this->stdout("Unknown component \"$db\".\n", Console::FG_RED); |
||||
155 | return ExitCode::UNSPECIFIED_ERROR; |
||||
156 | } |
||||
157 | |||||
158 | 1 | if (!$connection instanceof \yii\db\Connection) { |
|||
159 | $this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED); |
||||
160 | return ExitCode::UNSPECIFIED_ERROR; |
||||
161 | 1 | } elseif (!$this->confirm("Flush cache schema for \"$db\" connection?")) { |
|||
162 | return ExitCode::OK; |
||||
163 | } |
||||
164 | |||||
165 | try { |
||||
166 | 1 | $schema = $connection->getSchema(); |
|||
167 | 1 | $schema->refresh(); |
|||
168 | 1 | $this->stdout("Schema cache for component \"$db\", was flushed.\n\n", Console::FG_GREEN); |
|||
169 | } catch (\Exception $e) { |
||||
170 | $this->stdout($e->getMessage() . "\n\n", Console::FG_RED); |
||||
171 | } |
||||
172 | 1 | } |
|||
173 | |||||
174 | /** |
||||
175 | * Notifies user that given caches are found and can be flushed. |
||||
176 | * @param array $caches array of cache component classes |
||||
177 | */ |
||||
178 | private function notifyCachesCanBeFlushed($caches) |
||||
179 | { |
||||
180 | $this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW); |
||||
181 | |||||
182 | foreach ($caches as $name => $class) { |
||||
183 | if ($this->canBeFlushed($class)) { |
||||
184 | $this->stdout("\t* $name ($class)\n", Console::FG_GREEN); |
||||
185 | } else { |
||||
186 | $this->stdout("\t* $name ($class) - can not be flushed via console\n", Console::FG_YELLOW); |
||||
187 | } |
||||
188 | } |
||||
189 | |||||
190 | $this->stdout("\n"); |
||||
191 | } |
||||
192 | |||||
193 | /** |
||||
194 | * Notifies user that there was not found any cache in the system. |
||||
195 | */ |
||||
196 | 1 | private function notifyNoCachesFound() |
|||
197 | { |
||||
198 | 1 | $this->stdout("No cache components were found in the system.\n", Console::FG_RED); |
|||
199 | 1 | } |
|||
200 | |||||
201 | /** |
||||
202 | * Notifies user that given cache components were not found in the system. |
||||
203 | * @param array $cachesNames |
||||
204 | */ |
||||
205 | 1 | private function notifyNotFoundCaches($cachesNames) |
|||
206 | { |
||||
207 | 1 | $this->stdout("The following cache components were NOT found:\n\n", Console::FG_RED); |
|||
208 | |||||
209 | 1 | foreach ($cachesNames as $name) { |
|||
210 | 1 | $this->stdout("\t* $name \n", Console::FG_GREEN); |
|||
211 | } |
||||
212 | |||||
213 | 1 | $this->stdout("\n"); |
|||
214 | 1 | } |
|||
215 | |||||
216 | /** |
||||
217 | * @param array $caches |
||||
218 | */ |
||||
219 | 3 | private function notifyFlushed($caches) |
|||
220 | { |
||||
221 | 3 | $this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW); |
|||
222 | |||||
223 | 3 | foreach ($caches as $cache) { |
|||
224 | 3 | $this->stdout("\t* " . $cache['name'] . ' (' . $cache['class'] . ')', Console::FG_GREEN); |
|||
225 | |||||
226 | 3 | if (!$cache['is_flushed']) { |
|||
227 | $this->stdout(" - not flushed\n", Console::FG_RED); |
||||
228 | } else { |
||||
229 | 3 | $this->stdout("\n"); |
|||
230 | } |
||||
231 | } |
||||
232 | |||||
233 | 3 | $this->stdout("\n"); |
|||
234 | 3 | } |
|||
235 | |||||
236 | /** |
||||
237 | * Prompts user with confirmation if caches should be flushed. |
||||
238 | * @param array $cachesNames |
||||
239 | * @return bool |
||||
240 | */ |
||||
241 | 2 | private function confirmFlush($cachesNames) |
|||
242 | { |
||||
243 | 2 | $this->stdout("The following cache components will be flushed:\n\n", Console::FG_YELLOW); |
|||
244 | |||||
245 | 2 | foreach ($cachesNames as $name) { |
|||
246 | 2 | $this->stdout("\t* $name \n", Console::FG_GREEN); |
|||
247 | } |
||||
248 | |||||
249 | 2 | return $this->confirm("\nFlush above cache components?"); |
|||
250 | } |
||||
251 | |||||
252 | /** |
||||
253 | * Returns array of caches in the system, keys are cache components names, values are class names. |
||||
254 | * @param array $cachesNames caches to be found |
||||
255 | * @return array |
||||
256 | */ |
||||
257 | 4 | private function findCaches(array $cachesNames = []) |
|||
258 | { |
||||
259 | 4 | $caches = []; |
|||
260 | 4 | $components = Yii::$app->getComponents(); |
|||
261 | 4 | $findAll = ($cachesNames === []); |
|||
262 | |||||
263 | 4 | foreach ($components as $name => $component) { |
|||
264 | 4 | if (!$findAll && !in_array($name, $cachesNames, true)) { |
|||
265 | 3 | continue; |
|||
266 | } |
||||
267 | |||||
268 | 3 | if ($component instanceof CacheInterface) { |
|||
269 | $caches[$name] = get_class($component); |
||||
270 | 3 | } elseif (is_array($component) && isset($component['class']) && $this->isCacheClass($component['class'])) { |
|||
271 | $caches[$name] = $component['class']; |
||||
272 | 3 | } elseif (is_string($component) && $this->isCacheClass($component)) { |
|||
273 | 3 | $caches[$name] = $component; |
|||
274 | 2 | } elseif ($component instanceof \Closure) { |
|||
275 | 2 | $cache = Yii::$app->get($name); |
|||
276 | 2 | if ($this->isCacheClass($cache)) { |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
277 | 2 | $cacheClass = get_class($cache); |
|||
0 ignored issues
–
show
It seems like
$cache can also be of type mixed and 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
![]() |
|||||
278 | 3 | $caches[$name] = $cacheClass; |
|||
279 | } |
||||
280 | } |
||||
281 | } |
||||
282 | |||||
283 | 4 | return $caches; |
|||
284 | } |
||||
285 | |||||
286 | /** |
||||
287 | * Checks if given class is a Cache class. |
||||
288 | * @param string $className class name. |
||||
289 | * @return bool |
||||
290 | */ |
||||
291 | 3 | private function isCacheClass($className) |
|||
292 | { |
||||
293 | 3 | return is_subclass_of($className, 'yii\caching\CacheInterface') || $className === 'yii\caching\CacheInterface'; |
|||
294 | } |
||||
295 | |||||
296 | /** |
||||
297 | * Checks if cache of a certain class can be flushed. |
||||
298 | * @param string $className class name. |
||||
299 | * @return bool |
||||
300 | */ |
||||
301 | 3 | private function canBeFlushed($className) |
|||
302 | { |
||||
303 | 3 | return !is_a($className, ApcCache::className(), true) || PHP_SAPI !== 'cli'; |
|||
304 | } |
||||
305 | } |
||||
306 |