1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\Console\Command;
13:
14: use Symfony\Component\Console\Input\InputDefinition;
15: use Symfony\Component\Console\Input\InputOption;
16: use Symfony\Component\Console\Input\InputArgument;
17: use Symfony\Component\Console\Input\InputInterface;
18: use Symfony\Component\Console\Output\OutputInterface;
19: use Symfony\Component\Console\Application;
20: use Symfony\Component\Console\Helper\HelperSet;
21:
22: 23: 24: 25: 26: 27: 28:
29: class Command
30: {
31: private $application;
32: private $name;
33: private $aliases;
34: private $definition;
35: private $help;
36: private $description;
37: private $ignoreValidationErrors;
38: private $applicationDefinitionMerged;
39: private $code;
40: private $synopsis;
41: private $helperSet;
42:
43: 44: 45: 46: 47: 48: 49: 50: 51:
52: public function __construct($name = null)
53: {
54: $this->definition = new InputDefinition();
55: $this->ignoreValidationErrors = false;
56: $this->applicationDefinitionMerged = false;
57: $this->aliases = array();
58:
59: if (null !== $name) {
60: $this->setName($name);
61: }
62:
63: $this->configure();
64:
65: if (!$this->name) {
66: throw new \LogicException('The command name cannot be empty.');
67: }
68: }
69:
70: 71: 72: 73: 74:
75: public function ignoreValidationErrors()
76: {
77: $this->ignoreValidationErrors = true;
78: }
79:
80: 81: 82: 83: 84: 85: 86:
87: public function setApplication(Application $application = null)
88: {
89: $this->application = $application;
90: if ($application) {
91: $this->setHelperSet($application->getHelperSet());
92: } else {
93: $this->helperSet = null;
94: }
95: }
96:
97: 98: 99: 100: 101:
102: public function setHelperSet(HelperSet $helperSet)
103: {
104: $this->helperSet = $helperSet;
105: }
106:
107: 108: 109: 110: 111:
112: public function getHelperSet()
113: {
114: return $this->helperSet;
115: }
116:
117: 118: 119: 120: 121: 122: 123:
124: public function getApplication()
125: {
126: return $this->application;
127: }
128:
129: 130: 131: 132: 133: 134: 135: 136:
137: public function isEnabled()
138: {
139: return true;
140: }
141:
142: 143: 144:
145: protected function configure()
146: {
147: }
148:
149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164:
165: protected function execute(InputInterface $input, OutputInterface $output)
166: {
167: throw new \LogicException('You must override the execute() method in the concrete command class.');
168: }
169:
170: 171: 172: 173: 174: 175:
176: protected function interact(InputInterface $input, OutputInterface $output)
177: {
178: }
179:
180: 181: 182: 183: 184: 185: 186: 187: 188:
189: protected function initialize(InputInterface $input, OutputInterface $output)
190: {
191: }
192:
193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211:
212: public function run(InputInterface $input, OutputInterface $output)
213: {
214:
215: $this->getSynopsis();
216:
217:
218: $this->mergeApplicationDefinition();
219:
220:
221: try {
222: $input->bind($this->definition);
223: } catch (\Exception $e) {
224: if (!$this->ignoreValidationErrors) {
225: throw $e;
226: }
227: }
228:
229: $this->initialize($input, $output);
230:
231: if ($input->isInteractive()) {
232: $this->interact($input, $output);
233: }
234:
235: $input->validate();
236:
237: if ($this->code) {
238: $statusCode = call_user_func($this->code, $input, $output);
239: } else {
240: $statusCode = $this->execute($input, $output);
241: }
242:
243: return is_numeric($statusCode) ? $statusCode : 0;
244: }
245:
246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261:
262: public function setCode($code)
263: {
264: if (!is_callable($code)) {
265: throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
266: }
267:
268: $this->code = $code;
269:
270: return $this;
271: }
272:
273: 274: 275: 276: 277:
278: private function mergeApplicationDefinition($mergeArgs = true)
279: {
280: if (null === $this->application || true === $this->applicationDefinitionMerged) {
281: return;
282: }
283:
284: if ($mergeArgs) {
285: $currentArguments = $this->definition->getArguments();
286: $this->definition->setArguments($this->application->getDefinition()->getArguments());
287: $this->definition->addArguments($currentArguments);
288: }
289:
290: $this->definition->addOptions($this->application->getDefinition()->getOptions());
291:
292: $this->applicationDefinitionMerged = true;
293: }
294:
295: 296: 297: 298: 299: 300: 301: 302: 303:
304: public function setDefinition($definition)
305: {
306: if ($definition instanceof InputDefinition) {
307: $this->definition = $definition;
308: } else {
309: $this->definition->setDefinition($definition);
310: }
311:
312: $this->applicationDefinitionMerged = false;
313:
314: return $this;
315: }
316:
317: 318: 319: 320: 321: 322: 323:
324: public function getDefinition()
325: {
326: return $this->definition;
327: }
328:
329: 330: 331: 332: 333: 334: 335: 336:
337: protected function getNativeDefinition()
338: {
339: return $this->getDefinition();
340: }
341:
342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353:
354: public function addArgument($name, $mode = null, $description = '', $default = null)
355: {
356: $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
357:
358: return $this;
359: }
360:
361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373:
374: public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
375: {
376: $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
377:
378: return $this;
379: }
380:
381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396:
397: public function setName($name)
398: {
399: $this->validateName($name);
400:
401: $this->name = $name;
402:
403: return $this;
404: }
405:
406: 407: 408: 409: 410: 411: 412:
413: public function getName()
414: {
415: return $this->name;
416: }
417:
418: 419: 420: 421: 422: 423: 424: 425: 426:
427: public function setDescription($description)
428: {
429: $this->description = $description;
430:
431: return $this;
432: }
433:
434: 435: 436: 437: 438: 439: 440:
441: public function getDescription()
442: {
443: return $this->description;
444: }
445:
446: 447: 448: 449: 450: 451: 452: 453: 454:
455: public function setHelp($help)
456: {
457: $this->help = $help;
458:
459: return $this;
460: }
461:
462: 463: 464: 465: 466: 467: 468:
469: public function getHelp()
470: {
471: return $this->help;
472: }
473:
474: 475: 476: 477: 478: 479:
480: public function getProcessedHelp()
481: {
482: $name = $this->name;
483:
484: $placeholders = array(
485: '%command.name%',
486: '%command.full_name%'
487: );
488: $replacements = array(
489: $name,
490: $_SERVER['PHP_SELF'].' '.$name
491: );
492:
493: return str_replace($placeholders, $replacements, $this->getHelp());
494: }
495:
496: 497: 498: 499: 500: 501: 502: 503: 504:
505: public function setAliases($aliases)
506: {
507: foreach ($aliases as $alias) {
508: $this->validateName($alias);
509: }
510:
511: $this->aliases = $aliases;
512:
513: return $this;
514: }
515:
516: 517: 518: 519: 520: 521: 522:
523: public function getAliases()
524: {
525: return $this->aliases;
526: }
527:
528: 529: 530: 531: 532:
533: public function getSynopsis()
534: {
535: if (null === $this->synopsis) {
536: $this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
537: }
538:
539: return $this->synopsis;
540: }
541:
542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552:
553: public function getHelper($name)
554: {
555: return $this->helperSet->get($name);
556: }
557:
558: 559: 560: 561: 562:
563: public function asText()
564: {
565: if ($this->application && !$this->applicationDefinitionMerged) {
566: $this->getSynopsis();
567: $this->mergeApplicationDefinition(false);
568: }
569:
570: $messages = array(
571: '<comment>Usage:</comment>',
572: ' '.$this->getSynopsis(),
573: '',
574: );
575:
576: if ($this->getAliases()) {
577: $messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
578: }
579:
580: $messages[] = $this->getNativeDefinition()->asText();
581:
582: if ($help = $this->getProcessedHelp()) {
583: $messages[] = '<comment>Help:</comment>';
584: $messages[] = ' '.str_replace("\n", "\n ", $help)."\n";
585: }
586:
587: return implode("\n", $messages);
588: }
589:
590: 591: 592: 593: 594: 595: 596:
597: public function asXml($asDom = false)
598: {
599: if ($this->application && !$this->applicationDefinitionMerged) {
600: $this->getSynopsis();
601: $this->mergeApplicationDefinition(false);
602: }
603:
604: $dom = new \DOMDocument('1.0', 'UTF-8');
605: $dom->formatOutput = true;
606: $dom->appendChild($commandXML = $dom->createElement('command'));
607: $commandXML->setAttribute('id', $this->name);
608: $commandXML->setAttribute('name', $this->name);
609:
610: $commandXML->appendChild($usageXML = $dom->createElement('usage'));
611: $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
612:
613: $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
614: $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getDescription())));
615:
616: $commandXML->appendChild($helpXML = $dom->createElement('help'));
617: $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getProcessedHelp())));
618:
619: $commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
620: foreach ($this->getAliases() as $alias) {
621: $aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
622: $aliasXML->appendChild($dom->createTextNode($alias));
623: }
624:
625: $definition = $this->getNativeDefinition()->asXml(true);
626: $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
627: $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
628:
629: return $asDom ? $dom : $dom->saveXml();
630: }
631:
632: private function validateName($name)
633: {
634: if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
635: throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
636: }
637: }
638: }
639: