Completed
Push — master ( cfa785...3f4fca )
by Дмитрий
02:53
created

CheckCommand   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 13.33%

Importance

Changes 18
Bugs 2 Features 4
Metric Value
c 18
b 2
f 4
dl 0
loc 147
ccs 12
cts 90
cp 0.1333
rs 9.1666
wmc 14
lcom 1
cbo 15

4 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 14 1
C execute() 0 112 11
A getMemoryUsage() 0 4 1
A getCompiler() 0 4 1
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
        Analyzer\Factory::factory($em);
96
        
97
        $context = new Context($output, $application, $em);
98
99
        /**
100
         * Store option's in application's configuration
101
         */
102
        $blame = $input->getOption('blame');
103
        if ($blame === -1) {
104
            $application->configuration->setValue('blame', $blame);
105
        }
106
107
        $fileParser = new FileParser(
108
            $parser,
109
            $this->getCompiler()
110
        );
111
112
        $path = $input->getArgument('path');
113
        if (is_dir($path)) {
114
            $directoryIterator = new RecursiveIteratorIterator(
115
                new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)
116
            );
117
            $output->writeln('Scanning directory <info>' . $path . '</info>');
118
119
            $count = 0;
120
121
            /** @var SplFileInfo $file */
122
            foreach ($directoryIterator as $file) {
123
                if ($file->getExtension() != 'php') {
124
                    continue;
125
                }
126
127
                $context->debug($file->getPathname());
128
                $count++;
129
            }
130
131
            $output->writeln("Found <info>{$count} files</info>");
132
133
            if ($count > 100) {
134
                $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>');
135
            }
136
137
            $output->writeln('');
138
139
            /** @var SplFileInfo $file */
140
            foreach ($directoryIterator as $file) {
141
                if ($file->getExtension() != 'php') {
142
                    continue;
143
                }
144
145
                $fileParser->parserFile($file->getPathname(), $context);
146
            }
147
        } elseif (is_file($path)) {
148
            $fileParser->parserFile($path, $context);
149
        }
150
151
152
        /**
153
         * Step 2 Recursive check ...
154
         */
155
        $application->compiler->compile($context);
156
157
        $jsonReport = $input->getOption('report-json');
158
        if ($jsonReport) {
159
            file_put_contents(
160
                $jsonReport,
161
                json_encode(
162
                    $this->getApplication()->getIssuesCollector()->getIssues()
163
                )
164
            );
165
        }
166
167
        $output->writeln('');
168
        $output->writeln('Memory usage: ' . $this->getMemoryUsage(false) . ' (peak: ' . $this->getMemoryUsage(true) . ') MB');
169
    }
170
171
    /**
172
     * @param boolean $type
173
     * @return float
174
     */
175
    protected function getMemoryUsage($type)
176
    {
177
        return round(memory_get_usage($type) / 1024 / 1024, 2);
178
    }
179
180
    /**
181
     * @return Compiler
182
     */
183
    protected function getCompiler()
184
    {
185
        return $this->getApplication()->compiler;
186
    }
187
}
188