Chris@0
|
1 <?php
|
Chris@0
|
2 namespace Consolidation\AnnotatedCommand;
|
Chris@0
|
3
|
Chris@0
|
4 use Consolidation\AnnotatedCommand\Hooks\HookManager;
|
Chris@0
|
5 use Consolidation\AnnotatedCommand\Parser\CommandInfo;
|
Chris@0
|
6 use Consolidation\AnnotatedCommand\Help\HelpDocumentAlter;
|
Chris@0
|
7 use Symfony\Component\Console\Command\Command;
|
Chris@0
|
8 use Symfony\Component\Console\Input\InputArgument;
|
Chris@0
|
9 use Symfony\Component\Console\Input\InputInterface;
|
Chris@0
|
10 use Symfony\Component\Console\Input\InputOption;
|
Chris@0
|
11 use Symfony\Component\Console\Output\OutputInterface;
|
Chris@0
|
12
|
Chris@0
|
13 /**
|
Chris@0
|
14 * AnnotatedCommands are created automatically by the
|
Chris@0
|
15 * AnnotatedCommandFactory. Each command method in a
|
Chris@0
|
16 * command file will produce one AnnotatedCommand. These
|
Chris@0
|
17 * are then added to your Symfony Console Application object;
|
Chris@0
|
18 * nothing else is needed.
|
Chris@0
|
19 *
|
Chris@0
|
20 * Optionally, though, you may extend AnnotatedCommand directly
|
Chris@0
|
21 * to make a single command. The usage pattern is the same
|
Chris@0
|
22 * as for any other Symfony Console command, except that you may
|
Chris@0
|
23 * omit the 'Confiure' method, and instead place your annotations
|
Chris@0
|
24 * on the execute() method.
|
Chris@0
|
25 *
|
Chris@0
|
26 * @package Consolidation\AnnotatedCommand
|
Chris@0
|
27 */
|
Chris@0
|
28 class AnnotatedCommand extends Command implements HelpDocumentAlter
|
Chris@0
|
29 {
|
Chris@0
|
30 protected $commandCallback;
|
Chris@0
|
31 protected $commandProcessor;
|
Chris@0
|
32 protected $annotationData;
|
Chris@0
|
33 protected $examples = [];
|
Chris@0
|
34 protected $topics = [];
|
Chris@0
|
35 protected $usesInputInterface;
|
Chris@0
|
36 protected $usesOutputInterface;
|
Chris@0
|
37 protected $returnType;
|
Chris@0
|
38
|
Chris@0
|
39 public function __construct($name = null)
|
Chris@0
|
40 {
|
Chris@0
|
41 $commandInfo = false;
|
Chris@0
|
42
|
Chris@0
|
43 // If this is a subclass of AnnotatedCommand, check to see
|
Chris@0
|
44 // if the 'execute' method is annotated. We could do this
|
Chris@0
|
45 // unconditionally; it is a performance optimization to skip
|
Chris@0
|
46 // checking the annotations if $this is an instance of
|
Chris@0
|
47 // AnnotatedCommand. Alternately, we break out a new subclass.
|
Chris@0
|
48 // The command factory instantiates the subclass.
|
Chris@0
|
49 if (get_class($this) != 'Consolidation\AnnotatedCommand\AnnotatedCommand') {
|
Chris@0
|
50 $commandInfo = CommandInfo::create($this, 'execute');
|
Chris@0
|
51 if (!isset($name)) {
|
Chris@0
|
52 $name = $commandInfo->getName();
|
Chris@0
|
53 }
|
Chris@0
|
54 }
|
Chris@0
|
55 parent::__construct($name);
|
Chris@0
|
56 if ($commandInfo && $commandInfo->hasAnnotation('command')) {
|
Chris@0
|
57 $this->setCommandInfo($commandInfo);
|
Chris@0
|
58 $this->setCommandOptions($commandInfo);
|
Chris@0
|
59 }
|
Chris@0
|
60 }
|
Chris@0
|
61
|
Chris@0
|
62 public function setCommandCallback($commandCallback)
|
Chris@0
|
63 {
|
Chris@0
|
64 $this->commandCallback = $commandCallback;
|
Chris@0
|
65 return $this;
|
Chris@0
|
66 }
|
Chris@0
|
67
|
Chris@0
|
68 public function setCommandProcessor($commandProcessor)
|
Chris@0
|
69 {
|
Chris@0
|
70 $this->commandProcessor = $commandProcessor;
|
Chris@0
|
71 return $this;
|
Chris@0
|
72 }
|
Chris@0
|
73
|
Chris@0
|
74 public function commandProcessor()
|
Chris@0
|
75 {
|
Chris@0
|
76 // If someone is using an AnnotatedCommand, and is NOT getting
|
Chris@0
|
77 // it from an AnnotatedCommandFactory OR not correctly injecting
|
Chris@0
|
78 // a command processor via setCommandProcessor() (ideally via the
|
Chris@0
|
79 // DI container), then we'll just give each annotated command its
|
Chris@0
|
80 // own command processor. This is not ideal; preferably, there would
|
Chris@0
|
81 // only be one instance of the command processor in the application.
|
Chris@0
|
82 if (!isset($this->commandProcessor)) {
|
Chris@0
|
83 $this->commandProcessor = new CommandProcessor(new HookManager());
|
Chris@0
|
84 }
|
Chris@0
|
85 return $this->commandProcessor;
|
Chris@0
|
86 }
|
Chris@0
|
87
|
Chris@0
|
88 public function getReturnType()
|
Chris@0
|
89 {
|
Chris@0
|
90 return $this->returnType;
|
Chris@0
|
91 }
|
Chris@0
|
92
|
Chris@0
|
93 public function setReturnType($returnType)
|
Chris@0
|
94 {
|
Chris@0
|
95 $this->returnType = $returnType;
|
Chris@0
|
96 return $this;
|
Chris@0
|
97 }
|
Chris@0
|
98
|
Chris@0
|
99 public function getAnnotationData()
|
Chris@0
|
100 {
|
Chris@0
|
101 return $this->annotationData;
|
Chris@0
|
102 }
|
Chris@0
|
103
|
Chris@0
|
104 public function setAnnotationData($annotationData)
|
Chris@0
|
105 {
|
Chris@0
|
106 $this->annotationData = $annotationData;
|
Chris@0
|
107 return $this;
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@0
|
110 public function getTopics()
|
Chris@0
|
111 {
|
Chris@0
|
112 return $this->topics;
|
Chris@0
|
113 }
|
Chris@0
|
114
|
Chris@0
|
115 public function setTopics($topics)
|
Chris@0
|
116 {
|
Chris@0
|
117 $this->topics = $topics;
|
Chris@0
|
118 return $this;
|
Chris@0
|
119 }
|
Chris@0
|
120
|
Chris@0
|
121 public function setCommandInfo($commandInfo)
|
Chris@0
|
122 {
|
Chris@0
|
123 $this->setDescription($commandInfo->getDescription());
|
Chris@0
|
124 $this->setHelp($commandInfo->getHelp());
|
Chris@0
|
125 $this->setAliases($commandInfo->getAliases());
|
Chris@0
|
126 $this->setAnnotationData($commandInfo->getAnnotations());
|
Chris@0
|
127 $this->setTopics($commandInfo->getTopics());
|
Chris@0
|
128 foreach ($commandInfo->getExampleUsages() as $usage => $description) {
|
Chris@0
|
129 $this->addUsageOrExample($usage, $description);
|
Chris@0
|
130 }
|
Chris@0
|
131 $this->setCommandArguments($commandInfo);
|
Chris@0
|
132 $this->setReturnType($commandInfo->getReturnType());
|
Chris@0
|
133 // Hidden commands available since Symfony 3.2
|
Chris@0
|
134 // http://symfony.com/doc/current/console/hide_commands.html
|
Chris@0
|
135 if (method_exists($this, 'setHidden')) {
|
Chris@0
|
136 $this->setHidden($commandInfo->getHidden());
|
Chris@0
|
137 }
|
Chris@0
|
138 return $this;
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 public function getExampleUsages()
|
Chris@0
|
142 {
|
Chris@0
|
143 return $this->examples;
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@0
|
146 protected function addUsageOrExample($usage, $description)
|
Chris@0
|
147 {
|
Chris@0
|
148 $this->addUsage($usage);
|
Chris@0
|
149 if (!empty($description)) {
|
Chris@0
|
150 $this->examples[$usage] = $description;
|
Chris@0
|
151 }
|
Chris@0
|
152 }
|
Chris@0
|
153
|
Chris@0
|
154 public function helpAlter(\DomDocument $originalDom)
|
Chris@0
|
155 {
|
Chris@0
|
156 $dom = new \DOMDocument('1.0', 'UTF-8');
|
Chris@0
|
157 $dom->appendChild($commandXML = $dom->createElement('command'));
|
Chris@0
|
158 $commandXML->setAttribute('id', $this->getName());
|
Chris@0
|
159 $commandXML->setAttribute('name', $this->getName());
|
Chris@0
|
160
|
Chris@0
|
161 // Get the original <command> element and its top-level elements.
|
Chris@0
|
162 $originalCommandXML = $this->getSingleElementByTagName($dom, $originalDom, 'command');
|
Chris@0
|
163 $originalUsagesXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'usages');
|
Chris@0
|
164 $originalDescriptionXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'description');
|
Chris@0
|
165 $originalHelpXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'help');
|
Chris@0
|
166 $originalArgumentsXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'arguments');
|
Chris@0
|
167 $originalOptionsXML = $this->getSingleElementByTagName($dom, $originalCommandXML, 'options');
|
Chris@0
|
168
|
Chris@0
|
169 // Keep only the first of the <usage> elements
|
Chris@0
|
170 $newUsagesXML = $dom->createElement('usages');
|
Chris@0
|
171 $firstUsageXML = $this->getSingleElementByTagName($dom, $originalUsagesXML, 'usage');
|
Chris@0
|
172 $newUsagesXML->appendChild($firstUsageXML);
|
Chris@0
|
173
|
Chris@0
|
174 // Create our own <example> elements
|
Chris@0
|
175 $newExamplesXML = $dom->createElement('examples');
|
Chris@0
|
176 foreach ($this->examples as $usage => $description) {
|
Chris@0
|
177 $newExamplesXML->appendChild($exampleXML = $dom->createElement('example'));
|
Chris@0
|
178 $exampleXML->appendChild($usageXML = $dom->createElement('usage', $usage));
|
Chris@0
|
179 $exampleXML->appendChild($descriptionXML = $dom->createElement('description', $description));
|
Chris@0
|
180 }
|
Chris@0
|
181
|
Chris@0
|
182 // Create our own <alias> elements
|
Chris@0
|
183 $newAliasesXML = $dom->createElement('aliases');
|
Chris@0
|
184 foreach ($this->getAliases() as $alias) {
|
Chris@0
|
185 $newAliasesXML->appendChild($dom->createElement('alias', $alias));
|
Chris@0
|
186 }
|
Chris@0
|
187
|
Chris@0
|
188 // Create our own <topic> elements
|
Chris@0
|
189 $newTopicsXML = $dom->createElement('topics');
|
Chris@0
|
190 foreach ($this->getTopics() as $topic) {
|
Chris@0
|
191 $newTopicsXML->appendChild($topicXML = $dom->createElement('topic', $topic));
|
Chris@0
|
192 }
|
Chris@0
|
193
|
Chris@0
|
194 // Place the different elements into the <command> element in the desired order
|
Chris@0
|
195 $commandXML->appendChild($newUsagesXML);
|
Chris@0
|
196 $commandXML->appendChild($newExamplesXML);
|
Chris@0
|
197 $commandXML->appendChild($originalDescriptionXML);
|
Chris@0
|
198 $commandXML->appendChild($originalArgumentsXML);
|
Chris@0
|
199 $commandXML->appendChild($originalOptionsXML);
|
Chris@0
|
200 $commandXML->appendChild($originalHelpXML);
|
Chris@0
|
201 $commandXML->appendChild($newAliasesXML);
|
Chris@0
|
202 $commandXML->appendChild($newTopicsXML);
|
Chris@0
|
203
|
Chris@0
|
204 return $dom;
|
Chris@0
|
205 }
|
Chris@0
|
206
|
Chris@0
|
207 protected function getSingleElementByTagName($dom, $parent, $tagName)
|
Chris@0
|
208 {
|
Chris@0
|
209 // There should always be exactly one '<command>' element.
|
Chris@0
|
210 $elements = $parent->getElementsByTagName($tagName);
|
Chris@0
|
211 $result = $elements->item(0);
|
Chris@0
|
212
|
Chris@0
|
213 $result = $dom->importNode($result, true);
|
Chris@0
|
214
|
Chris@0
|
215 return $result;
|
Chris@0
|
216 }
|
Chris@0
|
217
|
Chris@0
|
218 protected function setCommandArguments($commandInfo)
|
Chris@0
|
219 {
|
Chris@0
|
220 $this->setUsesInputInterface($commandInfo);
|
Chris@0
|
221 $this->setUsesOutputInterface($commandInfo);
|
Chris@0
|
222 $this->setCommandArgumentsFromParameters($commandInfo);
|
Chris@0
|
223 return $this;
|
Chris@0
|
224 }
|
Chris@0
|
225
|
Chris@0
|
226 /**
|
Chris@0
|
227 * Check whether the first parameter is an InputInterface.
|
Chris@0
|
228 */
|
Chris@0
|
229 protected function checkUsesInputInterface($params)
|
Chris@0
|
230 {
|
Chris@0
|
231 /** @var \ReflectionParameter $firstParam */
|
Chris@0
|
232 $firstParam = reset($params);
|
Chris@0
|
233 return $firstParam && $firstParam->getClass() && $firstParam->getClass()->implementsInterface(
|
Chris@0
|
234 '\\Symfony\\Component\\Console\\Input\\InputInterface'
|
Chris@0
|
235 );
|
Chris@0
|
236 }
|
Chris@0
|
237
|
Chris@0
|
238 /**
|
Chris@0
|
239 * Determine whether this command wants to get its inputs
|
Chris@0
|
240 * via an InputInterface or via its command parameters
|
Chris@0
|
241 */
|
Chris@0
|
242 protected function setUsesInputInterface($commandInfo)
|
Chris@0
|
243 {
|
Chris@0
|
244 $params = $commandInfo->getParameters();
|
Chris@0
|
245 $this->usesInputInterface = $this->checkUsesInputInterface($params);
|
Chris@0
|
246 return $this;
|
Chris@0
|
247 }
|
Chris@0
|
248
|
Chris@0
|
249 /**
|
Chris@0
|
250 * Determine whether this command wants to send its output directly
|
Chris@0
|
251 * to the provided OutputInterface, or whether it will returned
|
Chris@0
|
252 * structured output to be processed by the command processor.
|
Chris@0
|
253 */
|
Chris@0
|
254 protected function setUsesOutputInterface($commandInfo)
|
Chris@0
|
255 {
|
Chris@0
|
256 $params = $commandInfo->getParameters();
|
Chris@0
|
257 $index = $this->checkUsesInputInterface($params) ? 1 : 0;
|
Chris@0
|
258 $this->usesOutputInterface =
|
Chris@0
|
259 (count($params) > $index) &&
|
Chris@0
|
260 $params[$index]->getClass() &&
|
Chris@0
|
261 $params[$index]->getClass()->implementsInterface(
|
Chris@0
|
262 '\\Symfony\\Component\\Console\\Output\\OutputInterface'
|
Chris@0
|
263 )
|
Chris@0
|
264 ;
|
Chris@0
|
265 return $this;
|
Chris@0
|
266 }
|
Chris@0
|
267
|
Chris@0
|
268 protected function setCommandArgumentsFromParameters($commandInfo)
|
Chris@0
|
269 {
|
Chris@0
|
270 $args = $commandInfo->arguments()->getValues();
|
Chris@0
|
271 foreach ($args as $name => $defaultValue) {
|
Chris@0
|
272 $description = $commandInfo->arguments()->getDescription($name);
|
Chris@0
|
273 $hasDefault = $commandInfo->arguments()->hasDefault($name);
|
Chris@0
|
274 $parameterMode = $this->getCommandArgumentMode($hasDefault, $defaultValue);
|
Chris@0
|
275 $this->addArgument($name, $parameterMode, $description, $defaultValue);
|
Chris@0
|
276 }
|
Chris@0
|
277 return $this;
|
Chris@0
|
278 }
|
Chris@0
|
279
|
Chris@0
|
280 protected function getCommandArgumentMode($hasDefault, $defaultValue)
|
Chris@0
|
281 {
|
Chris@0
|
282 if (!$hasDefault) {
|
Chris@0
|
283 return InputArgument::REQUIRED;
|
Chris@0
|
284 }
|
Chris@0
|
285 if (is_array($defaultValue)) {
|
Chris@0
|
286 return InputArgument::IS_ARRAY;
|
Chris@0
|
287 }
|
Chris@0
|
288 return InputArgument::OPTIONAL;
|
Chris@0
|
289 }
|
Chris@0
|
290
|
Chris@0
|
291 public function setCommandOptions($commandInfo, $automaticOptions = [])
|
Chris@0
|
292 {
|
Chris@0
|
293 $inputOptions = $commandInfo->inputOptions();
|
Chris@0
|
294
|
Chris@0
|
295 $this->addOptions($inputOptions + $automaticOptions, $automaticOptions);
|
Chris@0
|
296 return $this;
|
Chris@0
|
297 }
|
Chris@0
|
298
|
Chris@0
|
299 public function addOptions($inputOptions, $automaticOptions = [])
|
Chris@0
|
300 {
|
Chris@0
|
301 foreach ($inputOptions as $name => $inputOption) {
|
Chris@0
|
302 $description = $inputOption->getDescription();
|
Chris@0
|
303
|
Chris@0
|
304 if (empty($description) && isset($automaticOptions[$name])) {
|
Chris@0
|
305 $description = $automaticOptions[$name]->getDescription();
|
Chris@0
|
306 $inputOption = static::inputOptionSetDescription($inputOption, $description);
|
Chris@0
|
307 }
|
Chris@0
|
308 $this->getDefinition()->addOption($inputOption);
|
Chris@0
|
309 }
|
Chris@0
|
310 }
|
Chris@0
|
311
|
Chris@0
|
312 protected static function inputOptionSetDescription($inputOption, $description)
|
Chris@0
|
313 {
|
Chris@0
|
314 // Recover the 'mode' value, because Symfony is stubborn
|
Chris@0
|
315 $mode = 0;
|
Chris@0
|
316 if ($inputOption->isValueRequired()) {
|
Chris@0
|
317 $mode |= InputOption::VALUE_REQUIRED;
|
Chris@0
|
318 }
|
Chris@0
|
319 if ($inputOption->isValueOptional()) {
|
Chris@0
|
320 $mode |= InputOption::VALUE_OPTIONAL;
|
Chris@0
|
321 }
|
Chris@0
|
322 if ($inputOption->isArray()) {
|
Chris@0
|
323 $mode |= InputOption::VALUE_IS_ARRAY;
|
Chris@0
|
324 }
|
Chris@0
|
325 if (!$mode) {
|
Chris@0
|
326 $mode = InputOption::VALUE_NONE;
|
Chris@0
|
327 }
|
Chris@0
|
328
|
Chris@0
|
329 $inputOption = new InputOption(
|
Chris@0
|
330 $inputOption->getName(),
|
Chris@0
|
331 $inputOption->getShortcut(),
|
Chris@0
|
332 $mode,
|
Chris@0
|
333 $description,
|
Chris@0
|
334 $inputOption->getDefault()
|
Chris@0
|
335 );
|
Chris@0
|
336 return $inputOption;
|
Chris@0
|
337 }
|
Chris@0
|
338
|
Chris@0
|
339 /**
|
Chris@0
|
340 * Returns all of the hook names that may be called for this command.
|
Chris@0
|
341 *
|
Chris@0
|
342 * @return array
|
Chris@0
|
343 */
|
Chris@0
|
344 public function getNames()
|
Chris@0
|
345 {
|
Chris@0
|
346 return HookManager::getNames($this, $this->commandCallback);
|
Chris@0
|
347 }
|
Chris@0
|
348
|
Chris@0
|
349 /**
|
Chris@0
|
350 * Add any options to this command that are defined by hook implementations
|
Chris@0
|
351 */
|
Chris@0
|
352 public function optionsHook()
|
Chris@0
|
353 {
|
Chris@0
|
354 $this->commandProcessor()->optionsHook(
|
Chris@0
|
355 $this,
|
Chris@0
|
356 $this->getNames(),
|
Chris@0
|
357 $this->annotationData
|
Chris@0
|
358 );
|
Chris@0
|
359 }
|
Chris@0
|
360
|
Chris@0
|
361 public function optionsHookForHookAnnotations($commandInfoList)
|
Chris@0
|
362 {
|
Chris@0
|
363 foreach ($commandInfoList as $commandInfo) {
|
Chris@0
|
364 $inputOptions = $commandInfo->inputOptions();
|
Chris@0
|
365 $this->addOptions($inputOptions);
|
Chris@0
|
366 foreach ($commandInfo->getExampleUsages() as $usage => $description) {
|
Chris@0
|
367 if (!in_array($usage, $this->getUsages())) {
|
Chris@0
|
368 $this->addUsageOrExample($usage, $description);
|
Chris@0
|
369 }
|
Chris@0
|
370 }
|
Chris@0
|
371 }
|
Chris@0
|
372 }
|
Chris@0
|
373
|
Chris@0
|
374 /**
|
Chris@0
|
375 * {@inheritdoc}
|
Chris@0
|
376 */
|
Chris@0
|
377 protected function interact(InputInterface $input, OutputInterface $output)
|
Chris@0
|
378 {
|
Chris@0
|
379 $this->commandProcessor()->interact(
|
Chris@0
|
380 $input,
|
Chris@0
|
381 $output,
|
Chris@0
|
382 $this->getNames(),
|
Chris@0
|
383 $this->annotationData
|
Chris@0
|
384 );
|
Chris@0
|
385 }
|
Chris@0
|
386
|
Chris@0
|
387 protected function initialize(InputInterface $input, OutputInterface $output)
|
Chris@0
|
388 {
|
Chris@0
|
389 // Allow the hook manager a chance to provide configuration values,
|
Chris@0
|
390 // if there are any registered hooks to do that.
|
Chris@0
|
391 $this->commandProcessor()->initializeHook($input, $this->getNames(), $this->annotationData);
|
Chris@0
|
392 }
|
Chris@0
|
393
|
Chris@0
|
394 /**
|
Chris@0
|
395 * {@inheritdoc}
|
Chris@0
|
396 */
|
Chris@0
|
397 protected function execute(InputInterface $input, OutputInterface $output)
|
Chris@0
|
398 {
|
Chris@0
|
399 // Validate, run, process, alter, handle results.
|
Chris@0
|
400 return $this->commandProcessor()->process(
|
Chris@0
|
401 $output,
|
Chris@0
|
402 $this->getNames(),
|
Chris@0
|
403 $this->commandCallback,
|
Chris@0
|
404 $this->createCommandData($input, $output)
|
Chris@0
|
405 );
|
Chris@0
|
406 }
|
Chris@0
|
407
|
Chris@0
|
408 /**
|
Chris@0
|
409 * This function is available for use by a class that may
|
Chris@0
|
410 * wish to extend this class rather than use annotations to
|
Chris@0
|
411 * define commands. Using this technique does allow for the
|
Chris@0
|
412 * use of annotations to define hooks.
|
Chris@0
|
413 */
|
Chris@0
|
414 public function processResults(InputInterface $input, OutputInterface $output, $results)
|
Chris@0
|
415 {
|
Chris@0
|
416 $commandData = $this->createCommandData($input, $output);
|
Chris@0
|
417 $commandProcessor = $this->commandProcessor();
|
Chris@0
|
418 $names = $this->getNames();
|
Chris@0
|
419 $results = $commandProcessor->processResults(
|
Chris@0
|
420 $names,
|
Chris@0
|
421 $results,
|
Chris@0
|
422 $commandData
|
Chris@0
|
423 );
|
Chris@0
|
424 return $commandProcessor->handleResults(
|
Chris@0
|
425 $output,
|
Chris@0
|
426 $names,
|
Chris@0
|
427 $results,
|
Chris@0
|
428 $commandData
|
Chris@0
|
429 );
|
Chris@0
|
430 }
|
Chris@0
|
431
|
Chris@0
|
432 protected function createCommandData(InputInterface $input, OutputInterface $output)
|
Chris@0
|
433 {
|
Chris@0
|
434 $commandData = new CommandData(
|
Chris@0
|
435 $this->annotationData,
|
Chris@0
|
436 $input,
|
Chris@0
|
437 $output
|
Chris@0
|
438 );
|
Chris@0
|
439
|
Chris@0
|
440 $commandData->setUseIOInterfaces(
|
Chris@0
|
441 $this->usesInputInterface,
|
Chris@0
|
442 $this->usesOutputInterface
|
Chris@0
|
443 );
|
Chris@0
|
444
|
Chris@0
|
445 // Allow the commandData to cache the list of options with
|
Chris@0
|
446 // special default values ('null' and 'true'), as these will
|
Chris@0
|
447 // need special handling. @see CommandData::options().
|
Chris@0
|
448 $commandData->cacheSpecialDefaults($this->getDefinition());
|
Chris@0
|
449
|
Chris@0
|
450 return $commandData;
|
Chris@0
|
451 }
|
Chris@0
|
452 }
|