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 Psr\SimpleCache\CacheInterface; |
11
|
|
|
use Yii; |
12
|
|
|
use yii\caching\ApcCache; |
13
|
|
|
use yii\caching\Cache; |
14
|
|
|
use yii\console\Controller; |
15
|
|
|
use yii\console\Exception; |
16
|
|
|
use yii\console\ExitCode; |
17
|
|
|
use yii\helpers\Console; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Allows you to clear cache. |
21
|
|
|
* |
22
|
|
|
* see list of available components to clear: |
23
|
|
|
* |
24
|
|
|
* yii cache |
25
|
|
|
* |
26
|
|
|
* clear particular components specified by their names: |
27
|
|
|
* |
28
|
|
|
* yii cache/clear first second third |
29
|
|
|
* |
30
|
|
|
* clear all cache components that can be found in the system |
31
|
|
|
* |
32
|
|
|
* yii cache/clear-all |
33
|
|
|
* |
34
|
|
|
* Note that the command uses cache components defined in your console application configuration file. If components |
35
|
|
|
* configured are different from web application, web application cache won't be cleared. In order to fix it please |
36
|
|
|
* duplicate web application cache components in console config. You can use any component names. |
37
|
|
|
* |
38
|
|
|
* APC is not shared between PHP processes so clearing cache from command line has no effect on web. |
39
|
|
|
* Clearing web cache could be either done by: |
40
|
|
|
* |
41
|
|
|
* - Putting a php file under web root and calling it via HTTP |
42
|
|
|
* - Using [Cachetool](http://gordalina.github.io/cachetool/) |
43
|
|
|
* |
44
|
|
|
* @author Alexander Makarov <[email protected]> |
45
|
|
|
* @author Mark Jebri <[email protected]> |
46
|
|
|
* @since 2.0 |
47
|
|
|
*/ |
48
|
|
|
class CacheController extends Controller |
49
|
|
|
{ |
50
|
|
|
/** |
51
|
|
|
* Lists the caches that can be cleared. |
52
|
|
|
*/ |
53
|
|
|
public function actionIndex() |
54
|
|
|
{ |
55
|
|
|
$caches = $this->findCaches(); |
56
|
|
|
|
57
|
|
|
if (!empty($caches)) { |
58
|
|
|
$this->notifyCachesCanBeCleared($caches); |
59
|
|
|
} else { |
60
|
|
|
$this->notifyNoCachesFound(); |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Clears given cache components. |
66
|
|
|
* For example, |
67
|
|
|
* |
68
|
|
|
* ``` |
69
|
|
|
* # clears caches specified by their id: "first", "second", "third" |
70
|
|
|
* yii cache/clear first second third |
71
|
|
|
* ``` |
72
|
|
|
*/ |
73
|
4 |
|
public function actionClear() |
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->confirmClear($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_cleared' => $this->canBeCleared($class) ? Yii::$app->get($name)->clear() : false, |
105
|
|
|
]; |
106
|
|
|
} |
107
|
|
|
|
108
|
2 |
|
$this->notifyCleared($cachesInfo); |
109
|
2 |
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Clears all caches registered in the system. |
113
|
|
|
*/ |
114
|
1 |
|
public function actionClearAll() |
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_cleared' => $this->canBeCleared($class) ? Yii::$app->get($name)->clear() : false, |
129
|
|
|
]; |
130
|
|
|
} |
131
|
|
|
|
132
|
1 |
|
$this->notifyCleared($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/clear-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 actionClearSchema($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("Clear 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 cleared.\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 cleared. |
176
|
|
|
* @param array $caches array of cache component classes |
177
|
|
|
*/ |
178
|
|
|
private function notifyCachesCanBeCleared($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->canBeCleared($class)) { |
184
|
|
|
$this->stdout("\t* $name ($class)\n", Console::FG_GREEN); |
185
|
|
|
} else { |
186
|
|
|
$this->stdout("\t* $name ($class) - can not be cleared 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 notifyCleared($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_cleared']) { |
227
|
|
|
$this->stdout(" - not cleared\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 cleared. |
238
|
|
|
* @param array $cachesNames |
239
|
|
|
* @return bool |
240
|
|
|
*/ |
241
|
2 |
|
private function confirmClear($cachesNames) |
242
|
|
|
{ |
243
|
2 |
|
$this->stdout("The following cache components will be cleared:\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("\nClear 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
|
|
|
} |
275
|
|
|
} |
276
|
|
|
|
277
|
4 |
|
return $caches; |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* Checks if given class is a Cache class. |
282
|
|
|
* @param string $className class name. |
283
|
|
|
* @return bool |
284
|
|
|
*/ |
285
|
3 |
|
private function isCacheClass($className) |
286
|
|
|
{ |
287
|
3 |
|
return is_subclass_of($className, CacheInterface::class); |
|
|
|
|
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Checks if cache of a certain class can be cleared |
292
|
|
|
* @param string $className class name. |
293
|
|
|
* @return bool |
294
|
|
|
*/ |
295
|
3 |
|
private function canBeCleared($className) |
296
|
|
|
{ |
297
|
3 |
|
return !is_a($className, ApcCache::class, true) || php_sapi_name() !== 'cli'; |
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.