FinderCommand::flatten()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4286
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
/**
3
 * Author: Nil Portugués Calderó <[email protected]>
4
 * Date: 11/9/15
5
 * Time: 10:10 PM
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace NilPortugues\TodoFinder\Command;
11
12
use NilPortugues\TodoFinder\Finder\FileParser;
13
use NilPortugues\TodoFinder\Command\Exceptions\ConfigFileException;
14
use NilPortugues\TodoFinder\Finder\FileSystem;
15
use Symfony\Component\Console\Command\Command;
16
use Symfony\Component\Console\Input\InputArgument;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
21
class FinderCommand extends Command
22
{
23
    const COMMAND_NAME = 'find';
24
    const CONFIG_FILE  = 'php_todo_finder.yml';
25
    const TODO_FINDER  = 'todo_finder';
26
27
    /**
28
     * @var array
29
     */
30
    private $errors = [];
31
32
    /**
33
     *
34
     */
35
    protected function configure()
36
    {
37
        $this
38
            ->setName(self::COMMAND_NAME)
39
            ->setDescription(
40
                'Looks into the code using a user-defined list of to-do phrases and stops commit if the'
41
                .' total amount increased or is above a threshold.'
42
            )
43
            ->addArgument(self::COMMAND_NAME, InputArgument::REQUIRED, 'File Path')
44
            ->addOption('config', '-c', InputOption::VALUE_OPTIONAL, 'Config File', self::CONFIG_FILE);
45
    }
46
47
    /**
48
     * @param InputInterface  $input
49
     * @param OutputInterface $output
50
     *
51
     * @return int|null
52
     * @throws Exceptions\ConfigFileException
53
     * @throws \Exception
54
     */
55
    protected function execute(InputInterface $input, OutputInterface $output)
56
    {
57
        $path       = $input->getArgument(self::COMMAND_NAME);
58
        $realPath   = realpath($path);
59
        $configFile = $input->getOption('config');
60
61
        $finder = new FileParser($configFile);
62
63
        if (file_exists($configFile)) {
64
            $this->scanFiles($path, $finder);
65
66
            if (!empty($this->errors)) {
67
                $output->writeln("<info>To-do expressions were found:</info>\n");
68
                foreach ($this->errors as $file => $lines) {
69
                    foreach ($lines as $line) {
70
                        $output->writeln(
71
                            sprintf(
72
                                "<comment> - .%s:</comment> %s",
73
                                str_replace($realPath, '', $file),
74
                                $line
75
                            )
76
                        );
77
                    }
78
                }
79
80
                if (count($this->flatten($this->errors)) > $finder->getTotalAllowed()) {
81
                    throw new \Exception('To-do statements are piling up! Isn\'t it time to address this issue?');
82
                }
83
            }
84
85
            return $output->writeln("<info>\nCongratulations! To-do statements are under control.\n</info>");
86
        }
87
88
        throw new ConfigFileException($configFile);
89
    }
90
91
    /**
92
     * @param            $path
93
     * @param FileParser $finder
94
     */
95
    protected function scanFiles($path, FileParser $finder)
96
    {
97
        $fileSystem = new FileSystem();
98
99
        foreach ($fileSystem->getFilesFromPath($path) as $file) {
100
            $tokens = token_get_all(file_get_contents($file));
101
            foreach ($tokens as $token) {
102
                $this->scanForTodoFinder($finder, $token, $file);
103
            }
104
        }
105
    }
106
107
    /**
108
     * @param FileParser $finder
109
     * @param            $token
110
     * @param            $file
111
     */
112
    protected function scanForTodoFinder(FileParser $finder, $token, $file)
113
    {
114
        if (is_array($token) && count($token) === 3) {
115
            $type       = $token[0];
116
            $code       = $token[1];
117
            $lineNumber = $token[2];
118
119
            if (in_array($type, [T_COMMENT, T_DOC_COMMENT], \true)) {
120
                foreach ($finder->getTodoExpressions() as $todoExpression) {
121
                    if (false !== strpos(\strtolower($code), \strtolower($todoExpression))) {
122
                        $this->errors[$file][$lineNumber] = \sprintf(
123
                            '\'%s\' found on line %s.',
124
                            $todoExpression,
125
                            $lineNumber
126
                        );
127
                    }
128
                }
129
            }
130
        }
131
    }
132
133
    private function flatten(array $array)
134
    {
135
        $return = array();
136
        array_walk_recursive(
137
            $array,
138
            function ($a) use (&$return) {
139
                $return[] = $a;
140
            }
141
        );
142
143
        return $return;
144
    }
145
}
146