1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\Console\Input;
13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 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: 39: 40: 41: 42: 43:
44: public function __construct(array $definition = array())
45: {
46: $this->setDefinition($definition);
47: }
48:
49: 50: 51: 52: 53: 54: 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: 74: 75: 76: 77: 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: 90: 91: 92: 93: 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: 106: 107: 108: 109: 110: 111: 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 exists.', $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: 142: 143: 144: 145: 146: 147: 148: 149: 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: 164: 165: 166: 167: 168: 169: 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: 180: 181: 182: 183: 184:
185: public function getArguments()
186: {
187: return $this->arguments;
188: }
189:
190: 191: 192: 193: 194:
195: public function getArgumentCount()
196: {
197: return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
198: }
199:
200: 201: 202: 203: 204:
205: public function getArgumentRequiredCount()
206: {
207: return $this->requiredCount;
208: }
209:
210: 211: 212: 213: 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: 227: 228: 229: 230: 231:
232: public function setOptions($options = array())
233: {
234: $this->options = array();
235: $this->shortcuts = array();
236: $this->addOptions($options);
237: }
238:
239: 240: 241: 242: 243: 244: 245:
246: public function addOptions($options = array())
247: {
248: foreach ($options as $option) {
249: $this->addOption($option);
250: }
251: }
252:
253: 254: 255: 256: 257: 258: 259: 260: 261:
262: public function addOption(InputOption $option)
263: {
264: if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
265: throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
266: } elseif (isset($this->shortcuts[$option->getShortcut()]) && !$option->equals($this->options[$this->shortcuts[$option->getShortcut()]])) {
267: throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $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: 278: 279: 280: 281: 282: 283: 284: 285: 286:
287: public function getOption($name)
288: {
289: if (!$this->hasOption($name)) {
290: throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
291: }
292:
293: return $this->options[$name];
294: }
295:
296: 297: 298: 299: 300: 301: 302: 303: 304:
305: public function hasOption($name)
306: {
307: return isset($this->options[$name]);
308: }
309:
310: 311: 312: 313: 314: 315: 316:
317: public function getOptions()
318: {
319: return $this->options;
320: }
321:
322: 323: 324: 325: 326: 327: 328:
329: public function hasShortcut($name)
330: {
331: return isset($this->shortcuts[$name]);
332: }
333:
334: 335: 336: 337: 338: 339: 340:
341: public function getOptionForShortcut($shortcut)
342: {
343: return $this->getOption($this->shortcutToName($shortcut));
344: }
345:
346: 347: 348: 349: 350:
351: public function getOptionDefaults()
352: {
353: $values = array();
354: foreach ($this->options as $option) {
355: $values[$option->getName()] = $option->getDefault();
356: }
357:
358: return $values;
359: }
360:
361: 362: 363: 364: 365: 366: 367: 368: 369:
370: private function shortcutToName($shortcut)
371: {
372: if (!isset($this->shortcuts[$shortcut])) {
373: throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
374: }
375:
376: return $this->shortcuts[$shortcut];
377: }
378:
379: 380: 381: 382: 383:
384: public function getSynopsis()
385: {
386: $elements = array();
387: foreach ($this->getOptions() as $option) {
388: $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
389: $elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
390: }
391:
392: foreach ($this->getArguments() as $argument) {
393: $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
394:
395: if ($argument->isArray()) {
396: $elements[] = sprintf('... [%sN]', $argument->getName());
397: }
398: }
399:
400: return implode(' ', $elements);
401: }
402:
403: 404: 405: 406: 407:
408: public function asText()
409: {
410:
411: $max = 0;
412: foreach ($this->getOptions() as $option) {
413: $nameLength = strlen($option->getName()) + 2;
414: if ($option->getShortcut()) {
415: $nameLength += strlen($option->getShortcut()) + 3;
416: }
417:
418: $max = max($max, $nameLength);
419: }
420: foreach ($this->getArguments() as $argument) {
421: $max = max($max, strlen($argument->getName()));
422: }
423: ++$max;
424:
425: $text = array();
426:
427: if ($this->getArguments()) {
428: $text[] = '<comment>Arguments:</comment>';
429: foreach ($this->getArguments() as $argument) {
430: if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
431: $default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($argument->getDefault()));
432: } else {
433: $default = '';
434: }
435:
436: $description = str_replace("\n", "\n".str_repeat(' ', $max + 2), $argument->getDescription());
437:
438: $text[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default);
439: }
440:
441: $text[] = '';
442: }
443:
444: if ($this->getOptions()) {
445: $text[] = '<comment>Options:</comment>';
446:
447: foreach ($this->getOptions() as $option) {
448: if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
449: $default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($option->getDefault()));
450: } else {
451: $default = '';
452: }
453:
454: $multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
455: $description = str_replace("\n", "\n".str_repeat(' ', $max + 2), $option->getDescription());
456:
457: $optionMax = $max - strlen($option->getName()) - 2;
458: $text[] = sprintf(" <info>%s</info> %-${optionMax}s%s%s%s",
459: '--'.$option->getName(),
460: $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '',
461: $description,
462: $default,
463: $multiple
464: );
465: }
466:
467: $text[] = '';
468: }
469:
470: return implode("\n", $text);
471: }
472:
473: 474: 475: 476: 477: 478: 479:
480: public function asXml($asDom = false)
481: {
482: $dom = new \DOMDocument('1.0', 'UTF-8');
483: $dom->formatOutput = true;
484: $dom->appendChild($definitionXML = $dom->createElement('definition'));
485:
486: $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
487: foreach ($this->getArguments() as $argument) {
488: $argumentsXML->appendChild($argumentXML = $dom->createElement('argument'));
489: $argumentXML->setAttribute('name', $argument->getName());
490: $argumentXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
491: $argumentXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
492: $argumentXML->appendChild($descriptionXML = $dom->createElement('description'));
493: $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
494:
495: $argumentXML->appendChild($defaultsXML = $dom->createElement('defaults'));
496: $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : (is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
497: foreach ($defaults as $default) {
498: $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
499: $defaultXML->appendChild($dom->createTextNode($default));
500: }
501: }
502:
503: $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
504: foreach ($this->getOptions() as $option) {
505: $optionsXML->appendChild($optionXML = $dom->createElement('option'));
506: $optionXML->setAttribute('name', '--'.$option->getName());
507: $optionXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
508: $optionXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
509: $optionXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
510: $optionXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
511: $optionXML->appendChild($descriptionXML = $dom->createElement('description'));
512: $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
513:
514: if ($option->acceptValue()) {
515: $optionXML->appendChild($defaultsXML = $dom->createElement('defaults'));
516: $defaults = is_array($option->getDefault()) ? $option->getDefault() : (is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
517: foreach ($defaults as $default) {
518: $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
519: $defaultXML->appendChild($dom->createTextNode($default));
520: }
521: }
522: }
523:
524: return $asDom ? $dom : $dom->saveXml();
525: }
526:
527: private function formatDefaultValue($default)
528: {
529: if (version_compare(PHP_VERSION, '5.4', '<')) {
530: return str_replace('\/', '/', json_encode($default));
531: }
532:
533: return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
534: }
535: }
536: