ListElements::execute()   C
last analyzed

Complexity

Conditions 13
Paths 25

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 5.1234
c 0
b 0
f 0
nc 25
cc 13
eloc 24
nop 2

How to fix   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 Magium\Cli\Command;
4
5
use Magium\InvalidConfigurationException;
6
use Magium\NotFoundException;
7
use Symfony\Component\Console\Command\Command;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Output\OutputInterface;
12
13
class ListElements extends Command
14
{
15
    protected static $dirs = [];
16
17
    public static function addDirectory($dir, $namespace)
18
    {
19
        if ($dir != realpath($dir)) {
20
            throw new InvalidConfigurationException('Path not found.  Please ensure that you pass the realpath() in: ' . $dir);
21
        }
22
        self::$dirs[$dir] = $namespace;
23
    }
24
25
    protected function configure()
26
    {
27
        $this->setName('element:list');
28
        $this->setDescription('Extracts all of the AbstractConfigurableElement-based objects');
29
        $this->setHelp(<<<HELP
30
This command will traverse all known directories, or a specific directory, and return a list of all the classes found that extend Magium\\AbstractConfigurableElement in some way.
31
32
It can be used in conjunction with the magium:element:get to narrow down exactly which configuration value you are looking for.
33
 
34
There are two modes of operation to be aware of.
35
 
36
1. Argument mode
37
38
If you run with the "directory" and "namespace" arguments (if one is provided both are required) then this command will recursively descend into this directory and find all configurable elements.
39
40
2. Argument-less mode
41
42
Running without the options will cause the command to search through all registered paths.
43
44
An individual module is responsible to register its paths and does so by creating an autoload register.php file which contains at least the following code
45
46
<?php
47
48
Magium\Cli\Command\ListElements::addDirectory('my test dir', 'my\\test\\namespace');
49
50
Again, all classes must be defined in PSR-4-autoload format.  Custom autoloaders may be used, but the PSR-4 format is there to deduce the name of the class based on the file name.
51
52
HELP
53
);
54
        $this->addArgument(
55
            'directory',
56
            InputArgument::OPTIONAL,
57
            'The name of the directory to traverse'
58
        );
59
60
        $this->addArgument(
61
            'namespace',
62
            InputArgument::OPTIONAL,
63
            'The psr-4 base namespace of the directory.  Required if <directory> is used'
64
        );
65
        $this->addArgument(
66
            'filter',
67
            InputArgument::OPTIONAL,
68
            'A stripos()-compatible filter'
69
        );
70
71
        $this->addOption(
72
            'escape',
73
            '--esc',
74
            InputOption::VALUE_NONE,
75
            'Set if you want the namespace output escaped (useful for copy and paste)'
76
        );
77
78
        self::addDirectory(realpath(__DIR__ . '/../..'), 'Magium');
79
    }
80
81
    protected function execute(InputInterface $input, OutputInterface $output)
82
    {
83
        if ($input->getArgument('directory') || $input->getArgument('namespace')) {
84
            if (!$input->getArgument('directory') || !$input->getArgument('namespace')) {
85
                throw new NotFoundException('Missing either the directory or namespace argument.  If one is used, then both are required');
86
            }
87
        }
88
89
        $paths = [];
90
        if ($input->getArgument('directory') || $input->getArgument('namespace')) {
91
            $paths = $this->traverseDirectory(realpath($input->getArgument('directory')), $input->getArgument('namespace'));
92
        } else {
93
            foreach (self::$dirs as $dir => $namespace) {
94
                $result = $this->traverseDirectory($dir, $namespace);
95
                $paths = array_merge($paths, $result);
96
            }
97
        }
98
99
        sort($paths);
100
        $filter = $input->getArgument('filter');
101
        if (count($paths) > 0 ) {
102
            $output->writeln('Classes found: ');
103
            $escape = $input->getOption('escape');
104
105
            foreach ($paths as $path) {
106
                if ($escape) {
107
                    $path = str_replace('\\', '\\\\', $path);
108
                }
109
                if ($filter && stripos($path, $filter) !== false) {
110
                    $output->writeln("\t" . $path);
111
                }
112
            }
113
        } else {
114
            $output->writeln('No classes found.  If you were expecting to find some you might need to escape your namespace separators');
115
            $output->writeln('e.g.  Namespace\Class should be written as Namespace\\\\Class');
116
        }
117
    }
118
119
    /**
120
     * @param $dir
121
     * @param $namespace
122
     * @return array
123
     */
124
125
    protected function traverseDirectory($dir, $namespace)
126
    {
127
        $classes = [];
128
        $dirIterator = new \RecursiveDirectoryIterator($dir);
129
        $iterator = new \RecursiveIteratorIterator($dirIterator);
130
        $phpFiles = new \RegexIterator($iterator, '/.*\.php$/', \RegexIterator::GET_MATCH);
131
        foreach ($phpFiles as $file) {
132
            if (is_array($file)) {
133
                $file = array_shift($file);
134
            }
135
            if (strpos($file, $dir) === 0) {
136
                $eCls = explode('\\', $namespace);
137
                $cls = substr($file, strlen($dir), -4);
138
                $matches = null;
139
                preg_match_all('/(\w*)/', $cls, $matches);
140
                if ($matches) {
141
                    foreach ($matches[0] as $match) {
142
                        if ($match) {
143
                            $eCls[] = $match;
144
                        }
145
                    }
146
                    $class = implode('\\', $eCls);
147
                    if (class_exists($class) && is_subclass_of($class, 'Magium\AbstractConfigurableElement')) {
148
                        $classes [] = $class;
149
                    }
150
                }
151
152
            }
153
        }
154
        return $classes;
155
    }
156
    
157
}