4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Console\Command;
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;
23 * Base class for all commands.
25 * @author Fabien Potencier <fabien@symfony.com>
37 private $ignoreValidationErrors;
38 private $applicationDefinitionMerged;
46 * @param string $name The name of the command
48 * @throws \LogicException When the command name is empty
52 public function __construct($name = null)
54 $this->definition = new InputDefinition();
55 $this->ignoreValidationErrors = false;
56 $this->applicationDefinitionMerged = false;
57 $this->aliases = array();
60 $this->setName($name);
66 throw new \LogicException('The command name cannot be empty.');
71 * Ignores validation errors.
73 * This is mainly useful for the help command.
75 public function ignoreValidationErrors()
77 $this->ignoreValidationErrors = true;
81 * Sets the application instance for this command.
83 * @param Application $application An Application instance
87 public function setApplication(Application $application = null)
89 $this->application = $application;
91 $this->setHelperSet($application->getHelperSet());
93 $this->helperSet = null;
98 * Sets the helper set.
100 * @param HelperSet $helperSet A HelperSet instance
102 public function setHelperSet(HelperSet $helperSet)
104 $this->helperSet = $helperSet;
108 * Gets the helper set.
110 * @return HelperSet A HelperSet instance
112 public function getHelperSet()
114 return $this->helperSet;
118 * Gets the application instance for this command.
120 * @return Application An Application instance
124 public function getApplication()
126 return $this->application;
130 * Checks whether the command is enabled or not in the current environment
132 * Override this to check for x or y and return false if the command can not
133 * run properly under the current conditions.
137 public function isEnabled()
143 * Configures the current command.
145 protected function configure()
150 * Executes the current command.
152 * This method is not abstract because you can use this class
153 * as a concrete class. In this case, instead of defining the
154 * execute() method, you set the code to execute by passing
155 * a Closure to the setCode() method.
157 * @param InputInterface $input An InputInterface instance
158 * @param OutputInterface $output An OutputInterface instance
160 * @return integer 0 if everything went fine, or an error code
162 * @throws \LogicException When this abstract method is not implemented
165 protected function execute(InputInterface $input, OutputInterface $output)
167 throw new \LogicException('You must override the execute() method in the concrete command class.');
171 * Interacts with the user.
173 * @param InputInterface $input An InputInterface instance
174 * @param OutputInterface $output An OutputInterface instance
176 protected function interact(InputInterface $input, OutputInterface $output)
181 * Initializes the command just after the input has been validated.
183 * This is mainly useful when a lot of commands extends one main command
184 * where some things need to be initialized based on the input arguments and options.
186 * @param InputInterface $input An InputInterface instance
187 * @param OutputInterface $output An OutputInterface instance
189 protected function initialize(InputInterface $input, OutputInterface $output)
196 * The code to execute is either defined directly with the
197 * setCode() method or by overriding the execute() method
200 * @param InputInterface $input An InputInterface instance
201 * @param OutputInterface $output An OutputInterface instance
203 * @return integer The command exit code
210 public function run(InputInterface $input, OutputInterface $output)
212 // force the creation of the synopsis before the merge with the app definition
213 $this->getSynopsis();
215 // add the application arguments and options
216 $this->mergeApplicationDefinition();
218 // bind the input against the command specific arguments/options
220 $input->bind($this->definition);
221 } catch (\Exception $e) {
222 if (!$this->ignoreValidationErrors) {
227 $this->initialize($input, $output);
229 if ($input->isInteractive()) {
230 $this->interact($input, $output);
236 return call_user_func($this->code, $input, $output);
239 return $this->execute($input, $output);
243 * Sets the code to execute when running this command.
245 * If this method is used, it overrides the code defined
246 * in the execute() method.
248 * @param \Closure $code A \Closure
250 * @return Command The current instance
256 public function setCode(\Closure $code)
264 * Merges the application definition with the command definition.
266 private function mergeApplicationDefinition()
268 if (null === $this->application || true === $this->applicationDefinitionMerged) {
272 $currentArguments = $this->definition->getArguments();
273 $this->definition->setArguments($this->application->getDefinition()->getArguments());
274 $this->definition->addArguments($currentArguments);
276 $this->definition->addOptions($this->application->getDefinition()->getOptions());
278 $this->applicationDefinitionMerged = true;
282 * Sets an array of argument and option instances.
284 * @param array|InputDefinition $definition An array of argument and option instances or a definition instance
286 * @return Command The current instance
290 public function setDefinition($definition)
292 if ($definition instanceof InputDefinition) {
293 $this->definition = $definition;
295 $this->definition->setDefinition($definition);
298 $this->applicationDefinitionMerged = false;
304 * Gets the InputDefinition attached to this Command.
306 * @return InputDefinition An InputDefinition instance
310 public function getDefinition()
312 return $this->definition;
316 * Gets the InputDefinition to be used to create XML and Text representations of this Command.
318 * Can be overridden to provide the original command representation when it would otherwise
319 * be changed by merging with the application InputDefinition.
321 * @return InputDefinition An InputDefinition instance
323 protected function getNativeDefinition()
325 return $this->getDefinition();
331 * @param string $name The argument name
332 * @param integer $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
333 * @param string $description A description text
334 * @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
336 * @return Command The current instance
340 public function addArgument($name, $mode = null, $description = '', $default = null)
342 $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
350 * @param string $name The option name
351 * @param string $shortcut The shortcut (can be null)
352 * @param integer $mode The option mode: One of the InputOption::VALUE_* constants
353 * @param string $description A description text
354 * @param mixed $default The default value (must be null for InputOption::VALUE_REQUIRED or InputOption::VALUE_NONE)
356 * @return Command The current instance
360 public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
362 $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
368 * Sets the name of the command.
370 * This method can set both the namespace and the name if
371 * you separate them by a colon (:)
373 * $command->setName('foo:bar');
375 * @param string $name The command name
377 * @return Command The current instance
379 * @throws \InvalidArgumentException When command name given is empty
383 public function setName($name)
385 $this->validateName($name);
393 * Returns the command name.
395 * @return string The command name
399 public function getName()
405 * Sets the description for the command.
407 * @param string $description The description for the command
409 * @return Command The current instance
413 public function setDescription($description)
415 $this->description = $description;
421 * Returns the description for the command.
423 * @return string The description for the command
427 public function getDescription()
429 return $this->description;
433 * Sets the help for the command.
435 * @param string $help The help for the command
437 * @return Command The current instance
441 public function setHelp($help)
449 * Returns the help for the command.
451 * @return string The help for the command
455 public function getHelp()
461 * Returns the processed help for the command replacing the %command.name% and
462 * %command.full_name% patterns with the real values dynamically.
464 * @return string The processed help for the command
466 public function getProcessedHelp()
470 $placeholders = array(
472 '%command.full_name%'
474 $replacements = array(
476 $_SERVER['PHP_SELF'].' '.$name
479 return str_replace($placeholders, $replacements, $this->getHelp());
483 * Sets the aliases for the command.
485 * @param array $aliases An array of aliases for the command
487 * @return Command The current instance
491 public function setAliases($aliases)
493 foreach ($aliases as $alias) {
494 $this->validateName($alias);
497 $this->aliases = $aliases;
503 * Returns the aliases for the command.
505 * @return array An array of aliases for the command
509 public function getAliases()
511 return $this->aliases;
515 * Returns the synopsis for the command.
517 * @return string The synopsis
519 public function getSynopsis()
521 if (null === $this->synopsis) {
522 $this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
525 return $this->synopsis;
529 * Gets a helper instance by name.
531 * @param string $name The helper name
533 * @return mixed The helper value
535 * @throws \InvalidArgumentException if the helper is not defined
539 public function getHelper($name)
541 return $this->helperSet->get($name);
545 * Returns a text representation of the command.
547 * @return string A string representing the command
549 public function asText()
552 '<comment>Usage:</comment>',
553 ' '.$this->getSynopsis(),
557 if ($this->getAliases()) {
558 $messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
561 $messages[] = $this->getNativeDefinition()->asText();
563 if ($help = $this->getProcessedHelp()) {
564 $messages[] = '<comment>Help:</comment>';
565 $messages[] = ' '.str_replace("\n", "\n ", $help)."\n";
568 return implode("\n", $messages);
572 * Returns an XML representation of the command.
574 * @param Boolean $asDom Whether to return a DOM or an XML string
576 * @return string|DOMDocument An XML string representing the command
578 public function asXml($asDom = false)
580 $dom = new \DOMDocument('1.0', 'UTF-8');
581 $dom->formatOutput = true;
582 $dom->appendChild($commandXML = $dom->createElement('command'));
583 $commandXML->setAttribute('id', $this->name);
584 $commandXML->setAttribute('name', $this->name);
586 $commandXML->appendChild($usageXML = $dom->createElement('usage'));
587 $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
589 $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
590 $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getDescription())));
592 $commandXML->appendChild($helpXML = $dom->createElement('help'));
593 $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getProcessedHelp())));
595 $commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
596 foreach ($this->getAliases() as $alias) {
597 $aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
598 $aliasXML->appendChild($dom->createTextNode($alias));
601 $definition = $this->getNativeDefinition()->asXml(true);
602 $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
603 $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
605 return $asDom ? $dom : $dom->saveXml();
608 private function validateName($name)
610 if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
611 throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));