Completed
Push — master ( 146147...1776d4 )
by Neomerx
01:58
created

ApplicationCommand::composeContent()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 36
ccs 12
cts 12
cp 1
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 21
nc 1
nop 4
crap 1
1
<?php namespace Limoncello\Application\Commands;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use Limoncello\Application\Exceptions\ConfigurationException;
20
use Limoncello\Contracts\Application\ApplicationConfigurationInterface;
21
use Limoncello\Contracts\Application\CacheSettingsProviderInterface;
22
use Limoncello\Contracts\Commands\CommandInterface;
23
use Limoncello\Contracts\Commands\IoInterface;
24
use Limoncello\Contracts\FileSystem\FileSystemInterface;
25
use Psr\Container\ContainerInterface;
26
27
/**
28
 * @package Limoncello\Application
29
 */
30
class ApplicationCommand implements CommandInterface
31
{
32
    /** Argument name */
33
    const ARG_ACTION = 'action';
34
35
    /** Command action */
36
    const ACTION_CLEAR_CACHE = 'clear-cache';
37
38
    /** Command action */
39
    const ACTION_CREATE_CACHE = 'cache';
40
41
    /**
42
     * @inheritdoc
43
     */
44 1
    public static function getName(): string
45
    {
46 1
        return 'l:app';
47
    }
48
49
    /**
50
     * @inheritdoc
51
     */
52 1
    public static function getDescription(): string
53
    {
54 1
        return 'Creates and cleans application cache.';
55
    }
56
57
    /**
58
     * @inheritdoc
59
     */
60 1
    public static function getHelp(): string
61
    {
62 1
        return 'This command creates and cleans caches for routes, settings and etc.';
63
    }
64
65
    /**
66
     * @inheritdoc
67
     */
68 1
    public static function getArguments(): array
69
    {
70 1
        $cache = static::ACTION_CREATE_CACHE;
71 1
        $clear = static::ACTION_CLEAR_CACHE;
72
73
        return [
74
            [
75 1
                static::ARGUMENT_NAME        => static::ARG_ACTION,
76 1
                static::ARGUMENT_DESCRIPTION => "Action such as `$cache` or `$clear`.",
77 1
                static::ARGUMENT_MODE        => static::ARGUMENT_MODE__REQUIRED,
78
            ],
79
        ];
80
    }
81
82
    /**
83
     * @inheritdoc
84
     */
85 1
    public static function getOptions(): array
86
    {
87 1
        return [];
88
    }
89
90
    /**
91
     * @inheritdoc
92
     */
93 1
    public static function execute(ContainerInterface $container, IoInterface $inOut): void
94
    {
95 1
        (new static())->run($container, $inOut);
96
    }
97
98
    /**
99
     * @param ContainerInterface $container
100
     * @param IoInterface        $inOut
101
     *
102
     * @return void
103
     */
104 6
    protected function run(ContainerInterface $container, IoInterface $inOut): void
105
    {
106 6
        $action = $inOut->getArgument(static::ARG_ACTION);
107
        switch ($action) {
108 6
            case static::ACTION_CREATE_CACHE:
109 2
                $this->executeCache($container, $inOut);
110 1
                break;
111 4
            case static::ACTION_CLEAR_CACHE:
112 3
                $this->executeClear($container, $inOut);
113 2
                break;
114
            default:
115 1
                $inOut->writeError("Unsupported action `$action`." . PHP_EOL);
116 1
                break;
117
        }
118
    }
119
120
    /**
121
     * @param ContainerInterface $container
122
     * @param IoInterface        $inOut
123
     *
124
     * @return void
125
     */
126 3
    protected function executeClear(ContainerInterface $container, IoInterface $inOut): void
127
    {
128 3
        assert($inOut);
129
130 3
        $appConfig     = $this->getApplicationConfiguration($container);
131 3
        $cacheDir      = $appConfig[ApplicationConfigurationInterface::KEY_CACHE_FOLDER];
132 3
        $cacheCallable = $appConfig[ApplicationConfigurationInterface::KEY_CACHE_CALLABLE];
133 3
        list (, $class) = $this->parseCacheCallable($cacheCallable);
134
135 3
        if ($class === null) {
136
            // parsing of cache callable failed (most likely error in settings)
137 1
            throw new ConfigurationException();
138
        }
139
140 2
        $path = $cacheDir . DIRECTORY_SEPARATOR . $class . '.php';
141
142 2
        $fileSystem = $this->getFileSystem($container);
143 2
        if ($fileSystem->exists($path) === true) {
144 1
            $fileSystem->delete($path);
145 1
            $inOut->writeInfo("Cache file deleted `$path`." . PHP_EOL, IoInterface::VERBOSITY_VERBOSE);
0 ignored issues
show
Unused Code introduced by
The call to IoInterface::writeInfo() has too many arguments starting with \Limoncello\Contracts\Co...face::VERBOSITY_VERBOSE.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
146
147 1
            return;
148
        }
149
150 1
        $inOut->writeInfo('Cache already clean.' . PHP_EOL);
151
    }
152
153
    /**
154
     * @param ContainerInterface $container
155
     * @param IoInterface        $inOut
156
     *
157
     * @return void
158
     */
159 2
    protected function executeCache(ContainerInterface $container, IoInterface $inOut): void
160
    {
161 2
        assert($inOut);
162
163 2
        $appConfig     = $this->getApplicationConfiguration($container);
164 2
        $cacheDir      = $appConfig[ApplicationConfigurationInterface::KEY_CACHE_FOLDER];
165 2
        $cacheCallable = $appConfig[ApplicationConfigurationInterface::KEY_CACHE_CALLABLE];
166 2
        list ($namespace, $class, $method) = $this->parseCacheCallable($cacheCallable);
167 2
        if ($class === null || $namespace === null || $method === null) {
168
            // parsing of cache callable failed (most likely error in settings)
169 1
            throw new ConfigurationException();
170
        }
171
172
        /** @var CacheSettingsProviderInterface $settingsProvider */
173 1
        $settingsProvider = $container->get(CacheSettingsProviderInterface::class);
174 1
        $settingsData     = $settingsProvider->serialize();
175 1
        $content          = $this->composeContent($settingsData, $namespace, $class, $method);
176
177 1
        $path = $cacheDir . DIRECTORY_SEPARATOR . $class . '.php';
178 1
        $this->getFileSystem($container)->write($path, $content);
179
180 1
        $inOut->writeInfo('Cache created.' . PHP_EOL);
181 1
        $inOut->writeInfo("Cache written to `$path`." . PHP_EOL, IoInterface::VERBOSITY_VERBOSE);
0 ignored issues
show
Unused Code introduced by
The call to IoInterface::writeInfo() has too many arguments starting with \Limoncello\Contracts\Co...face::VERBOSITY_VERBOSE.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
182
    }
183
184
    /**
185
     * @param mixed $mightBeCallable
186
     *
187
     * @return array
188
     *
189
     * @SuppressWarnings(PHPMD.ElseExpression)
190
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
191
     */
192 8
    protected function parseCacheCallable($mightBeCallable): array
193
    {
194 8
        if (is_string($mightBeCallable) === true &&
195 8
            count($nsClassMethod = explode('::', $mightBeCallable, 2)) === 2 &&
196 8
            count($nsClass = explode('\\', $nsClassMethod[0])) > 1
197
        ) {
198 3
            $canBeClass     = array_pop($nsClass);
199 3
            $canBeNamespace = array_filter($nsClass);
200 3
            $canBeMethod    = $nsClassMethod[1];
201 5
        } elseif (is_array($mightBeCallable) === true &&
202 5
            count($mightBeCallable) === 2 &&
203 5
            count($nsClass = explode('\\', $mightBeCallable[0])) > 1
204
        ) {
205 2
            $canBeClass     = array_pop($nsClass);
206 2
            $canBeNamespace = array_filter($nsClass);
207 2
            $canBeMethod    = $mightBeCallable[1];
208
        } else {
209 3
            return [null, null, null];
210
        }
211
212 5
        foreach (array_merge($canBeNamespace, [$canBeClass, $canBeMethod]) as $value) {
213
            // is string might have a-z, A-Z, _, numbers but has at least one a-z or A-Z.
214 5
            if (is_string($value) === false ||
215 5
                preg_match('/^\\w+$/i', $value) !== 1 ||
216 5
                preg_match('/^[a-z]+$/i', $value) !== 1
217
            ) {
218 5
                return [null, null, null];
219
            }
220
        }
221
222 4
        $namespace = implode('\\', $canBeNamespace);
223 4
        $class     = $canBeClass;
224 4
        $method    = $canBeMethod;
225
226 4
        return [$namespace, $class, $method];
227
    }
228
229
    /**
230
     * @param mixed  $value
231
     * @param string $className
232
     * @param string $methodName
233
     * @param string $namespace
234
     *
235
     * @return string
236
     */
237 1
    protected function composeContent(
238
        $value,
239
        string $namespace,
240
        string $className,
241
        string $methodName
242
    ): string {
243 1
        $now  = date(DATE_RFC2822);
244 1
        $data = var_export($value, true);
245
246 1
        assert(
247 1
            $data !== null,
248
            'It seems the data are not exportable. It is likely to be caused by class instances ' .
249
            'that do not implement ` __set_state` magic method required by `var_export`. ' .
250 1
            'See http://php.net/manual/en/language.oop5.magic.php#object.set-state for more details.'
251
        );
252
253
        $content = <<<EOT
254 1
<?php namespace $namespace;
255
256
// THIS FILE IS AUTO GENERATED. DO NOT EDIT IT MANUALLY.
257 1
// Generated at: $now
258
259 1
class $className
260
{
261 1
    const DATA = $data;
262
263 1
    public static function $methodName()
264
    {
265
        return static::DATA;
266
    }
267
}
268
269
EOT;
270
271 1
        return $content;
272
    }
273
274
    /**
275
     * @param ContainerInterface $container
276
     *
277
     * @return array
278
     */
279 5
    protected function getApplicationConfiguration(ContainerInterface $container): array
280
    {
281
        /** @var CacheSettingsProviderInterface $settingsProvider */
282 5
        $settingsProvider = $container->get(CacheSettingsProviderInterface::class);
283 5
        $appConfig        = $settingsProvider->getApplicationConfiguration();
284
285 5
        return $appConfig;
286
    }
287
288
    /**
289
     * @param ContainerInterface $container
290
     *
291
     * @return FileSystemInterface
292
     */
293 3
    protected function getFileSystem(ContainerInterface $container): FileSystemInterface
294
    {
295 3
        return $container->get(FileSystemInterface::class);
296
    }
297
}
298