|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\Console\Input; |
|
13 |
|
14 /** |
|
15 * A InputDefinition represents a set of valid command line arguments and options. |
|
16 * |
|
17 * Usage: |
|
18 * |
|
19 * $definition = new InputDefinition(array( |
|
20 * new InputArgument('name', InputArgument::REQUIRED), |
|
21 * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), |
|
22 * )); |
|
23 * |
|
24 * @author Fabien Potencier <fabien@symfony.com> |
|
25 * |
|
26 * @api |
|
27 */ |
|
28 class InputDefinition |
|
29 { |
|
30 private $arguments; |
|
31 private $requiredCount; |
|
32 private $hasAnArrayArgument = false; |
|
33 private $hasOptional; |
|
34 private $options; |
|
35 private $shortcuts; |
|
36 |
|
37 /** |
|
38 * Constructor. |
|
39 * |
|
40 * @param array $definition An array of InputArgument and InputOption instance |
|
41 * |
|
42 * @api |
|
43 */ |
|
44 public function __construct(array $definition = array()) |
|
45 { |
|
46 $this->setDefinition($definition); |
|
47 } |
|
48 |
|
49 /** |
|
50 * Sets the definition of the input. |
|
51 * |
|
52 * @param array $definition The definition array |
|
53 * |
|
54 * @api |
|
55 */ |
|
56 public function setDefinition(array $definition) |
|
57 { |
|
58 $arguments = array(); |
|
59 $options = array(); |
|
60 foreach ($definition as $item) { |
|
61 if ($item instanceof InputOption) { |
|
62 $options[] = $item; |
|
63 } else { |
|
64 $arguments[] = $item; |
|
65 } |
|
66 } |
|
67 |
|
68 $this->setArguments($arguments); |
|
69 $this->setOptions($options); |
|
70 } |
|
71 |
|
72 /** |
|
73 * Sets the InputArgument objects. |
|
74 * |
|
75 * @param array $arguments An array of InputArgument objects |
|
76 * |
|
77 * @api |
|
78 */ |
|
79 public function setArguments($arguments = array()) |
|
80 { |
|
81 $this->arguments = array(); |
|
82 $this->requiredCount = 0; |
|
83 $this->hasOptional = false; |
|
84 $this->hasAnArrayArgument = false; |
|
85 $this->addArguments($arguments); |
|
86 } |
|
87 |
|
88 /** |
|
89 * Add an array of InputArgument objects. |
|
90 * |
|
91 * @param InputArgument[] $arguments An array of InputArgument objects |
|
92 * |
|
93 * @api |
|
94 */ |
|
95 public function addArguments($arguments = array()) |
|
96 { |
|
97 if (null !== $arguments) { |
|
98 foreach ($arguments as $argument) { |
|
99 $this->addArgument($argument); |
|
100 } |
|
101 } |
|
102 } |
|
103 |
|
104 /** |
|
105 * Add an InputArgument object. |
|
106 * |
|
107 * @param InputArgument $argument An InputArgument object |
|
108 * |
|
109 * @throws \LogicException When incorrect argument is given |
|
110 * |
|
111 * @api |
|
112 */ |
|
113 public function addArgument(InputArgument $argument) |
|
114 { |
|
115 if (isset($this->arguments[$argument->getName()])) { |
|
116 throw new \LogicException(sprintf('An argument with name "%s" already exist.', $argument->getName())); |
|
117 } |
|
118 |
|
119 if ($this->hasAnArrayArgument) { |
|
120 throw new \LogicException('Cannot add an argument after an array argument.'); |
|
121 } |
|
122 |
|
123 if ($argument->isRequired() && $this->hasOptional) { |
|
124 throw new \LogicException('Cannot add a required argument after an optional one.'); |
|
125 } |
|
126 |
|
127 if ($argument->isArray()) { |
|
128 $this->hasAnArrayArgument = true; |
|
129 } |
|
130 |
|
131 if ($argument->isRequired()) { |
|
132 ++$this->requiredCount; |
|
133 } else { |
|
134 $this->hasOptional = true; |
|
135 } |
|
136 |
|
137 $this->arguments[$argument->getName()] = $argument; |
|
138 } |
|
139 |
|
140 /** |
|
141 * Returns an InputArgument by name or by position. |
|
142 * |
|
143 * @param string|integer $name The InputArgument name or position |
|
144 * |
|
145 * @return InputArgument An InputArgument object |
|
146 * |
|
147 * @throws \InvalidArgumentException When argument given doesn't exist |
|
148 * |
|
149 * @api |
|
150 */ |
|
151 public function getArgument($name) |
|
152 { |
|
153 $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; |
|
154 |
|
155 if (!$this->hasArgument($name)) { |
|
156 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); |
|
157 } |
|
158 |
|
159 return $arguments[$name]; |
|
160 } |
|
161 |
|
162 /** |
|
163 * Returns true if an InputArgument object exists by name or position. |
|
164 * |
|
165 * @param string|integer $name The InputArgument name or position |
|
166 * |
|
167 * @return Boolean true if the InputArgument object exists, false otherwise |
|
168 * |
|
169 * @api |
|
170 */ |
|
171 public function hasArgument($name) |
|
172 { |
|
173 $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; |
|
174 |
|
175 return isset($arguments[$name]); |
|
176 } |
|
177 |
|
178 /** |
|
179 * Gets the array of InputArgument objects. |
|
180 * |
|
181 * @return array An array of InputArgument objects |
|
182 * |
|
183 * @api |
|
184 */ |
|
185 public function getArguments() |
|
186 { |
|
187 return $this->arguments; |
|
188 } |
|
189 |
|
190 /** |
|
191 * Returns the number of InputArguments. |
|
192 * |
|
193 * @return integer The number of InputArguments |
|
194 */ |
|
195 public function getArgumentCount() |
|
196 { |
|
197 return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments); |
|
198 } |
|
199 |
|
200 /** |
|
201 * Returns the number of required InputArguments. |
|
202 * |
|
203 * @return integer The number of required InputArguments |
|
204 */ |
|
205 public function getArgumentRequiredCount() |
|
206 { |
|
207 return $this->requiredCount; |
|
208 } |
|
209 |
|
210 /** |
|
211 * Gets the default values. |
|
212 * |
|
213 * @return array An array of default values |
|
214 */ |
|
215 public function getArgumentDefaults() |
|
216 { |
|
217 $values = array(); |
|
218 foreach ($this->arguments as $argument) { |
|
219 $values[$argument->getName()] = $argument->getDefault(); |
|
220 } |
|
221 |
|
222 return $values; |
|
223 } |
|
224 |
|
225 /** |
|
226 * Sets the InputOption objects. |
|
227 * |
|
228 * @param array $options An array of InputOption objects |
|
229 * |
|
230 * @api |
|
231 */ |
|
232 public function setOptions($options = array()) |
|
233 { |
|
234 $this->options = array(); |
|
235 $this->shortcuts = array(); |
|
236 $this->addOptions($options); |
|
237 } |
|
238 |
|
239 /** |
|
240 * Add an array of InputOption objects. |
|
241 * |
|
242 * @param InputOption[] $options An array of InputOption objects |
|
243 * |
|
244 * @api |
|
245 */ |
|
246 public function addOptions($options = array()) |
|
247 { |
|
248 foreach ($options as $option) { |
|
249 $this->addOption($option); |
|
250 } |
|
251 } |
|
252 |
|
253 /** |
|
254 * Add an InputOption object. |
|
255 * |
|
256 * @param InputOption $option An InputOption object |
|
257 * |
|
258 * @throws \LogicException When option given already exist |
|
259 * |
|
260 * @api |
|
261 */ |
|
262 public function addOption(InputOption $option) |
|
263 { |
|
264 if (isset($this->options[$option->getName()])) { |
|
265 throw new \LogicException(sprintf('An option named "%s" already exist.', $option->getName())); |
|
266 } else if (isset($this->shortcuts[$option->getShortcut()])) { |
|
267 throw new \LogicException(sprintf('An option with shortcut "%s" already exist.', $option->getShortcut())); |
|
268 } |
|
269 |
|
270 $this->options[$option->getName()] = $option; |
|
271 if ($option->getShortcut()) { |
|
272 $this->shortcuts[$option->getShortcut()] = $option->getName(); |
|
273 } |
|
274 } |
|
275 |
|
276 /** |
|
277 * Returns an InputOption by name. |
|
278 * |
|
279 * @param string $name The InputOption name |
|
280 * |
|
281 * @return InputOption A InputOption object |
|
282 * |
|
283 * @api |
|
284 */ |
|
285 public function getOption($name) |
|
286 { |
|
287 if (!$this->hasOption($name)) { |
|
288 throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); |
|
289 } |
|
290 |
|
291 return $this->options[$name]; |
|
292 } |
|
293 |
|
294 /** |
|
295 * Returns true if an InputOption object exists by name. |
|
296 * |
|
297 * @param string $name The InputOption name |
|
298 * |
|
299 * @return Boolean true if the InputOption object exists, false otherwise |
|
300 * |
|
301 * @api |
|
302 */ |
|
303 public function hasOption($name) |
|
304 { |
|
305 return isset($this->options[$name]); |
|
306 } |
|
307 |
|
308 /** |
|
309 * Gets the array of InputOption objects. |
|
310 * |
|
311 * @return array An array of InputOption objects |
|
312 * |
|
313 * @api |
|
314 */ |
|
315 public function getOptions() |
|
316 { |
|
317 return $this->options; |
|
318 } |
|
319 |
|
320 /** |
|
321 * Returns true if an InputOption object exists by shortcut. |
|
322 * |
|
323 * @param string $name The InputOption shortcut |
|
324 * |
|
325 * @return Boolean true if the InputOption object exists, false otherwise |
|
326 */ |
|
327 public function hasShortcut($name) |
|
328 { |
|
329 return isset($this->shortcuts[$name]); |
|
330 } |
|
331 |
|
332 /** |
|
333 * Gets an InputOption by shortcut. |
|
334 * |
|
335 * @param string $shortcut the Shortcut name |
|
336 * |
|
337 * @return InputOption An InputOption object |
|
338 */ |
|
339 public function getOptionForShortcut($shortcut) |
|
340 { |
|
341 return $this->getOption($this->shortcutToName($shortcut)); |
|
342 } |
|
343 |
|
344 /** |
|
345 * Gets an array of default values. |
|
346 * |
|
347 * @return array An array of all default values |
|
348 */ |
|
349 public function getOptionDefaults() |
|
350 { |
|
351 $values = array(); |
|
352 foreach ($this->options as $option) { |
|
353 $values[$option->getName()] = $option->getDefault(); |
|
354 } |
|
355 |
|
356 return $values; |
|
357 } |
|
358 |
|
359 /** |
|
360 * Returns the InputOption name given a shortcut. |
|
361 * |
|
362 * @param string $shortcut The shortcut |
|
363 * |
|
364 * @return string The InputOption name |
|
365 * |
|
366 * @throws \InvalidArgumentException When option given does not exist |
|
367 */ |
|
368 private function shortcutToName($shortcut) |
|
369 { |
|
370 if (!isset($this->shortcuts[$shortcut])) { |
|
371 throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); |
|
372 } |
|
373 |
|
374 return $this->shortcuts[$shortcut]; |
|
375 } |
|
376 |
|
377 /** |
|
378 * Gets the synopsis. |
|
379 * |
|
380 * @return string The synopsis |
|
381 */ |
|
382 public function getSynopsis() |
|
383 { |
|
384 $elements = array(); |
|
385 foreach ($this->getOptions() as $option) { |
|
386 $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; |
|
387 $elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName()); |
|
388 } |
|
389 |
|
390 foreach ($this->getArguments() as $argument) { |
|
391 $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : '')); |
|
392 |
|
393 if ($argument->isArray()) { |
|
394 $elements[] = sprintf('... [%sN]', $argument->getName()); |
|
395 } |
|
396 } |
|
397 |
|
398 return implode(' ', $elements); |
|
399 } |
|
400 |
|
401 /** |
|
402 * Returns a textual representation of the InputDefinition. |
|
403 * |
|
404 * @return string A string representing the InputDefinition |
|
405 */ |
|
406 public function asText() |
|
407 { |
|
408 // find the largest option or argument name |
|
409 $max = 0; |
|
410 foreach ($this->getOptions() as $option) { |
|
411 $nameLength = strlen($option->getName()) + 2; |
|
412 if ($option->getShortcut()) { |
|
413 $nameLength += strlen($option->getShortcut()) + 3; |
|
414 } |
|
415 |
|
416 $max = max($max, $nameLength); |
|
417 } |
|
418 foreach ($this->getArguments() as $argument) { |
|
419 $max = max($max, strlen($argument->getName())); |
|
420 } |
|
421 ++$max; |
|
422 |
|
423 $text = array(); |
|
424 |
|
425 if ($this->getArguments()) { |
|
426 $text[] = '<comment>Arguments:</comment>'; |
|
427 foreach ($this->getArguments() as $argument) { |
|
428 if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) { |
|
429 $default = sprintf('<comment> (default: %s)</comment>', is_array($argument->getDefault()) ? str_replace("\n", '', var_export($argument->getDefault(), true)): $argument->getDefault()); |
|
430 } else { |
|
431 $default = ''; |
|
432 } |
|
433 |
|
434 $description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $argument->getDescription()); |
|
435 |
|
436 $text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default); |
|
437 } |
|
438 |
|
439 $text[] = ''; |
|
440 } |
|
441 |
|
442 if ($this->getOptions()) { |
|
443 $text[] = '<comment>Options:</comment>'; |
|
444 |
|
445 foreach ($this->getOptions() as $option) { |
|
446 if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) { |
|
447 $default = sprintf('<comment> (default: %s)</comment>', is_array($option->getDefault()) ? str_replace("\n", '', print_r($option->getDefault(), true)): $option->getDefault()); |
|
448 } else { |
|
449 $default = ''; |
|
450 } |
|
451 |
|
452 $multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''; |
|
453 $description = str_replace("\n", "\n".str_pad('', $max + 2, ' '), $option->getDescription()); |
|
454 |
|
455 $optionMax = $max - strlen($option->getName()) - 2; |
|
456 $text[] = sprintf(" <info>%s</info> %-${optionMax}s%s%s%s", |
|
457 '--'.$option->getName(), |
|
458 $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '', |
|
459 $description, |
|
460 $default, |
|
461 $multiple |
|
462 ); |
|
463 } |
|
464 |
|
465 $text[] = ''; |
|
466 } |
|
467 |
|
468 return implode("\n", $text); |
|
469 } |
|
470 |
|
471 /** |
|
472 * Returns an XML representation of the InputDefinition. |
|
473 * |
|
474 * @param Boolean $asDom Whether to return a DOM or an XML string |
|
475 * |
|
476 * @return string|DOMDocument An XML string representing the InputDefinition |
|
477 */ |
|
478 public function asXml($asDom = false) |
|
479 { |
|
480 $dom = new \DOMDocument('1.0', 'UTF-8'); |
|
481 $dom->formatOutput = true; |
|
482 $dom->appendChild($definitionXML = $dom->createElement('definition')); |
|
483 |
|
484 $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); |
|
485 foreach ($this->getArguments() as $argument) { |
|
486 $argumentsXML->appendChild($argumentXML = $dom->createElement('argument')); |
|
487 $argumentXML->setAttribute('name', $argument->getName()); |
|
488 $argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); |
|
489 $argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); |
|
490 $argumentXML->appendChild($descriptionXML = $dom->createElement('description')); |
|
491 $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); |
|
492 |
|
493 $argumentXML->appendChild($defaultsXML = $dom->createElement('defaults')); |
|
494 $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : ($argument->getDefault() ? array($argument->getDefault()) : array()); |
|
495 foreach ($defaults as $default) { |
|
496 $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); |
|
497 $defaultXML->appendChild($dom->createTextNode($default)); |
|
498 } |
|
499 } |
|
500 |
|
501 $definitionXML->appendChild($optionsXML = $dom->createElement('options')); |
|
502 foreach ($this->getOptions() as $option) { |
|
503 $optionsXML->appendChild($optionXML = $dom->createElement('option')); |
|
504 $optionXML->setAttribute('name', '--'.$option->getName()); |
|
505 $optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); |
|
506 $optionXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); |
|
507 $optionXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); |
|
508 $optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); |
|
509 $optionXML->appendChild($descriptionXML = $dom->createElement('description')); |
|
510 $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); |
|
511 |
|
512 if ($option->acceptValue()) { |
|
513 $optionXML->appendChild($defaultsXML = $dom->createElement('defaults')); |
|
514 $defaults = is_array($option->getDefault()) ? $option->getDefault() : ($option->getDefault() ? array($option->getDefault()) : array()); |
|
515 foreach ($defaults as $default) { |
|
516 $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); |
|
517 $defaultXML->appendChild($dom->createTextNode($default)); |
|
518 } |
|
519 } |
|
520 } |
|
521 |
|
522 return $asDom ? $dom : $dom->saveXml(); |
|
523 } |
|
524 } |