|
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
|
|
|
} |