Completed
Push — prepare-travis-for-js ( a7ee60...8c0a43 )
by Carsten
17:00 queued 09:50
created

CacheController::actionIndex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 7
cp 0
cc 2
eloc 6
nc 2
nop 0
crap 6
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\console\Controller;
12
use yii\caching\Cache;
13
use yii\helpers\Console;
14
use yii\console\Exception;
15
16
/**
17
 * Allows you to flush cache.
18
 *
19
 * see list of available components to flush:
20
 *
21
 *     yii cache
22
 *
23
 * flush particular components specified by their names:
24
 *
25
 *     yii cache/flush first second third
26
 *
27
 * flush all cache components that can be found in the system
28
 *
29
 *     yii cache/flush-all
30
 *
31
 * Note that the command uses cache components defined in your console application configuration file. If components
32
 * configured are different from web application, web application cache won't be cleared. In order to fix it please
33
 * duplicate web application cache components in console config. You can use any component names.
34
 *
35
 * Both APC and OpCache aren't shared between PHP processes so flushing cache from command line has no effect on web.
36
 * Flushing web cache could be either done by:
37
 *
38
 * - Putting a php file under web root and calling it via HTTP
39
 * - Using [Cachetool](http://gordalina.github.io/cachetool/)
40
 *
41
 * @author Alexander Makarov <[email protected]>
42
 * @author Mark Jebri <[email protected]>
43
 * @since 2.0
44
 */
45
class CacheController extends Controller
46
{
47
    /**
48
     * Lists the caches that can be flushed.
49
     */
50
    public function actionIndex()
51
    {
52
        $caches = $this->findCaches();
53
54
        if (!empty($caches)) {
55
            $this->notifyCachesCanBeFlushed($caches);
56
        } else {
57
            $this->notifyNoCachesFound();
58
        }
59
    }
60
61
    /**
62
     * Flushes given cache components.
63
     * For example,
64
     *
65
     * ```
66
     * # flushes caches specified by their id: "first", "second", "third"
67
     * yii cache/flush first second third
68
     * ```
69
     *
70
     */
71 4
    public function actionFlush()
72
    {
73 4
        $cachesInput = func_get_args();
74
75 4
        if (empty($cachesInput)) {
76 1
            throw new Exception('You should specify cache components names');
77
        }
78
79 3
        $caches = $this->findCaches($cachesInput);
80 3
        $cachesInfo = [];
81
82 3
        $foundCaches = array_keys($caches);
83 3
        $notFoundCaches = array_diff($cachesInput, array_keys($caches));
84
85 3
        if ($notFoundCaches) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $notFoundCaches of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
86 1
            $this->notifyNotFoundCaches($notFoundCaches);
87 1
        }
88
89 3
        if (!$foundCaches) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $foundCaches of type array<integer|string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
90 1
            $this->notifyNoCachesFound();
91 1
            return static::EXIT_CODE_NORMAL;
92
        }
93
94 2
        if (!$this->confirmFlush($foundCaches)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->confirmFlush($foundCaches) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
95
            return static::EXIT_CODE_NORMAL;
96
        }
97
98 2
        foreach ($caches as $name => $class) {
99 2
            $cachesInfo[] = [
100 2
                'name' => $name,
101 2
                'class' => $class,
102 2
                'is_flushed' => Yii::$app->get($name)->flush(),
103
            ];
104 2
        }
105
106 2
        $this->notifyFlushed($cachesInfo);
107 2
    }
108
109
    /**
110
     * Flushes all caches registered in the system.
111
     */
112 1
    public function actionFlushAll()
113
    {
114 1
        $caches = $this->findCaches();
115 1
        $cachesInfo = [];
116
117 1
        if (empty($caches)) {
118
            $this->notifyNoCachesFound();
119
            return static::EXIT_CODE_NORMAL;
120
        }
121
122 1
        foreach ($caches as $name => $class) {
123 1
            $cachesInfo[] = [
124 1
                'name' => $name,
125 1
                'class' => $class,
126 1
                'is_flushed' => Yii::$app->get($name)->flush(),
127
            ];
128 1
        }
129
130 1
        $this->notifyFlushed($cachesInfo);
131 1
    }
132
133
    /**
134
     * Clears DB schema cache for a given connection component.
135
     *
136
     * ```
137
     * # clears cache schema specified by component id: "db"
138
     * yii cache/flush-schema db
139
     * ```
140
     *
141
     * @param string $db id connection component
142
     * @return int exit code
143
     * @throws Exception
144
     * @throws \yii\base\InvalidConfigException
145
     *
146
     * @since 2.0.1
147
     */
148 1
    public function actionFlushSchema($db = 'db')
149
    {
150 1
        $connection = Yii::$app->get($db, false);
151 1
        if ($connection === null) {
152
            $this->stdout("Unknown component \"$db\".\n", Console::FG_RED);
153
            return self::EXIT_CODE_ERROR;
154
        }
155
156 1
        if (!$connection instanceof \yii\db\Connection) {
157
            $this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED);
158
            return self::EXIT_CODE_ERROR;
159 1
        } elseif (!$this->confirm("Flush cache schema for \"$db\" connection?")) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->confirm("Flush ca...\"{$db}\" connection?") of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
160
            return static::EXIT_CODE_NORMAL;
161
        }
162
163
        try {
164 1
            $schema = $connection->getSchema();
165 1
            $schema->refresh();
166 1
            $this->stdout("Schema cache for component \"$db\", was flushed.\n\n", Console::FG_GREEN);
167 1
        } catch (\Exception $e) {
168
            $this->stdout($e->getMessage() . "\n\n", Console::FG_RED);
169
        }
170 1
    }
171
172
    /**
173
     * Notifies user that given caches are found and can be flushed.
174
     * @param array $caches array of cache component classes
175
     */
176
    private function notifyCachesCanBeFlushed($caches)
177
    {
178
        $this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW);
179
180
        foreach ($caches as $name => $class) {
181
            $this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
182
        }
183
184
        $this->stdout("\n");
185
    }
186
187
    /**
188
     * Notifies user that there was not found any cache in the system.
189
     */
190 1
    private function notifyNoCachesFound()
191
    {
192 1
        $this->stdout("No cache components were found in the system.\n", Console::FG_RED);
193 1
    }
194
195
    /**
196
     * Notifies user that given cache components were not found in the system.
197
     * @param array $cachesNames
198
     */
199 1
    private function notifyNotFoundCaches($cachesNames)
200
    {
201 1
        $this->stdout("The following cache components were NOT found:\n\n", Console::FG_RED);
202
203 1
        foreach ($cachesNames as $name) {
204 1
            $this->stdout("\t* $name \n", Console::FG_GREEN);
205 1
        }
206
207 1
        $this->stdout("\n");
208 1
    }
209
210
    /**
211
     *
212
     * @param array $caches
213
     */
214 3
    private function notifyFlushed($caches)
215
    {
216 3
        $this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW);
217
218 3
        foreach ($caches as $cache) {
219 3
            $this->stdout("\t* " . $cache['name'] .' (' . $cache['class'] . ')', Console::FG_GREEN);
220
221 3
            if (!$cache['is_flushed']) {
222
                $this->stdout(" - not flushed\n", Console::FG_RED);
223
            } else {
224 3
                $this->stdout("\n");
225
            }
226 3
        }
227
228 3
        $this->stdout("\n");
229 3
    }
230
231
    /**
232
     * Prompts user with confirmation if caches should be flushed.
233
     * @param array $cachesNames
234
     * @return bool
235
     */
236 2
    private function confirmFlush($cachesNames)
237
    {
238 2
        $this->stdout("The following cache components will be flushed:\n\n", Console::FG_YELLOW);
239
240 2
        foreach ($cachesNames as $name) {
241 2
            $this->stdout("\t* $name \n", Console::FG_GREEN);
242 2
        }
243
244 2
        return $this->confirm("\nFlush above cache components?");
245
    }
246
247
    /**
248
     * Returns array of caches in the system, keys are cache components names, values are class names.
249
     * @param array $cachesNames caches to be found
250
     * @return array
251
     */
252 4
    private function findCaches(array $cachesNames = [])
253
    {
254 4
        $caches = [];
255 4
        $components = Yii::$app->getComponents();
256 4
        $findAll = ($cachesNames === []);
257
258 4
        foreach ($components as $name => $component) {
259 4
            if (!$findAll && !in_array($name, $cachesNames)) {
260 3
                continue;
261
            }
262
263 3
            if ($component instanceof Cache) {
264
                $caches[$name] = get_class($component);
265 3
            } elseif (is_array($component) && isset($component['class']) && $this->isCacheClass($component['class'])) {
266
                $caches[$name] = $component['class'];
267 3
            } elseif (is_string($component) && $this->isCacheClass($component)) {
268 3
                $caches[$name] = $component;
269 3
            }
270 4
        }
271
272 4
        return $caches;
273
    }
274
275
    /**
276
     * Checks if given class is a Cache class.
277
     * @param string $className class name.
278
     * @return bool
279
     */
280 3
    private function isCacheClass($className)
281
    {
282 3
        return is_subclass_of($className, Cache::className());
283
    }
284
}
285