Completed
Push — master ( ed93a7...cfa785 )
by Дмитрий
04:06
created

CheckCommand::execute()   C

Complexity

Conditions 11
Paths 32

Size

Total Lines 143
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 13
Bugs 1 Features 4
Metric Value
cc 11
eloc 76
c 13
b 1
f 4
nc 32
nop 2
dl 0
loc 143
ccs 0
cts 98
cp 0
crap 132
rs 5.2653

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
 * @author Patsura Dmitry https://github.com/ovr <[email protected]>
4
 */
5
6
namespace PHPSA\Command;
7
8
use PhpParser\ParserFactory;
9
use PHPSA\Analyzer;
10
use PHPSA\Analyzer\EventListener\ExpressionListener;
11
use PHPSA\Analyzer\EventListener\StatementListener;
12
use PHPSA\Application;
13
use PHPSA\Compiler;
14
use PHPSA\Configuration;
15
use PHPSA\ConfigurationLoader;
16
use PHPSA\Context;
17
use PHPSA\Definition\FileParser;
18
use RecursiveDirectoryIterator;
19
use RecursiveIteratorIterator;
20
use SplFileInfo;
21
use FilesystemIterator;
22
use PhpParser\Node;
23
use PhpParser\Parser;
24
use Symfony\Component\Config\Definition\Processor;
25
use Symfony\Component\Config\FileLocator;
26
use Symfony\Component\Config\Loader\LoaderResolver;
27
use Symfony\Component\Console\Command\Command;
28
use Symfony\Component\Console\Input\InputArgument;
29
use Symfony\Component\Console\Input\InputInterface;
30
use Symfony\Component\Console\Input\InputOption;
31
use Symfony\Component\Console\Output\OutputInterface;
32
use Webiny\Component\EventManager\EventManager;
33
use PHPSA\Analyzer\Pass as AnalyzerPass;
34
35
/**
36
 * Class CheckCommand
37
 * @package PHPSA\Command
38
 *
39
 * @method Application getApplication();
40
 */
41
class CheckCommand extends Command
42
{
43 379
    protected function configure()
44
    {
45 379
        $this
46 379
            ->setName('check')
47 379
            ->setDescription('SPA')
48 379
            ->addOption('blame', null, InputOption::VALUE_OPTIONAL, 'Git blame author for bad code ;)', -1)
49 379
            ->addArgument('path', InputArgument::OPTIONAL, 'Path to check file or directory', '.')
50 379
            ->addOption(
51 379
                'report-json',
52 379
                null,
53 379
                InputOption::VALUE_REQUIRED,
54
                'Path to save detailed report in JSON format. Example: /tmp/report.json'
55 379
            );
56 379
    }
57
58
    protected function execute(InputInterface $input, OutputInterface $output)
59
    {
60
        $output->writeln('');
61
62
        if (extension_loaded('xdebug')) {
63
            $output->writeln('<error>It is highly recommended to disable the XDebug extension before invoking this command.</error>');
64
        }
65
66
        $parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7, new \PhpParser\Lexer\Emulative(
67
            array(
68
                'usedAttributes' => array(
69
                    'comments',
70
                    'startLine',
71
                    'endLine',
72
                    'startTokenPos',
73
                    'endTokenPos'
74
                )
75
            )
76
        ));
77
78
        /** @var Application $application */
79
        $application = $this->getApplication();
80
        $application->compiler = new Compiler();
81
82
        $loader = new ConfigurationLoader(
83
            new FileLocator(
84
                [
85
                    realpath($input->getArgument('path')) . DIRECTORY_SEPARATOR
86
                ]
87
            )
88
        );
89
90
        $application->configuration = new Configuration(
91
            $loader->load('.phpsa.yml')
92
        );
93
94
        $em = EventManager::getInstance();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $em. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
95
96
        $em->listen(Compiler\Event\ExpressionBeforeCompile::EVENT_NAME)
97
            ->handler(
98
                new ExpressionListener(
99
                    [
100
                        Node\Expr\FuncCall::class => [
101
                            new AnalyzerPass\Expression\FunctionCall\AliasCheck(),
102
                            new AnalyzerPass\Expression\FunctionCall\DebugCode(),
103
                            new AnalyzerPass\Expression\FunctionCall\RandomApiMigration(),
104
                            new AnalyzerPass\Expression\FunctionCall\UseCast(),
105
                            new AnalyzerPass\Expression\FunctionCall\DeprecatedIniOptions(),
106
                            new AnalyzerPass\Expression\FunctionCall\RegularExpressions(),
107
                        ],
108
                        Node\Expr\Array_::class => [
109
                            new AnalyzerPass\Expression\ArrayShortDefinition()
110
                        ]
111
                    ]
112
                )
113
            )
114
            ->method('beforeCompile');
115
        
116
        $em->listen(Compiler\Event\StatementBeforeCompile::EVENT_NAME)
117
            ->handler(
118
                new StatementListener(
119
                    [
120
                        Node\Stmt\ClassMethod::class => [
121
                            new AnalyzerPass\Statement\MethodCannotReturn()
122
                        ]
123
                    ]
124
                )
125
            )
126
            ->method('beforeCompile');
127
128
        $context = new Context($output, $application, $em);
129
130
        /**
131
         * Store option's in application's configuration
132
         */
133
        $blame = $input->getOption('blame');
134
        if ($blame === -1) {
135
            $application->configuration->setValue('blame', $blame);
136
        }
137
138
        $fileParser = new FileParser(
139
            $parser,
140
            $this->getCompiler()
141
        );
142
143
        $path = $input->getArgument('path');
144
        if (is_dir($path)) {
145
            $directoryIterator = new RecursiveIteratorIterator(
146
                new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)
147
            );
148
            $output->writeln('Scanning directory <info>' . $path . '</info>');
149
150
            $count = 0;
151
152
            /** @var SplFileInfo $file */
153
            foreach ($directoryIterator as $file) {
154
                if ($file->getExtension() != 'php') {
155
                    continue;
156
                }
157
158
                $context->debug($file->getPathname());
159
                $count++;
160
            }
161
162
            $output->writeln("Found <info>{$count} files</info>");
163
164
            if ($count > 100) {
165
                $output->writeln('<comment>Caution: You are trying to scan a lot of files; this might be slow. For bigger libraries, consider setting up a dedicated platform or using ci.lowl.io.</comment>');
166
            }
167
168
            $output->writeln('');
169
170
            /** @var SplFileInfo $file */
171
            foreach ($directoryIterator as $file) {
172
                if ($file->getExtension() != 'php') {
173
                    continue;
174
                }
175
176
                $fileParser->parserFile($file->getPathname(), $context);
177
            }
178
        } elseif (is_file($path)) {
179
            $fileParser->parserFile($path, $context);
180
        }
181
182
183
        /**
184
         * Step 2 Recursive check ...
185
         */
186
        $application->compiler->compile($context);
187
188
        $jsonReport = $input->getOption('report-json');
189
        if ($jsonReport) {
190
            file_put_contents(
191
                $jsonReport,
192
                json_encode(
193
                    $this->getApplication()->getIssuesCollector()->getIssues()
194
                )
195
            );
196
        }
197
198
        $output->writeln('');
199
        $output->writeln('Memory usage: ' . $this->getMemoryUsage(false) . ' (peak: ' . $this->getMemoryUsage(true) . ') MB');
200
    }
201
202
    /**
203
     * @param boolean $type
204
     * @return float
205
     */
206
    protected function getMemoryUsage($type)
207
    {
208
        return round(memory_get_usage($type) / 1024 / 1024, 2);
209
    }
210
211
    /**
212
     * @return Compiler
213
     */
214
    protected function getCompiler()
215
    {
216
        return $this->getApplication()->compiler;
217
    }
218
}
219