Completed
Push — master ( b1b3d7...ed93a7 )
by Дмитрий
03:53
created

CheckCommand::execute()   C

Complexity

Conditions 11
Paths 32

Size

Total Lines 142
Code Lines 75

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 12
Bugs 1 Features 4
Metric Value
cc 11
eloc 75
c 12
b 1
f 4
nc 32
nop 2
dl 0
loc 142
ccs 0
cts 97
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
                        ],
107
                        Node\Expr\Array_::class => [
108
                            new AnalyzerPass\Expression\ArrayShortDefinition()
109
                        ]
110
                    ]
111
                )
112
            )
113
            ->method('beforeCompile');
114
        
115
        $em->listen(Compiler\Event\StatementBeforeCompile::EVENT_NAME)
116
            ->handler(
117
                new StatementListener(
118
                    [
119
                        Node\Stmt\ClassMethod::class => [
120
                            new AnalyzerPass\Statement\MethodCannotReturn()
121
                        ]
122
                    ]
123
                )
124
            )
125
            ->method('beforeCompile');
126
127
        $context = new Context($output, $application, $em);
128
129
        /**
130
         * Store option's in application's configuration
131
         */
132
        $blame = $input->getOption('blame');
133
        if ($blame === -1) {
134
            $application->configuration->setValue('blame', $blame);
135
        }
136
137
        $fileParser = new FileParser(
138
            $parser,
139
            $this->getCompiler()
140
        );
141
142
        $path = $input->getArgument('path');
143
        if (is_dir($path)) {
144
            $directoryIterator = new RecursiveIteratorIterator(
145
                new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)
146
            );
147
            $output->writeln('Scanning directory <info>' . $path . '</info>');
148
149
            $count = 0;
150
151
            /** @var SplFileInfo $file */
152
            foreach ($directoryIterator as $file) {
153
                if ($file->getExtension() != 'php') {
154
                    continue;
155
                }
156
157
                $context->debug($file->getPathname());
158
                $count++;
159
            }
160
161
            $output->writeln("Found <info>{$count} files</info>");
162
163
            if ($count > 100) {
164
                $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>');
165
            }
166
167
            $output->writeln('');
168
169
            /** @var SplFileInfo $file */
170
            foreach ($directoryIterator as $file) {
171
                if ($file->getExtension() != 'php') {
172
                    continue;
173
                }
174
175
                $fileParser->parserFile($file->getPathname(), $context);
176
            }
177
        } elseif (is_file($path)) {
178
            $fileParser->parserFile($path, $context);
179
        }
180
181
182
        /**
183
         * Step 2 Recursive check ...
184
         */
185
        $application->compiler->compile($context);
186
187
        $jsonReport = $input->getOption('report-json');
188
        if ($jsonReport) {
189
            file_put_contents(
190
                $jsonReport,
191
                json_encode(
192
                    $this->getApplication()->getIssuesCollector()->getIssues()
193
                )
194
            );
195
        }
196
197
        $output->writeln('');
198
        $output->writeln('Memory usage: ' . $this->getMemoryUsage(false) . ' (peak: ' . $this->getMemoryUsage(true) . ') MB');
199
    }
200
201
    /**
202
     * @param boolean $type
203
     * @return float
204
     */
205
    protected function getMemoryUsage($type)
206
    {
207
        return round(memory_get_usage($type) / 1024 / 1024, 2);
208
    }
209
210
    /**
211
     * @return Compiler
212
     */
213
    protected function getCompiler()
214
    {
215
        return $this->getApplication()->compiler;
216
    }
217
}
218