Completed
Pull Request — master (#38)
by Pádraic
02:50
created

Command::execute()   D

Complexity

Conditions 9
Paths 89

Size

Total Lines 43
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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