Completed
Pull Request — master (#8)
by Povilas
03:23 queued 01:26
created

Command   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
c 1
b 0
f 0
lcom 1
cbo 12
dl 0
loc 152
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getCSVOption() 0 10 2
A castToNumber() 0 8 2
A configure() 0 47 1
C execute() 0 46 9
A createOption() 0 12 2
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
                'progress',
68
                null,
69
                InputOption::VALUE_NONE,
70
                'Show progress bar'
71
            );
72
    }
73
74
    /**
75
     * @inheritdoc
76
     */
77
    protected function execute(InputInterface $input, OutputInterface $output)
78
    {
79
        $finder = new PHPFinder();
80
        $finder
81
            ->in($input->getArgument('directory'))
82
            ->exclude(array_merge(['vendor'], $input->getOption('exclude')));
83
84
        if (0 === $finder->count()) {
85
            $output->writeln('No files found to scan');
86
            exit(1);
87
        }
88
89
        $progressBar = null;
90
        if ($input->getOption('progress')) {
91
            $progressBar = new ProgressBar($output, $finder->count());
92
            $progressBar->start();
93
        }
94
95
        $detector = new Detector($this->createOption($input));
96
97
        $printer = new Printer();
98
        foreach ($finder as $file) {
99
            try {
100
                $fileReport = $detector->detect($file);
101
                if ($fileReport->hasMagicNumbers()) {
102
                    $printer->addFileReport($fileReport);
103
                }
104
            } catch (\Exception $e) {
105
                $output->writeln($e->getMessage());
106
            }
107
108
            if ($input->getOption('progress')) {
109
                $progressBar->advance();
110
            }
111
        }
112
113
        if ($input->getOption('progress')) {
114
            $progressBar->finish();
115
        }
116
117
        if ($output->getVerbosity() !== OutputInterface::VERBOSITY_QUIET) {
118
            $output->writeln('');
119
            $printer->printData($output);
120
            $output->writeln('<info>' . \PHP_Timer::resourceUsage() . '</info>');
121
        }
122
    }
123
124
    /**
125
     * @param InputInterface $input
126
     * @param string $option
127
     *
128
     * @return array
129
     */
130
    private function getCSVOption(InputInterface $input, $option)
131
    {
132
        $result = $input->getOption($option);
133
        if (false === is_array($result)) {
134
            $result = explode(',', $result);
135
            $result = array_map([$this, 'castToNumber'], $result);
136
        }
137
138
        return $result;
139
    }
140
141
    /**
142
     * @param string $value
143
     *
144
     * @return int|float|string
145
     */
146
    private function castToNumber($value)
147
    {
148
        if (is_numeric($value)) {
149
            $value += 0; // '2' -> (int) 2, '2.' -> (float) 2.0
150
        }
151
152
        return $value;
153
    }
154
155
    /**
156
     * @param InputInterface $input
157
     * @return Option
158
     * @throws \Exception
159
     */
160
    private function createOption(InputInterface $input)
161
    {
162
        $option = new Option;
163
        $option->setIgnoreNumbers($this->getCSVOption($input, 'ignore-numbers'));
164
        $option->setIgnoreFuncs($this->getCSVOption($input, 'ignore-funcs'));
165
        $extensions = $this->getCSVOption($input, 'extensions');
166
        foreach ($extensions as $extensionName) {
167
            $option->addExtension(ExtensionFactory::create($extensionName));
168
        }
169
170
        return $option;
171
    }
172
}
173