Completed
Pull Request — master (#42)
by Povilas
02:03
created

Command::configure()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 79
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 79
rs 8.8701
cc 1
eloc 60
nc 1
nop 0

How to fix   Long Method   

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
                'suffixes',
80
                null,
81
                InputOption::VALUE_REQUIRED,
82
                'Comma-separated string of valid source code filename extensions',
83
                'php'
84
            )
85
            ->addOption(
86
                'progress',
87
                null,
88
                InputOption::VALUE_NONE,
89
                'Show progress bar'
90
            )
91
            ->addOption(
92
                'strings',
93
                null,
94
                InputOption::VALUE_NONE,
95
                'Include strings literal search in code analysis'
96
            )
97
            ->addOption(
98
                'ignore-strings',
99
                null,
100
                InputOption::VALUE_REQUIRED,
101
                'A comma-separated list of strings to ignore when using "strings" option',
102
                []
103
            );
104
    }
105
106
    /**
107
     * @inheritdoc
108
     */
109
    protected function execute(InputInterface $input, OutputInterface $output)
110
    {
111
        $finder = new PHPFinder(
112
            $input->getArgument('directory'),
113
            $input->getOption('exclude'),
114
            $input->getOption('exclude-path'),
115
            $input->getOption('exclude-file'),
116
            $this->getCSVOption($input, 'suffixes')
117
        );
118
119
        if (0 === $finder->count()) {
120
            $output->writeln('No files found to scan');
121
            exit(1);
122
        }
123
124
        $progressBar = null;
125
        if ($input->getOption('progress')) {
126
            $progressBar = new ProgressBar($output, $finder->count());
127
            $progressBar->start();
128
        }
129
130
        $detector = new Detector($this->createOption($input));
131
132
        $printer = new Printer();
133
        foreach ($finder as $file) {
134
            try {
135
                $fileReport = $detector->detect($file);
136
                if ($fileReport->hasMagicNumbers()) {
137
                    $printer->addFileReport($fileReport);
138
                }
139
            } catch (\Exception $e) {
140
                $output->writeln($e->getMessage());
141
            }
142
143
            if ($input->getOption('progress')) {
144
                $progressBar->advance();
145
            }
146
        }
147
148
        if ($input->getOption('progress')) {
149
            $progressBar->finish();
150
        }
151
152
        if ($output->getVerbosity() !== OutputInterface::VERBOSITY_QUIET) {
153
            $output->writeln('');
154
            $printer->printData($output);
155
            $output->writeln('<info>' . \PHP_Timer::resourceUsage() . '</info>');
156
        }
157
    }
158
159
    /**
160
     * @param InputInterface $input
161
     * @return Option
162
     * @throws \Exception
163
     */
164
    private function createOption(InputInterface $input)
165
    {
166
        $option = new Option;
167
        $option->setIgnoreNumbers(array_map([$this, 'castToNumber'], $this->getCSVOption($input, 'ignore-numbers')));
168
        $option->setIgnoreFuncs($this->getCSVOption($input, 'ignore-funcs'));
169
        $option->setIncludeStrings($input->getOption('strings'));
170
        $option->setIgnoreStrings($input->getOption('ignore-strings'));
171
        $extensions = $this->getCSVOption($input, 'extensions');
172
        foreach ($extensions as $extensionName) {
173
            $option->addExtension(ExtensionFactory::create($extensionName));
174
        }
175
176
        return $option;
177
    }
178
179
    /**
180
     * @param InputInterface $input
181
     * @param string $option
182
     *
183
     * @return array
184
     */
185
    private function getCSVOption(InputInterface $input, $option)
186
    {
187
        $result = $input->getOption($option);
188
        if (false === is_array($result)) {
189
            return explode(',', $result);
190
        }
191
192
        return $result;
193
    }
194
195
    /**
196
     * @param string $value
197
     *
198
     * @return int|float|string
199
     */
200
    private function castToNumber($value)
201
    {
202
        if (is_numeric($value)) {
203
            $value += 0; // '2' -> (int) 2, '2.' -> (float) 2.0
204
        }
205
206
        return $value;
207
    }
208
}
209