Passed
Pull Request — master (#116)
by Théo
02:27
created

Checker::check()   D

Complexity

Conditions 14
Paths 360

Size

Total Lines 74
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 74
rs 4.0377
c 0
b 0
f 0
cc 14
eloc 44
nc 360
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the humbug/Box package.
5
 *
6
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
7
 *                    Pádraic Brady <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace KevinGH\Box\RequirementChecker;
14
15
require 'vendor/symfony/requirements-checker/src/RequirementCollection.php';
16
require 'vendor/symfony/requirements-checker/src/Requirement.php';
17
18
use Symfony\Component\Console\Input\ArgvInput;
19
use Symfony\Requirements\Requirement;
20
use const PHP_EOL;
21
use const STR_PAD_RIGHT;
22
use function array_reduce;
23
use function function_exists;
24
use function getenv;
25
use function posix_isatty;
26
use function str_pad;
27
use function str_repeat;
28
use function strlen;
29
use Symfony\Requirements\RequirementCollection;
30
use function trim;
31
use function unserialize;
32
use function wordwrap;
33
34
/**
35
 * The code in this file must be PHP 5.3+ compatible as is used to know if the application can be run.
36
 *
37
 * @private
38
 */
39
final class Checker
40
{
41
    /**
42
     * @var RequirementCollection
43
     */
44
    private static $requirements = 'C:42:"Symfony\Requirements\RequirementCollection":2914:{C:13:"ArrayIterator":2886:{x:i:0;a:6:{i:0;O:32:"Symfony\Requirements\Requirement":5:{s:43:"Symfony\Requirements\Requirementfulfilled";b:1;s:45:"Symfony\Requirements\RequirementtestMessage";s:67:"The application requires the version "^7.1" or greater. Got "7.2.2"";s:42:"Symfony\Requirements\RequirementhelpText";s:55:"The application requires the version "^7.1" or greater.";s:42:"Symfony\Requirements\RequirementhelpHtml";s:0:"";s:42:"Symfony\Requirements\Requirementoptional";b:0;}i:1;O:32:"Symfony\Requirements\Requirement":5:{s:43:"Symfony\Requirements\Requirementfulfilled";b:1;s:45:"Symfony\Requirements\RequirementtestMessage";s:79:"The application requires the extension "phar". Enable it or install a polyfill.";s:42:"Symfony\Requirements\RequirementhelpText";s:46:"The application requires the extension "phar".";s:42:"Symfony\Requirements\RequirementhelpHtml";s:0:"";s:42:"Symfony\Requirements\Requirementoptional";b:0;}i:2;O:32:"Symfony\Requirements\Requirement":5:{s:43:"Symfony\Requirements\Requirementfulfilled";b:0;s:45:"Symfony\Requirements\RequirementtestMessage";s:82:"The application requires the extension "sqlite3". Enable it or install a polyfill.";s:42:"Symfony\Requirements\RequirementhelpText";s:49:"The application requires the extension "sqlite3".";s:42:"Symfony\Requirements\RequirementhelpHtml";s:0:"";s:42:"Symfony\Requirements\Requirementoptional";b:0;}i:3;O:32:"Symfony\Requirements\Requirement":5:{s:43:"Symfony\Requirements\Requirementfulfilled";b:1;s:45:"Symfony\Requirements\RequirementtestMessage";s:99:"The package "composer/ca-bundle" requires the extension "openssl". Enable it or install a polyfill.";s:42:"Symfony\Requirements\RequirementhelpText";s:66:"The package "composer/ca-bundle" requires the extension "openssl".";s:42:"Symfony\Requirements\RequirementhelpHtml";s:0:"";s:42:"Symfony\Requirements\Requirementoptional";b:0;}i:4;O:32:"Symfony\Requirements\Requirement":5:{s:43:"Symfony\Requirements\Requirementfulfilled";b:1;s:45:"Symfony\Requirements\RequirementtestMessage";s:96:"The package "composer/ca-bundle" requires the extension "pcre". Enable it or install a polyfill.";s:42:"Symfony\Requirements\RequirementhelpText";s:63:"The package "composer/ca-bundle" requires the extension "pcre".";s:42:"Symfony\Requirements\RequirementhelpHtml";s:0:"";s:42:"Symfony\Requirements\Requirementoptional";b:0;}i:5;O:32:"Symfony\Requirements\Requirement":5:{s:43:"Symfony\Requirements\Requirementfulfilled";b:1;s:45:"Symfony\Requirements\RequirementtestMessage";s:99:"The package "nikic/php-parser" requires the extension "tokenizer". Enable it or install a polyfill.";s:42:"Symfony\Requirements\RequirementhelpText";s:66:"The package "nikic/php-parser" requires the extension "tokenizer".";s:42:"Symfony\Requirements\RequirementhelpHtml";s:0:"";s:42:"Symfony\Requirements\Requirementoptional";b:0;}};m:a:0:{}}}';
45
46
    public static function checkRequirements()
47
    {
48
        $requirements = unserialize(
49
            self::$requirements,
0 ignored issues
show
Bug introduced by
self::requirements of type Symfony\Requirements\RequirementCollection is incompatible with the type string expected by parameter $str of unserialize(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

49
            /** @scrutinizer ignore-type */ self::$requirements,
Loading history...
50
            [
51
                'allowed_classes' => [
52
                    'ArrayIterator',
53
                    'Symfony\Requirements\Requirement',
54
                    'Symfony\Requirements\RequirementCollection',
55
                ]
56
            ]
57
        );
58
59
        [$verbose, $debug] = self::retrieveConfig();
60
61
        $checkPassed = self::check($requirements, $verbose, $debug);
62
63
        if (false === $checkPassed) {
64
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
65
        }
66
    }
67
68
    /**
69
     * @return bool[] The first value is the verbosity and the second is wether debug is enabled or not
70
     */
71
    private static function retrieveConfig()
72
    {
73
        $input = new ArgvInput();
0 ignored issues
show
Unused Code introduced by
The assignment to $input is dead and can be removed.
Loading history...
74
75
        return [true, true];
76
77
        if (true === $input->hasParameterOption(array('--ansi'), true)) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
78
            $output->setDecorated(true);
79
        } elseif (true === $input->hasParameterOption(array('--no-ansi'), true)) {
80
            $output->setDecorated(false);
81
        }
82
83
        if (true === $input->hasParameterOption(array('--no-interaction', '-n'), true)) {
84
            $input->setInteractive(false);
85
        } elseif (function_exists('posix_isatty')) {
86
            $inputStream = null;
87
88
            if ($input instanceof StreamableInputInterface) {
0 ignored issues
show
Bug introduced by
The type KevinGH\Box\RequirementC...treamableInputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
89
                $inputStream = $input->getStream();
90
            }
91
92
            if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
93
                $input->setInteractive(false);
94
            }
95
        }
96
97
        switch ($shellVerbosity = (int)getenv('SHELL_VERBOSITY')) {
98
            case -1:
99
                $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
0 ignored issues
show
Bug introduced by
The type KevinGH\Box\RequirementChecker\OutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
100
                break;
101
            case 1:
102
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
103
                break;
104
            case 2:
105
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
106
                break;
107
            case 3:
108
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
109
                break;
110
            default:
111
                $shellVerbosity = 0;
112
                break;
113
        }
114
115
        if (true === $input->hasParameterOption(array('--quiet', '-q'), true)) {
116
            $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
117
            $shellVerbosity = -1;
118
        } else {
119
            if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) {
120
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
121
                $shellVerbosity = 3;
122
            } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) {
123
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
124
                $shellVerbosity = 2;
125
            } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) {
126
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
127
                $shellVerbosity = 1;
128
            }
129
        }
130
131
        if (-1 === $shellVerbosity) {
132
            $input->setInteractive(false);
133
        }
134
135
        putenv('SHELL_VERBOSITY=' . $shellVerbosity);
136
        $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
137
        $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
138
    }
139
140
    /**
141
     * @param RequirementCollection $requirements
142
     * @param bool $verbose
143
     * @param bool $debug
144
     *
145
     * @return bool
146
     */
147
    private static function check(RequirementCollection $requirements, $verbose, $debug)
148
    {
149
        $lineSize = 70;
150
        $iniPath = $requirements->getPhpIniPath();
151
152
        $checkPassed = self::evaluateRequirements($requirements, $lineSize);
153
154
        if (false === $checkPassed) {
155
            // Override the default verbosity to output errors regardless of the verbosity asked by the user
156
            $verbose = true;
157
        }
158
159
        self::echoTitle('Box Requirements Checker', 'title', $verbose);
160
161
        self::print('> PHP is using the following php.ini file:' . PHP_EOL, $verbose);
162
163
        if ($iniPath) {
164
            self::echo_style('green', '  ' . $iniPath, $verbose);
165
        } else {
166
            self::echo_style('yellow', '  WARNING: No configuration file (php.ini) used by PHP!', $verbose);
167
        }
168
169
        self::print(PHP_EOL . PHP_EOL, $verbose);
170
        self::print('> Checking Box requirements:' . PHP_EOL . '  ', $verbose);
171
172
        $messages = [];
173
174
        foreach ($requirements->getRequirements() as $requirement) {
175
            if ($helpText = self::getErrorMessage($requirement, $lineSize)) {
176
                if ($debug) {
177
                    self::echo_style('red', '✘ ' . $requirement->getTestMessage() . PHP_EOL . '  ', $verbose);
178
                } else {
179
                    self::echo_style('red', 'E', $verbose);
180
                    $messages['error'][] = $helpText;
181
                }
182
            } elseif ($debug) {
183
                self::echo_style('green', '✔ ' . $requirement->getHelpText() . PHP_EOL . '  ', $verbose);
184
            } else {
185
                self::echo_style('green', '.', $verbose);
186
            }
187
        }
188
189
        foreach ($requirements->getRecommendations() as $requirement) {
190
            if ($helpText = self::getErrorMessage($requirement, $lineSize)) {
191
                self::echo_style('yellow', 'W', $verbose);
192
                $messages['warning'][] = $helpText;
193
            } else {
194
                self::echo_style('green', '.', $verbose);
195
            }
196
        }
197
198
        if ($checkPassed) {
0 ignored issues
show
introduced by
The condition $checkPassed is always false.
Loading history...
199
            self::echo_block($lineSize, 'success', 'OK', 'Your system is ready to run the application.', $verbose);
200
        } else {
201
            self::echo_block($lineSize, 'error', 'ERROR', 'Your system is not ready to run the application', $verbose);
202
203
            if (false === $debug) {
204
                self::echoTitle('Fix the following mandatory requirements', 'red', $verbose);
205
206
                foreach ($messages['error'] as $helpText) {
207
                    self::print(' * ' . $helpText . PHP_EOL, $verbose);
208
                }
209
            }
210
        }
211
212
        if (!empty($messages['warning'])) {
213
            self::echoTitle('Optional recommendations to improve your setup', 'yellow', $verbose);
214
215
            foreach ($messages['warning'] as $helpText) {
216
                self::print(' * ' . $helpText . PHP_EOL, $verbose);
217
            }
218
        }
219
220
        return $checkPassed;
221
    }
222
223
    /**
224
     * @param RequirementCollection $requirements
225
     * @param int $lineSize
226
     * 
227
     * @return bool
228
     */
229
    private static function evaluateRequirements(RequirementCollection $requirements, $lineSize)
230
    {
231
        return array_reduce(
232
            $requirements->getRequirements(),
233
            /**
234
             * @param bool $checkPassed
235
             * @param Requirement $requirement
236
             *
237
             * @return bool
238
             */
239
            function ($checkPassed, Requirement $requirement) use ($lineSize) {
240
                return $checkPassed && null === self::getErrorMessage($requirement, $lineSize);
241
            },
242
            false
243
        );
244
    }
245
246
    private static function print($message, $verbose)
247
    {
248
        if (false === $verbose) {
249
            return;
250
        }
251
252
        echo $message;
253
    }
254
255
    /**
256
     * @param Requirement $requirement
257
     * @param int $lineSize
258
     *
259
     * @return string|null
260
     */
261
    private static function getErrorMessage(Requirement $requirement, $lineSize)
262
    {
263
        if ($requirement->isFulfilled()) {
264
            return null;
265
        }
266
267
        $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL . '   ') . PHP_EOL;
268
269
        return $errorMessage;
270
    }
271
272
    /**
273
     * @param string $title
274
     * @param string $style
275
     * @param bool $verbose
276
     */
277
    private static function echoTitle($title, $style = null, $verbose)
278
    {
279
        if (false === $verbose) {
280
            return;
281
        }
282
283
        echo PHP_EOL;
284
        self::echo_style($style, $title . PHP_EOL, $verbose);
285
        self::echo_style($style, str_repeat('=', strlen($title)) . PHP_EOL, $verbose);
286
        echo PHP_EOL;
287
    }
288
289
    /**
290
     * @param string $style
291
     * @param string $message
292
     * @param bool $verbose
293
     */
294
    private static function echo_style($style, $message, $verbose)
295
    {
296
        if (false === $verbose) {
297
            return;
298
        }
299
300
        // ANSI color codes
301
        $styles = array(
302
            'reset' => "\033[0m",
303
            'red' => "\033[31m",
304
            'green' => "\033[32m",
305
            'yellow' => "\033[33m",
306
            'error' => "\033[37;41m",
307
            'success' => "\033[30;42m",
308
        );
309
310
        $styles['title'] = $styles['yellow'];
311
312
        $supports = self::hasColorSupports();
313
314
        echo ($supports ? $styles[$style] : '') . $message . ($supports ? $styles['reset'] : '');
315
    }
316
317
    /**
318
     * @param int $lineSize
319
     * @param string $style
320
     * @param string $title
321
     * @param string $message
322
     * 
323
     * @param bool $verbose
324
     */
325
    private static function echo_block($lineSize, $style, $title, $message, $verbose)
326
    {
327
        if (false === $verbose) {
328
            return;
329
        }
330
331
        $message = str_pad(' [' . $title . '] ' . trim($message) . ' ', $lineSize, ' ', STR_PAD_RIGHT);
332
333
        $width = $lineSize;
334
335
        echo PHP_EOL . PHP_EOL;
336
337
        self::echo_style($style, str_repeat(' ', $width), $verbose);
338
        echo PHP_EOL;
339
        self::echo_style($style, $message, $verbose);
340
        echo PHP_EOL;
341
        self::echo_style($style, str_repeat(' ', $width), $verbose);
342
        echo PHP_EOL;
343
    }
344
345
    /**
346
     * @return bool
347
     */
348
    private static function hasColorSupports()
349
    {
350
        static $support;
351
352
        if (null === $support) {
353
            if (DIRECTORY_SEPARATOR == '\\') {
354
                $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
355
            } else {
356
                $support = function_exists('posix_isatty') && @posix_isatty(STDOUT);
357
            }
358
        }
359
360
        return $support;
361
    }
362
}
363
364
Checker::checkRequirements();
365