Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / symfony / console / Symfony / Component / Console / Command / Command.php
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\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  * Base class for all commands.
24  *
25  * @author Fabien Potencier <fabien@symfony.com>
26  *
27  * @api
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      * Constructor.
45      *
46      * @param string $name The name of the command
47      *
48      * @throws \LogicException When the command name is empty
49      *
50      * @api
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      * Ignores validation errors.
72      *
73      * This is mainly useful for the help command.
74      */
75     public function ignoreValidationErrors()
76     {
77         $this->ignoreValidationErrors = true;
78     }
79
80     /**
81      * Sets the application instance for this command.
82      *
83      * @param Application $application An Application instance
84      *
85      * @api
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      * Sets the helper set.
99      *
100      * @param HelperSet $helperSet A HelperSet instance
101      */
102     public function setHelperSet(HelperSet $helperSet)
103     {
104         $this->helperSet = $helperSet;
105     }
106
107     /**
108      * Gets the helper set.
109      *
110      * @return HelperSet A HelperSet instance
111      */
112     public function getHelperSet()
113     {
114         return $this->helperSet;
115     }
116
117     /**
118      * Gets the application instance for this command.
119      *
120      * @return Application An Application instance
121      *
122      * @api
123      */
124     public function getApplication()
125     {
126         return $this->application;
127     }
128
129     /**
130      * Checks whether the command is enabled or not in the current environment
131      *
132      * Override this to check for x or y and return false if the command can not
133      * run properly under the current conditions.
134      *
135      * @return Boolean
136      */
137     public function isEnabled()
138     {
139         return true;
140     }
141
142     /**
143      * Configures the current command.
144      */
145     protected function configure()
146     {
147     }
148
149     /**
150      * Executes the current command.
151      *
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.
156      *
157      * @param InputInterface  $input  An InputInterface instance
158      * @param OutputInterface $output An OutputInterface instance
159      *
160      * @return integer 0 if everything went fine, or an error code
161      *
162      * @throws \LogicException When this abstract method is not implemented
163      * @see    setCode()
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      * Interacts with the user.
172      *
173      * @param InputInterface  $input  An InputInterface instance
174      * @param OutputInterface $output An OutputInterface instance
175      */
176     protected function interact(InputInterface $input, OutputInterface $output)
177     {
178     }
179
180     /**
181      * Initializes the command just after the input has been validated.
182      *
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.
185      *
186      * @param InputInterface  $input  An InputInterface instance
187      * @param OutputInterface $output An OutputInterface instance
188      */
189     protected function initialize(InputInterface $input, OutputInterface $output)
190     {
191     }
192
193     /**
194      * Runs the command.
195      *
196      * The code to execute is either defined directly with the
197      * setCode() method or by overriding the execute() method
198      * in a sub-class.
199      *
200      * @param InputInterface  $input  An InputInterface instance
201      * @param OutputInterface $output An OutputInterface instance
202      *
203      * @return integer The command exit code
204      *
205      * @see setCode()
206      * @see execute()
207      *
208      * @api
209      */
210     public function run(InputInterface $input, OutputInterface $output)
211     {
212         // force the creation of the synopsis before the merge with the app definition
213         $this->getSynopsis();
214
215         // add the application arguments and options
216         $this->mergeApplicationDefinition();
217
218         // bind the input against the command specific arguments/options
219         try {
220             $input->bind($this->definition);
221         } catch (\Exception $e) {
222             if (!$this->ignoreValidationErrors) {
223                 throw $e;
224             }
225         }
226
227         $this->initialize($input, $output);
228
229         if ($input->isInteractive()) {
230             $this->interact($input, $output);
231         }
232
233         $input->validate();
234
235         if ($this->code) {
236             return call_user_func($this->code, $input, $output);
237         }
238
239         return $this->execute($input, $output);
240     }
241
242     /**
243      * Sets the code to execute when running this command.
244      *
245      * If this method is used, it overrides the code defined
246      * in the execute() method.
247      *
248      * @param \Closure $code A \Closure
249      *
250      * @return Command The current instance
251      *
252      * @see execute()
253      *
254      * @api
255      */
256     public function setCode(\Closure $code)
257     {
258         $this->code = $code;
259
260         return $this;
261     }
262
263     /**
264      * Merges the application definition with the command definition.
265      */
266     private function mergeApplicationDefinition()
267     {
268         if (null === $this->application || true === $this->applicationDefinitionMerged) {
269             return;
270         }
271
272         $currentArguments = $this->definition->getArguments();
273         $this->definition->setArguments($this->application->getDefinition()->getArguments());
274         $this->definition->addArguments($currentArguments);
275
276         $this->definition->addOptions($this->application->getDefinition()->getOptions());
277
278         $this->applicationDefinitionMerged = true;
279     }
280
281     /**
282      * Sets an array of argument and option instances.
283      *
284      * @param array|InputDefinition $definition An array of argument and option instances or a definition instance
285      *
286      * @return Command The current instance
287      *
288      * @api
289      */
290     public function setDefinition($definition)
291     {
292         if ($definition instanceof InputDefinition) {
293             $this->definition = $definition;
294         } else {
295             $this->definition->setDefinition($definition);
296         }
297
298         $this->applicationDefinitionMerged = false;
299
300         return $this;
301     }
302
303     /**
304      * Gets the InputDefinition attached to this Command.
305      *
306      * @return InputDefinition An InputDefinition instance
307      *
308      * @api
309      */
310     public function getDefinition()
311     {
312         return $this->definition;
313     }
314
315     /**
316      * Gets the InputDefinition to be used to create XML and Text representations of this Command.
317      *
318      * Can be overridden to provide the original command representation when it would otherwise
319      * be changed by merging with the application InputDefinition.
320      *
321      * @return InputDefinition An InputDefinition instance
322      */
323     protected function getNativeDefinition()
324     {
325         return $this->getDefinition();
326     }
327
328     /**
329      * Adds an argument.
330      *
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)
335      *
336      * @return Command The current instance
337      *
338      * @api
339      */
340     public function addArgument($name, $mode = null, $description = '', $default = null)
341     {
342         $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
343
344         return $this;
345     }
346
347     /**
348      * Adds an option.
349      *
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)
355      *
356      * @return Command The current instance
357      *
358      * @api
359      */
360     public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
361     {
362         $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
363
364         return $this;
365     }
366
367     /**
368      * Sets the name of the command.
369      *
370      * This method can set both the namespace and the name if
371      * you separate them by a colon (:)
372      *
373      *     $command->setName('foo:bar');
374      *
375      * @param string $name The command name
376      *
377      * @return Command The current instance
378      *
379      * @throws \InvalidArgumentException When command name given is empty
380      *
381      * @api
382      */
383     public function setName($name)
384     {
385         $this->validateName($name);
386
387         $this->name = $name;
388
389         return $this;
390     }
391
392     /**
393      * Returns the command name.
394      *
395      * @return string The command name
396      *
397      * @api
398      */
399     public function getName()
400     {
401         return $this->name;
402     }
403
404     /**
405      * Sets the description for the command.
406      *
407      * @param string $description The description for the command
408      *
409      * @return Command The current instance
410      *
411      * @api
412      */
413     public function setDescription($description)
414     {
415         $this->description = $description;
416
417         return $this;
418     }
419
420     /**
421      * Returns the description for the command.
422      *
423      * @return string The description for the command
424      *
425      * @api
426      */
427     public function getDescription()
428     {
429         return $this->description;
430     }
431
432     /**
433      * Sets the help for the command.
434      *
435      * @param string $help The help for the command
436      *
437      * @return Command The current instance
438      *
439      * @api
440      */
441     public function setHelp($help)
442     {
443         $this->help = $help;
444
445         return $this;
446     }
447
448     /**
449      * Returns the help for the command.
450      *
451      * @return string The help for the command
452      *
453      * @api
454      */
455     public function getHelp()
456     {
457         return $this->help;
458     }
459
460     /**
461      * Returns the processed help for the command replacing the %command.name% and
462      * %command.full_name% patterns with the real values dynamically.
463      *
464      * @return string  The processed help for the command
465      */
466     public function getProcessedHelp()
467     {
468         $name = $this->name;
469
470         $placeholders = array(
471             '%command.name%',
472             '%command.full_name%'
473         );
474         $replacements = array(
475             $name,
476             $_SERVER['PHP_SELF'].' '.$name
477         );
478
479         return str_replace($placeholders, $replacements, $this->getHelp());
480     }
481
482     /**
483      * Sets the aliases for the command.
484      *
485      * @param array $aliases An array of aliases for the command
486      *
487      * @return Command The current instance
488      *
489      * @api
490      */
491     public function setAliases($aliases)
492     {
493         foreach ($aliases as $alias) {
494             $this->validateName($alias);
495         }
496
497         $this->aliases = $aliases;
498
499         return $this;
500     }
501
502     /**
503      * Returns the aliases for the command.
504      *
505      * @return array An array of aliases for the command
506      *
507      * @api
508      */
509     public function getAliases()
510     {
511         return $this->aliases;
512     }
513
514     /**
515      * Returns the synopsis for the command.
516      *
517      * @return string The synopsis
518      */
519     public function getSynopsis()
520     {
521         if (null === $this->synopsis) {
522             $this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
523         }
524
525         return $this->synopsis;
526     }
527
528     /**
529      * Gets a helper instance by name.
530      *
531      * @param string $name The helper name
532      *
533      * @return mixed The helper value
534      *
535      * @throws \InvalidArgumentException if the helper is not defined
536      *
537      * @api
538      */
539     public function getHelper($name)
540     {
541         return $this->helperSet->get($name);
542     }
543
544     /**
545      * Returns a text representation of the command.
546      *
547      * @return string A string representing the command
548      */
549     public function asText()
550     {
551         $messages = array(
552             '<comment>Usage:</comment>',
553             ' '.$this->getSynopsis(),
554             '',
555         );
556
557         if ($this->getAliases()) {
558             $messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
559         }
560
561         $messages[] = $this->getNativeDefinition()->asText();
562
563         if ($help = $this->getProcessedHelp()) {
564             $messages[] = '<comment>Help:</comment>';
565             $messages[] = ' '.str_replace("\n", "\n ", $help)."\n";
566         }
567
568         return implode("\n", $messages);
569     }
570
571     /**
572      * Returns an XML representation of the command.
573      *
574      * @param Boolean $asDom Whether to return a DOM or an XML string
575      *
576      * @return string|DOMDocument An XML string representing the command
577      */
578     public function asXml($asDom = false)
579     {
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);
585
586         $commandXML->appendChild($usageXML = $dom->createElement('usage'));
587         $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
588
589         $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
590         $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getDescription())));
591
592         $commandXML->appendChild($helpXML = $dom->createElement('help'));
593         $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $this->getProcessedHelp())));
594
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));
599         }
600
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));
604
605         return $asDom ? $dom : $dom->saveXml();
606     }
607
608     private function validateName($name)
609     {
610         if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
611             throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
612         }
613     }
614 }