Completed
Push — master ( b4c4dd...81ea86 )
by Povilas
11s
created

Command::execute()   D

Complexity

Conditions 11
Paths 356

Size

Total Lines 54
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 54
rs 4.941
cc 11
eloc 33
nc 356
nop 2

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
namespace Povils\PHPMND\Console;
4
5
use Povils\PHPMND\Detector;
6
use Povils\PHPMND\ExtensionFactory;
7
use Povils\PHPMND\PHPFinder;
8
use Povils\PHPMND\Printer;
9
use Symfony\Component\Console\Command\Command as BaseCommand;
10
use Symfony\Component\Console\Helper\ProgressBar;
11
use Symfony\Component\Console\Input\InputArgument;
12
use Symfony\Component\Console\Input\InputInterface;
13
use Symfony\Component\Console\Input\InputOption;
14
use Symfony\Component\Console\Output\OutputInterface;
15
16
/**
17
 * Class Command
18
 *
19
 * @package Povils\PHPMND\Console
20
 */
21
class Command extends BaseCommand
22
{
23
    /**
24
     * @inheritdoc
25
     */
26
    protected function configure()
27
    {
28
        $this
29
            ->setName('phpmnd')
30
            ->setDefinition(
31
                [
32
                    new InputArgument(
33
                        'directory',
34
                        InputArgument::REQUIRED,
35
                        'Directory to analyze'
36
                    )
37
                ]
38
            )
39
            ->addOption(
40
                'extensions',
41
                null,
42
                InputOption::VALUE_REQUIRED,
43
                'A comma-separated list of extensions',
44
                []
45
            )
46
            ->addOption(
47
                'ignore-numbers',
48
                null,
49
                InputOption::VALUE_REQUIRED,
50
                'A comma-separated list of numbers to ignore',
51
                [0, 1]
52
            )
53
            ->addOption(
54
                'ignore-funcs',
55
                null,
56
                InputOption::VALUE_REQUIRED,
57
                'A comma-separated list of functions to ignore when using "argument" extension',
58
                []
59
            )
60
            ->addOption(
61
                'exclude',
62
                null,
63
                InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
64
                'Exclude a directory from code analysis (must be relative to source)'
65
            )
66
            ->addOption(
67
               'exclude-path',
68
               null,
69
               InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
70
               'Exclude a path from code analysis (must be relative to source)'
71
            )
72
            ->addOption(
73
               'exclude-file',
74
               null,
75
               InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
76
               'Exclude a file from code analysis (must be relative to source)'
77
            )
78
            ->addOption(
79
                'progress',
80
                null,
81
                InputOption::VALUE_NONE,
82
                'Show progress bar'
83
            );
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89
    protected function execute(InputInterface $input, OutputInterface $output)
90
    {
91
        $finder = new PHPFinder();
92
        $finder
93
            ->in($input->getArgument('directory'))
94
            ->exclude(array_merge(['vendor'], $input->getOption('exclude')));
95
96
        foreach ($input->getOption('exclude-path') as $notPath) {
97
            $finder->notPath($notPath);
98
        }
99
100
        foreach ($input->getOption('exclude-file') as $notName) {
101
            $finder->notName($notName);
102
        }
103
104
        if (0 === $finder->count()) {
105
            $output->writeln('No files found to scan');
106
            exit(1);
107
        }
108
109
        $progressBar = null;
110
        if ($input->getOption('progress')) {
111
            $progressBar = new ProgressBar($output, $finder->count());
112
            $progressBar->start();
113
        }
114
115
        $detector = new Detector($this->createOption($input));
116
117
        $printer = new Printer();
118
        foreach ($finder as $file) {
119
            try {
120
                $fileReport = $detector->detect($file);
121
                if ($fileReport->hasMagicNumbers()) {
122
                    $printer->addFileReport($fileReport);
123
                }
124
            } catch (\Exception $e) {
125
                $output->writeln($e->getMessage());
126
            }
127
128
            if ($input->getOption('progress')) {
129
                $progressBar->advance();
130
            }
131
        }
132
133
        if ($input->getOption('progress')) {
134
            $progressBar->finish();
135
        }
136
137
        if ($output->getVerbosity() !== OutputInterface::VERBOSITY_QUIET) {
138
            $output->writeln('');
139
            $printer->printData($output);
140
            $output->writeln('<info>' . \PHP_Timer::resourceUsage() . '</info>');
141
        }
142
    }
143
144
    /**
145
     * @param InputInterface $input
146
     * @param string $option
147
     *
148
     * @return array
149
     */
150
    private function getCSVOption(InputInterface $input, $option)
151
    {
152
        $result = $input->getOption($option);
153
        if (false === is_array($result)) {
154
            $result = explode(',', $result);
155
            $result = array_map([$this, 'castToNumber'], $result);
156
        }
157
158
        return $result;
159
    }
160
161
    /**
162
     * @param string $value
163
     *
164
     * @return int|float|string
165
     */
166
    private function castToNumber($value)
167
    {
168
        if (is_numeric($value)) {
169
            $value += 0; // '2' -> (int) 2, '2.' -> (float) 2.0
170
        }
171
172
        return $value;
173
    }
174
175
    /**
176
     * @param InputInterface $input
177
     * @return Option
178
     * @throws \Exception
179
     */
180
    private function createOption(InputInterface $input)
181
    {
182
        $option = new Option;
183
        $option->setIgnoreNumbers($this->getCSVOption($input, 'ignore-numbers'));
184
        $option->setIgnoreFuncs($this->getCSVOption($input, 'ignore-funcs'));
185
        $extensions = $this->getCSVOption($input, 'extensions');
186
        foreach ($extensions as $extensionName) {
187
            $option->addExtension(ExtensionFactory::create($extensionName));
188
        }
189
190
        return $option;
191
    }
192
}
193