Chris@0
|
1 <?php
|
Chris@0
|
2 namespace Consolidation\AnnotatedCommand;
|
Chris@0
|
3
|
Chris@0
|
4 use Consolidation\AnnotatedCommand\Cache\CacheWrapper;
|
Chris@0
|
5 use Consolidation\AnnotatedCommand\Cache\NullCache;
|
Chris@0
|
6 use Consolidation\AnnotatedCommand\Cache\SimpleCacheInterface;
|
Chris@0
|
7 use Consolidation\AnnotatedCommand\Hooks\HookManager;
|
Chris@0
|
8 use Consolidation\AnnotatedCommand\Options\AutomaticOptionsProviderInterface;
|
Chris@0
|
9 use Consolidation\AnnotatedCommand\Parser\CommandInfo;
|
Chris@0
|
10 use Consolidation\AnnotatedCommand\Parser\CommandInfoDeserializer;
|
Chris@0
|
11 use Consolidation\AnnotatedCommand\Parser\CommandInfoSerializer;
|
Chris@0
|
12 use Consolidation\OutputFormatters\Options\FormatterOptions;
|
Chris@0
|
13 use Symfony\Component\Console\Command\Command;
|
Chris@0
|
14 use Symfony\Component\Console\Input\InputInterface;
|
Chris@0
|
15 use Symfony\Component\Console\Output\OutputInterface;
|
Chris@0
|
16
|
Chris@0
|
17 /**
|
Chris@0
|
18 * The AnnotatedCommandFactory creates commands for your application.
|
Chris@0
|
19 * Use with a Dependency Injection Container and the CommandFactory.
|
Chris@0
|
20 * Alternately, use the CommandFileDiscovery to find commandfiles, and
|
Chris@0
|
21 * then use AnnotatedCommandFactory::createCommandsFromClass() to create
|
Chris@0
|
22 * commands. See the README for more information.
|
Chris@0
|
23 *
|
Chris@0
|
24 * @package Consolidation\AnnotatedCommand
|
Chris@0
|
25 */
|
Chris@0
|
26 class AnnotatedCommandFactory implements AutomaticOptionsProviderInterface
|
Chris@0
|
27 {
|
Chris@0
|
28 /** var CommandProcessor */
|
Chris@0
|
29 protected $commandProcessor;
|
Chris@0
|
30
|
Chris@0
|
31 /** var CommandCreationListenerInterface[] */
|
Chris@0
|
32 protected $listeners = [];
|
Chris@0
|
33
|
Chris@0
|
34 /** var AutomaticOptionsProvider[] */
|
Chris@0
|
35 protected $automaticOptionsProviderList = [];
|
Chris@0
|
36
|
Chris@0
|
37 /** var boolean */
|
Chris@0
|
38 protected $includeAllPublicMethods = true;
|
Chris@0
|
39
|
Chris@0
|
40 /** var CommandInfoAltererInterface */
|
Chris@0
|
41 protected $commandInfoAlterers = [];
|
Chris@0
|
42
|
Chris@0
|
43 /** var SimpleCacheInterface */
|
Chris@0
|
44 protected $dataStore;
|
Chris@0
|
45
|
Chris@0
|
46 public function __construct()
|
Chris@0
|
47 {
|
Chris@0
|
48 $this->dataStore = new NullCache();
|
Chris@0
|
49 $this->commandProcessor = new CommandProcessor(new HookManager());
|
Chris@0
|
50 $this->addAutomaticOptionProvider($this);
|
Chris@0
|
51 }
|
Chris@0
|
52
|
Chris@0
|
53 public function setCommandProcessor(CommandProcessor $commandProcessor)
|
Chris@0
|
54 {
|
Chris@0
|
55 $this->commandProcessor = $commandProcessor;
|
Chris@0
|
56 return $this;
|
Chris@0
|
57 }
|
Chris@0
|
58
|
Chris@0
|
59 /**
|
Chris@0
|
60 * @return CommandProcessor
|
Chris@0
|
61 */
|
Chris@0
|
62 public function commandProcessor()
|
Chris@0
|
63 {
|
Chris@0
|
64 return $this->commandProcessor;
|
Chris@0
|
65 }
|
Chris@0
|
66
|
Chris@0
|
67 /**
|
Chris@0
|
68 * Set the 'include all public methods flag'. If true (the default), then
|
Chris@0
|
69 * every public method of each commandFile will be used to create commands.
|
Chris@0
|
70 * If it is false, then only those public methods annotated with @command
|
Chris@0
|
71 * or @name (deprecated) will be used to create commands.
|
Chris@0
|
72 */
|
Chris@0
|
73 public function setIncludeAllPublicMethods($includeAllPublicMethods)
|
Chris@0
|
74 {
|
Chris@0
|
75 $this->includeAllPublicMethods = $includeAllPublicMethods;
|
Chris@0
|
76 return $this;
|
Chris@0
|
77 }
|
Chris@0
|
78
|
Chris@0
|
79 public function getIncludeAllPublicMethods()
|
Chris@0
|
80 {
|
Chris@0
|
81 return $this->includeAllPublicMethods;
|
Chris@0
|
82 }
|
Chris@0
|
83
|
Chris@0
|
84 /**
|
Chris@0
|
85 * @return HookManager
|
Chris@0
|
86 */
|
Chris@0
|
87 public function hookManager()
|
Chris@0
|
88 {
|
Chris@0
|
89 return $this->commandProcessor()->hookManager();
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 /**
|
Chris@0
|
93 * Add a listener that is notified immediately before the command
|
Chris@0
|
94 * factory creates commands from a commandFile instance. This
|
Chris@0
|
95 * listener can use this opportunity to do more setup for the commandFile,
|
Chris@0
|
96 * and so on.
|
Chris@0
|
97 *
|
Chris@0
|
98 * @param CommandCreationListenerInterface $listener
|
Chris@0
|
99 */
|
Chris@0
|
100 public function addListener(CommandCreationListenerInterface $listener)
|
Chris@0
|
101 {
|
Chris@0
|
102 $this->listeners[] = $listener;
|
Chris@0
|
103 return $this;
|
Chris@0
|
104 }
|
Chris@0
|
105
|
Chris@0
|
106 /**
|
Chris@0
|
107 * Add a listener that's just a simple 'callable'.
|
Chris@0
|
108 * @param callable $listener
|
Chris@0
|
109 */
|
Chris@0
|
110 public function addListernerCallback(callable $listener)
|
Chris@0
|
111 {
|
Chris@0
|
112 $this->addListener(new CommandCreationListener($listener));
|
Chris@0
|
113 return $this;
|
Chris@0
|
114 }
|
Chris@0
|
115
|
Chris@0
|
116 /**
|
Chris@0
|
117 * Call all command creation listeners
|
Chris@0
|
118 *
|
Chris@0
|
119 * @param object $commandFileInstance
|
Chris@0
|
120 */
|
Chris@0
|
121 protected function notify($commandFileInstance)
|
Chris@0
|
122 {
|
Chris@0
|
123 foreach ($this->listeners as $listener) {
|
Chris@0
|
124 $listener->notifyCommandFileAdded($commandFileInstance);
|
Chris@0
|
125 }
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 public function addAutomaticOptionProvider(AutomaticOptionsProviderInterface $optionsProvider)
|
Chris@0
|
129 {
|
Chris@0
|
130 $this->automaticOptionsProviderList[] = $optionsProvider;
|
Chris@0
|
131 }
|
Chris@0
|
132
|
Chris@0
|
133 public function addCommandInfoAlterer(CommandInfoAltererInterface $alterer)
|
Chris@0
|
134 {
|
Chris@0
|
135 $this->commandInfoAlterers[] = $alterer;
|
Chris@0
|
136 }
|
Chris@0
|
137
|
Chris@0
|
138 /**
|
Chris@0
|
139 * n.b. This registers all hooks from the commandfile instance as a side-effect.
|
Chris@0
|
140 */
|
Chris@0
|
141 public function createCommandsFromClass($commandFileInstance, $includeAllPublicMethods = null)
|
Chris@0
|
142 {
|
Chris@0
|
143 // Deprecated: avoid using the $includeAllPublicMethods in favor of the setIncludeAllPublicMethods() accessor.
|
Chris@0
|
144 if (!isset($includeAllPublicMethods)) {
|
Chris@0
|
145 $includeAllPublicMethods = $this->getIncludeAllPublicMethods();
|
Chris@0
|
146 }
|
Chris@0
|
147 $this->notify($commandFileInstance);
|
Chris@0
|
148 $commandInfoList = $this->getCommandInfoListFromClass($commandFileInstance);
|
Chris@0
|
149 $this->registerCommandHooksFromClassInfo($commandInfoList, $commandFileInstance);
|
Chris@0
|
150 return $this->createCommandsFromClassInfo($commandInfoList, $commandFileInstance, $includeAllPublicMethods);
|
Chris@0
|
151 }
|
Chris@0
|
152
|
Chris@0
|
153 public function getCommandInfoListFromClass($commandFileInstance)
|
Chris@0
|
154 {
|
Chris@0
|
155 $cachedCommandInfoList = $this->getCommandInfoListFromCache($commandFileInstance);
|
Chris@0
|
156 $commandInfoList = $this->createCommandInfoListFromClass($commandFileInstance, $cachedCommandInfoList);
|
Chris@0
|
157 if (!empty($commandInfoList)) {
|
Chris@0
|
158 $cachedCommandInfoList = array_merge($commandInfoList, $cachedCommandInfoList);
|
Chris@0
|
159 $this->storeCommandInfoListInCache($commandFileInstance, $cachedCommandInfoList);
|
Chris@0
|
160 }
|
Chris@0
|
161 return $cachedCommandInfoList;
|
Chris@0
|
162 }
|
Chris@0
|
163
|
Chris@0
|
164 protected function storeCommandInfoListInCache($commandFileInstance, $commandInfoList)
|
Chris@0
|
165 {
|
Chris@0
|
166 if (!$this->hasDataStore()) {
|
Chris@0
|
167 return;
|
Chris@0
|
168 }
|
Chris@0
|
169 $cache_data = [];
|
Chris@0
|
170 $serializer = new CommandInfoSerializer();
|
Chris@0
|
171 foreach ($commandInfoList as $i => $commandInfo) {
|
Chris@0
|
172 $cache_data[$i] = $serializer->serialize($commandInfo);
|
Chris@0
|
173 }
|
Chris@0
|
174 $className = get_class($commandFileInstance);
|
Chris@0
|
175 $this->getDataStore()->set($className, $cache_data);
|
Chris@0
|
176 }
|
Chris@0
|
177
|
Chris@0
|
178 /**
|
Chris@0
|
179 * Get the command info list from the cache
|
Chris@0
|
180 *
|
Chris@0
|
181 * @param mixed $commandFileInstance
|
Chris@0
|
182 * @return array
|
Chris@0
|
183 */
|
Chris@0
|
184 protected function getCommandInfoListFromCache($commandFileInstance)
|
Chris@0
|
185 {
|
Chris@0
|
186 $commandInfoList = [];
|
Chris@17
|
187 if (!is_object($commandFileInstance)) {
|
Chris@17
|
188 return [];
|
Chris@17
|
189 }
|
Chris@0
|
190 $className = get_class($commandFileInstance);
|
Chris@0
|
191 if (!$this->getDataStore()->has($className)) {
|
Chris@0
|
192 return [];
|
Chris@0
|
193 }
|
Chris@0
|
194 $deserializer = new CommandInfoDeserializer();
|
Chris@0
|
195
|
Chris@0
|
196 $cache_data = $this->getDataStore()->get($className);
|
Chris@0
|
197 foreach ($cache_data as $i => $data) {
|
Chris@0
|
198 if (CommandInfoDeserializer::isValidSerializedData((array)$data)) {
|
Chris@0
|
199 $commandInfoList[$i] = $deserializer->deserialize((array)$data);
|
Chris@0
|
200 }
|
Chris@0
|
201 }
|
Chris@0
|
202 return $commandInfoList;
|
Chris@0
|
203 }
|
Chris@0
|
204
|
Chris@0
|
205 /**
|
Chris@0
|
206 * Check to see if this factory has a cache datastore.
|
Chris@0
|
207 * @return boolean
|
Chris@0
|
208 */
|
Chris@0
|
209 public function hasDataStore()
|
Chris@0
|
210 {
|
Chris@0
|
211 return !($this->dataStore instanceof NullCache);
|
Chris@0
|
212 }
|
Chris@0
|
213
|
Chris@0
|
214 /**
|
Chris@0
|
215 * Set a cache datastore for this factory. Any object with 'set' and
|
Chris@0
|
216 * 'get' methods is acceptable. The key is the classname being cached,
|
Chris@0
|
217 * and the value is a nested associative array of strings.
|
Chris@0
|
218 *
|
Chris@0
|
219 * TODO: Typehint this to SimpleCacheInterface
|
Chris@0
|
220 *
|
Chris@0
|
221 * This is not done currently to allow clients to use a generic cache
|
Chris@0
|
222 * store that does not itself depend on the annotated-command library.
|
Chris@0
|
223 *
|
Chris@0
|
224 * @param Mixed $dataStore
|
Chris@0
|
225 * @return type
|
Chris@0
|
226 */
|
Chris@0
|
227 public function setDataStore($dataStore)
|
Chris@0
|
228 {
|
Chris@0
|
229 if (!($dataStore instanceof SimpleCacheInterface)) {
|
Chris@0
|
230 $dataStore = new CacheWrapper($dataStore);
|
Chris@0
|
231 }
|
Chris@0
|
232 $this->dataStore = $dataStore;
|
Chris@0
|
233 return $this;
|
Chris@0
|
234 }
|
Chris@0
|
235
|
Chris@0
|
236 /**
|
Chris@0
|
237 * Get the data store attached to this factory.
|
Chris@0
|
238 */
|
Chris@0
|
239 public function getDataStore()
|
Chris@0
|
240 {
|
Chris@0
|
241 return $this->dataStore;
|
Chris@0
|
242 }
|
Chris@0
|
243
|
Chris@0
|
244 protected function createCommandInfoListFromClass($classNameOrInstance, $cachedCommandInfoList)
|
Chris@0
|
245 {
|
Chris@0
|
246 $commandInfoList = [];
|
Chris@0
|
247
|
Chris@0
|
248 // Ignore special functions, such as __construct and __call, which
|
Chris@0
|
249 // can never be commands.
|
Chris@0
|
250 $commandMethodNames = array_filter(
|
Chris@0
|
251 get_class_methods($classNameOrInstance) ?: [],
|
Chris@0
|
252 function ($m) use ($classNameOrInstance) {
|
Chris@0
|
253 $reflectionMethod = new \ReflectionMethod($classNameOrInstance, $m);
|
Chris@0
|
254 return !$reflectionMethod->isStatic() && !preg_match('#^_#', $m);
|
Chris@0
|
255 }
|
Chris@0
|
256 );
|
Chris@0
|
257
|
Chris@0
|
258 foreach ($commandMethodNames as $commandMethodName) {
|
Chris@0
|
259 if (!array_key_exists($commandMethodName, $cachedCommandInfoList)) {
|
Chris@0
|
260 $commandInfo = CommandInfo::create($classNameOrInstance, $commandMethodName);
|
Chris@0
|
261 if (!static::isCommandOrHookMethod($commandInfo, $this->getIncludeAllPublicMethods())) {
|
Chris@0
|
262 $commandInfo->invalidate();
|
Chris@0
|
263 }
|
Chris@0
|
264 $commandInfoList[$commandMethodName] = $commandInfo;
|
Chris@0
|
265 }
|
Chris@0
|
266 }
|
Chris@0
|
267
|
Chris@0
|
268 return $commandInfoList;
|
Chris@0
|
269 }
|
Chris@0
|
270
|
Chris@0
|
271 public function createCommandInfo($classNameOrInstance, $commandMethodName)
|
Chris@0
|
272 {
|
Chris@0
|
273 return CommandInfo::create($classNameOrInstance, $commandMethodName);
|
Chris@0
|
274 }
|
Chris@0
|
275
|
Chris@0
|
276 public function createCommandsFromClassInfo($commandInfoList, $commandFileInstance, $includeAllPublicMethods = null)
|
Chris@0
|
277 {
|
Chris@0
|
278 // Deprecated: avoid using the $includeAllPublicMethods in favor of the setIncludeAllPublicMethods() accessor.
|
Chris@0
|
279 if (!isset($includeAllPublicMethods)) {
|
Chris@0
|
280 $includeAllPublicMethods = $this->getIncludeAllPublicMethods();
|
Chris@0
|
281 }
|
Chris@0
|
282 return $this->createSelectedCommandsFromClassInfo(
|
Chris@0
|
283 $commandInfoList,
|
Chris@0
|
284 $commandFileInstance,
|
Chris@0
|
285 function ($commandInfo) use ($includeAllPublicMethods) {
|
Chris@0
|
286 return static::isCommandMethod($commandInfo, $includeAllPublicMethods);
|
Chris@0
|
287 }
|
Chris@0
|
288 );
|
Chris@0
|
289 }
|
Chris@0
|
290
|
Chris@0
|
291 public function createSelectedCommandsFromClassInfo($commandInfoList, $commandFileInstance, callable $commandSelector)
|
Chris@0
|
292 {
|
Chris@0
|
293 $commandInfoList = $this->filterCommandInfoList($commandInfoList, $commandSelector);
|
Chris@0
|
294 return array_map(
|
Chris@0
|
295 function ($commandInfo) use ($commandFileInstance) {
|
Chris@0
|
296 return $this->createCommand($commandInfo, $commandFileInstance);
|
Chris@0
|
297 },
|
Chris@0
|
298 $commandInfoList
|
Chris@0
|
299 );
|
Chris@0
|
300 }
|
Chris@0
|
301
|
Chris@0
|
302 protected function filterCommandInfoList($commandInfoList, callable $commandSelector)
|
Chris@0
|
303 {
|
Chris@0
|
304 return array_filter($commandInfoList, $commandSelector);
|
Chris@0
|
305 }
|
Chris@0
|
306
|
Chris@0
|
307 public static function isCommandOrHookMethod($commandInfo, $includeAllPublicMethods)
|
Chris@0
|
308 {
|
Chris@0
|
309 return static::isHookMethod($commandInfo) || static::isCommandMethod($commandInfo, $includeAllPublicMethods);
|
Chris@0
|
310 }
|
Chris@0
|
311
|
Chris@0
|
312 public static function isHookMethod($commandInfo)
|
Chris@0
|
313 {
|
Chris@0
|
314 return $commandInfo->hasAnnotation('hook');
|
Chris@0
|
315 }
|
Chris@0
|
316
|
Chris@0
|
317 public static function isCommandMethod($commandInfo, $includeAllPublicMethods)
|
Chris@0
|
318 {
|
Chris@0
|
319 // Ignore everything labeled @hook
|
Chris@0
|
320 if (static::isHookMethod($commandInfo)) {
|
Chris@0
|
321 return false;
|
Chris@0
|
322 }
|
Chris@0
|
323 // Include everything labeled @command
|
Chris@0
|
324 if ($commandInfo->hasAnnotation('command')) {
|
Chris@0
|
325 return true;
|
Chris@0
|
326 }
|
Chris@0
|
327 // Skip anything that has a missing or invalid name.
|
Chris@0
|
328 $commandName = $commandInfo->getName();
|
Chris@0
|
329 if (empty($commandName) || preg_match('#[^a-zA-Z0-9:_-]#', $commandName)) {
|
Chris@0
|
330 return false;
|
Chris@0
|
331 }
|
Chris@0
|
332 // Skip anything named like an accessor ('get' or 'set')
|
Chris@0
|
333 if (preg_match('#^(get[A-Z]|set[A-Z])#', $commandInfo->getMethodName())) {
|
Chris@0
|
334 return false;
|
Chris@0
|
335 }
|
Chris@0
|
336
|
Chris@0
|
337 // Default to the setting of 'include all public methods'.
|
Chris@0
|
338 return $includeAllPublicMethods;
|
Chris@0
|
339 }
|
Chris@0
|
340
|
Chris@0
|
341 public function registerCommandHooksFromClassInfo($commandInfoList, $commandFileInstance)
|
Chris@0
|
342 {
|
Chris@0
|
343 foreach ($commandInfoList as $commandInfo) {
|
Chris@0
|
344 if (static::isHookMethod($commandInfo)) {
|
Chris@0
|
345 $this->registerCommandHook($commandInfo, $commandFileInstance);
|
Chris@0
|
346 }
|
Chris@0
|
347 }
|
Chris@0
|
348 }
|
Chris@0
|
349
|
Chris@0
|
350 /**
|
Chris@0
|
351 * Register a command hook given the CommandInfo for a method.
|
Chris@0
|
352 *
|
Chris@0
|
353 * The hook format is:
|
Chris@0
|
354 *
|
Chris@0
|
355 * @hook type name type
|
Chris@0
|
356 *
|
Chris@0
|
357 * For example, the pre-validate hook for the core:init command is:
|
Chris@0
|
358 *
|
Chris@0
|
359 * @hook pre-validate core:init
|
Chris@0
|
360 *
|
Chris@0
|
361 * If no command name is provided, then this hook will affect every
|
Chris@0
|
362 * command that is defined in the same file.
|
Chris@0
|
363 *
|
Chris@0
|
364 * If no hook is provided, then we will presume that ALTER_RESULT
|
Chris@0
|
365 * is intended.
|
Chris@0
|
366 *
|
Chris@0
|
367 * @param CommandInfo $commandInfo Information about the command hook method.
|
Chris@0
|
368 * @param object $commandFileInstance An instance of the CommandFile class.
|
Chris@0
|
369 */
|
Chris@0
|
370 public function registerCommandHook(CommandInfo $commandInfo, $commandFileInstance)
|
Chris@0
|
371 {
|
Chris@0
|
372 // Ignore if the command info has no @hook
|
Chris@0
|
373 if (!static::isHookMethod($commandInfo)) {
|
Chris@0
|
374 return;
|
Chris@0
|
375 }
|
Chris@0
|
376 $hookData = $commandInfo->getAnnotation('hook');
|
Chris@0
|
377 $hook = $this->getNthWord($hookData, 0, HookManager::ALTER_RESULT);
|
Chris@0
|
378 $commandName = $this->getNthWord($hookData, 1);
|
Chris@0
|
379
|
Chris@0
|
380 // Register the hook
|
Chris@0
|
381 $callback = [$commandFileInstance, $commandInfo->getMethodName()];
|
Chris@0
|
382 $this->commandProcessor()->hookManager()->add($callback, $hook, $commandName);
|
Chris@0
|
383
|
Chris@0
|
384 // If the hook has options, then also register the commandInfo
|
Chris@0
|
385 // with the hook manager, so that we can add options and such to
|
Chris@0
|
386 // the commands they hook.
|
Chris@0
|
387 if (!$commandInfo->options()->isEmpty()) {
|
Chris@0
|
388 $this->commandProcessor()->hookManager()->recordHookOptions($commandInfo, $commandName);
|
Chris@0
|
389 }
|
Chris@0
|
390 }
|
Chris@0
|
391
|
Chris@0
|
392 protected function getNthWord($string, $n, $default = '', $delimiter = ' ')
|
Chris@0
|
393 {
|
Chris@0
|
394 $words = explode($delimiter, $string);
|
Chris@0
|
395 if (!empty($words[$n])) {
|
Chris@0
|
396 return $words[$n];
|
Chris@0
|
397 }
|
Chris@0
|
398 return $default;
|
Chris@0
|
399 }
|
Chris@0
|
400
|
Chris@0
|
401 public function createCommand(CommandInfo $commandInfo, $commandFileInstance)
|
Chris@0
|
402 {
|
Chris@0
|
403 $this->alterCommandInfo($commandInfo, $commandFileInstance);
|
Chris@0
|
404 $command = new AnnotatedCommand($commandInfo->getName());
|
Chris@0
|
405 $commandCallback = [$commandFileInstance, $commandInfo->getMethodName()];
|
Chris@0
|
406 $command->setCommandCallback($commandCallback);
|
Chris@0
|
407 $command->setCommandProcessor($this->commandProcessor);
|
Chris@0
|
408 $command->setCommandInfo($commandInfo);
|
Chris@0
|
409 $automaticOptions = $this->callAutomaticOptionsProviders($commandInfo);
|
Chris@0
|
410 $command->setCommandOptions($commandInfo, $automaticOptions);
|
Chris@0
|
411 // Annotation commands are never bootstrap-aware, but for completeness
|
Chris@0
|
412 // we will notify on every created command, as some clients may wish to
|
Chris@0
|
413 // use this notification for some other purpose.
|
Chris@0
|
414 $this->notify($command);
|
Chris@0
|
415 return $command;
|
Chris@0
|
416 }
|
Chris@0
|
417
|
Chris@0
|
418 /**
|
Chris@0
|
419 * Give plugins an opportunity to update the commandInfo
|
Chris@0
|
420 */
|
Chris@0
|
421 public function alterCommandInfo(CommandInfo $commandInfo, $commandFileInstance)
|
Chris@0
|
422 {
|
Chris@0
|
423 foreach ($this->commandInfoAlterers as $alterer) {
|
Chris@0
|
424 $alterer->alterCommandInfo($commandInfo, $commandFileInstance);
|
Chris@0
|
425 }
|
Chris@0
|
426 }
|
Chris@0
|
427
|
Chris@0
|
428 /**
|
Chris@0
|
429 * Get the options that are implied by annotations, e.g. @fields implies
|
Chris@0
|
430 * that there should be a --fields and a --format option.
|
Chris@0
|
431 *
|
Chris@0
|
432 * @return InputOption[]
|
Chris@0
|
433 */
|
Chris@0
|
434 public function callAutomaticOptionsProviders(CommandInfo $commandInfo)
|
Chris@0
|
435 {
|
Chris@0
|
436 $automaticOptions = [];
|
Chris@0
|
437 foreach ($this->automaticOptionsProviderList as $automaticOptionsProvider) {
|
Chris@0
|
438 $automaticOptions += $automaticOptionsProvider->automaticOptions($commandInfo);
|
Chris@0
|
439 }
|
Chris@0
|
440 return $automaticOptions;
|
Chris@0
|
441 }
|
Chris@0
|
442
|
Chris@0
|
443 /**
|
Chris@0
|
444 * Get the options that are implied by annotations, e.g. @fields implies
|
Chris@0
|
445 * that there should be a --fields and a --format option.
|
Chris@0
|
446 *
|
Chris@0
|
447 * @return InputOption[]
|
Chris@0
|
448 */
|
Chris@0
|
449 public function automaticOptions(CommandInfo $commandInfo)
|
Chris@0
|
450 {
|
Chris@0
|
451 $automaticOptions = [];
|
Chris@0
|
452 $formatManager = $this->commandProcessor()->formatterManager();
|
Chris@0
|
453 if ($formatManager) {
|
Chris@0
|
454 $annotationData = $commandInfo->getAnnotations()->getArrayCopy();
|
Chris@0
|
455 $formatterOptions = new FormatterOptions($annotationData);
|
Chris@0
|
456 $dataType = $commandInfo->getReturnType();
|
Chris@0
|
457 $automaticOptions = $formatManager->automaticOptions($formatterOptions, $dataType);
|
Chris@0
|
458 }
|
Chris@0
|
459 return $automaticOptions;
|
Chris@0
|
460 }
|
Chris@0
|
461 }
|