source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/Symfony/Component/Console/Command/Command.php @ 345

Last change on this file since 345 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 14.4 KB
Line 
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
12namespace Symfony\Component\Console\Command;
13
14use Symfony\Component\Console\Input\InputDefinition;
15use Symfony\Component\Console\Input\InputOption;
16use Symfony\Component\Console\Input\InputArgument;
17use Symfony\Component\Console\Input\InputInterface;
18use Symfony\Component\Console\Output\OutputInterface;
19use Symfony\Component\Console\Application;
20
21/**
22 * Base class for all commands.
23 *
24 * @author Fabien Potencier <fabien@symfony.com>
25 *
26 * @api
27 */
28class Command
29{
30    private $application;
31    private $name;
32    private $aliases;
33    private $definition;
34    private $help;
35    private $description;
36    private $ignoreValidationErrors;
37    private $applicationDefinitionMerged;
38    private $code;
39    private $synopsis;
40
41    /**
42     * Constructor.
43     *
44     * @param string $name The name of the command
45     *
46     * @throws \LogicException When the command name is empty
47     *
48     * @api
49     */
50    public function __construct($name = null)
51    {
52        $this->definition = new InputDefinition();
53        $this->ignoreValidationErrors = false;
54        $this->applicationDefinitionMerged = false;
55        $this->aliases = array();
56
57        if (null !== $name) {
58            $this->setName($name);
59        }
60
61        $this->configure();
62
63        if (!$this->name) {
64            throw new \LogicException('The command name cannot be empty.');
65        }
66    }
67
68    /**
69     * Sets the application instance for this command.
70     *
71     * @param Application $application An Application instance
72     *
73     * @api
74     */
75    public function setApplication(Application $application = null)
76    {
77        $this->application = $application;
78    }
79
80    /**
81     * Gets the application instance for this command.
82     *
83     * @return Application An Application instance
84     *
85     * @api
86     */
87    public function getApplication()
88    {
89        return $this->application;
90    }
91
92    /**
93     * Configures the current command.
94     */
95    protected function configure()
96    {
97    }
98
99    /**
100     * Executes the current command.
101     *
102     * This method is not abstract because you can use this class
103     * as a concrete class. In this case, instead of defining the
104     * execute() method, you set the code to execute by passing
105     * a Closure to the setCode() method.
106     *
107     * @param InputInterface  $input  An InputInterface instance
108     * @param OutputInterface $output An OutputInterface instance
109     *
110     * @return integer 0 if everything went fine, or an error code
111     *
112     * @throws \LogicException When this abstract method is not implemented
113     * @see    setCode()
114     */
115    protected function execute(InputInterface $input, OutputInterface $output)
116    {
117        throw new \LogicException('You must override the execute() method in the concrete command class.');
118    }
119
120    /**
121     * Interacts with the user.
122     *
123     * @param InputInterface  $input  An InputInterface instance
124     * @param OutputInterface $output An OutputInterface instance
125     */
126    protected function interact(InputInterface $input, OutputInterface $output)
127    {
128    }
129
130    /**
131     * Initializes the command just after the input has been validated.
132     *
133     * This is mainly useful when a lot of commands extends one main command
134     * where some things need to be initialized based on the input arguments and options.
135     *
136     * @param InputInterface  $input  An InputInterface instance
137     * @param OutputInterface $output An OutputInterface instance
138     */
139    protected function initialize(InputInterface $input, OutputInterface $output)
140    {
141    }
142
143    /**
144     * Runs the command.
145     *
146     * The code to execute is either defined directly with the
147     * setCode() method or by overriding the execute() method
148     * in a sub-class.
149     *
150     * @param InputInterface  $input  An InputInterface instance
151     * @param OutputInterface $output An OutputInterface instance
152     *
153     * @see setCode()
154     * @see execute()
155     *
156     * @api
157     */
158    public function run(InputInterface $input, OutputInterface $output)
159    {
160        // force the creation of the synopsis before the merge with the app definition
161        $this->getSynopsis();
162
163        // add the application arguments and options
164        $this->mergeApplicationDefinition();
165
166        // bind the input against the command specific arguments/options
167        try {
168            $input->bind($this->definition);
169        } catch (\Exception $e) {
170            if (!$this->ignoreValidationErrors) {
171                throw $e;
172            }
173        }
174
175        $this->initialize($input, $output);
176
177        if ($input->isInteractive()) {
178            $this->interact($input, $output);
179        }
180
181        $input->validate();
182
183        if ($this->code) {
184            return call_user_func($this->code, $input, $output);
185        }
186
187        return $this->execute($input, $output);
188    }
189
190    /**
191     * Sets the code to execute when running this command.
192     *
193     * If this method is used, it overrides the code defined
194     * in the execute() method.
195     *
196     * @param \Closure $code A \Closure
197     *
198     * @return Command The current instance
199     *
200     * @see execute()
201     *
202     * @api
203     */
204    public function setCode(\Closure $code)
205    {
206        $this->code = $code;
207
208        return $this;
209    }
210
211    /**
212     * Merges the application definition with the command definition.
213     */
214    private function mergeApplicationDefinition()
215    {
216        if (null === $this->application || true === $this->applicationDefinitionMerged) {
217            return;
218        }
219
220        $this->definition->setArguments(array_merge(
221            $this->application->getDefinition()->getArguments(),
222            $this->definition->getArguments()
223        ));
224
225        $this->definition->addOptions($this->application->getDefinition()->getOptions());
226
227        $this->applicationDefinitionMerged = true;
228    }
229
230    /**
231     * Sets an array of argument and option instances.
232     *
233     * @param array|Definition $definition An array of argument and option instances or a definition instance
234     *
235     * @return Command The current instance
236     *
237     * @api
238     */
239    public function setDefinition($definition)
240    {
241        if ($definition instanceof InputDefinition) {
242            $this->definition = $definition;
243        } else {
244            $this->definition->setDefinition($definition);
245        }
246
247        $this->applicationDefinitionMerged = false;
248
249        return $this;
250    }
251
252    /**
253     * Gets the InputDefinition attached to this Command.
254     *
255     * @return InputDefinition An InputDefinition instance
256     *
257     * @api
258     */
259    public function getDefinition()
260    {
261        return $this->definition;
262    }
263
264    /**
265     * Adds an argument.
266     *
267     * @param string  $name        The argument name
268     * @param integer $mode        The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
269     * @param string  $description A description text
270     * @param mixed   $default     The default value (for InputArgument::OPTIONAL mode only)
271     *
272     * @return Command The current instance
273     *
274     * @api
275     */
276    public function addArgument($name, $mode = null, $description = '', $default = null)
277    {
278        $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
279
280        return $this;
281    }
282
283    /**
284     * Adds an option.
285     *
286     * @param string  $name        The option name
287     * @param string  $shortcut    The shortcut (can be null)
288     * @param integer $mode        The option mode: One of the InputOption::VALUE_* constants
289     * @param string  $description A description text
290     * @param mixed   $default     The default value (must be null for InputOption::VALUE_REQUIRED or self::VALUE_NONE)
291     *
292     * @return Command The current instance
293     *
294     * @api
295     */
296    public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
297    {
298        $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
299
300        return $this;
301    }
302
303    /**
304     * Sets the name of the command.
305     *
306     * This method can set both the namespace and the name if
307     * you separate them by a colon (:)
308     *
309     *     $command->setName('foo:bar');
310     *
311     * @param string $name The command name
312     *
313     * @return Command The current instance
314     *
315     * @throws \InvalidArgumentException When command name given is empty
316     *
317     * @api
318     */
319    public function setName($name)
320    {
321        $this->validateName($name);
322
323        $this->name = $name;
324
325        return $this;
326    }
327
328    /**
329     * Returns the command name.
330     *
331     * @return string The command name
332     *
333     * @api
334     */
335    public function getName()
336    {
337        return $this->name;
338    }
339
340    /**
341     * Sets the description for the command.
342     *
343     * @param string $description The description for the command
344     *
345     * @return Command The current instance
346     *
347     * @api
348     */
349    public function setDescription($description)
350    {
351        $this->description = $description;
352
353        return $this;
354    }
355
356    /**
357     * Returns the description for the command.
358     *
359     * @return string The description for the command
360     *
361     * @api
362     */
363    public function getDescription()
364    {
365        return $this->description;
366    }
367
368    /**
369     * Sets the help for the command.
370     *
371     * @param string $help The help for the command
372     *
373     * @return Command The current instance
374     *
375     * @api
376     */
377    public function setHelp($help)
378    {
379        $this->help = $help;
380
381        return $this;
382    }
383
384    /**
385     * Returns the help for the command.
386     *
387     * @return string The help for the command
388     *
389     * @api
390     */
391    public function getHelp()
392    {
393        return $this->help;
394    }
395
396    /**
397     * Returns the processed help for the command replacing the %command.name% and
398     * %command.full_name% patterns with the real values dynamically.
399     *
400     * @return string  The processed help for the command
401     */
402    public function getProcessedHelp()
403    {
404        $name = $this->name;
405
406        $placeholders = array(
407            '%command.name%',
408            '%command.full_name%'
409        );
410        $replacements = array(
411            $name,
412            $_SERVER['PHP_SELF'].' '.$name
413        );
414
415        return str_replace($placeholders, $replacements, $this->getHelp());
416    }
417
418    /**
419     * Sets the aliases for the command.
420     *
421     * @param array $aliases An array of aliases for the command
422     *
423     * @return Command The current instance
424     *
425     * @api
426     */
427    public function setAliases($aliases)
428    {
429        foreach ($aliases as $alias) {
430            $this->validateName($alias);
431        }
432
433        $this->aliases = $aliases;
434
435        return $this;
436    }
437
438    /**
439     * Returns the aliases for the command.
440     *
441     * @return array An array of aliases for the command
442     *
443     * @api
444     */
445    public function getAliases()
446    {
447        return $this->aliases;
448    }
449
450    /**
451     * Returns the synopsis for the command.
452     *
453     * @return string The synopsis
454     */
455    public function getSynopsis()
456    {
457        if (null === $this->synopsis) {
458            $this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
459        }
460
461        return $this->synopsis;
462    }
463
464    /**
465     * Gets a helper instance by name.
466     *
467     * @param string $name The helper name
468     *
469     * @return mixed The helper value
470     *
471     * @throws \InvalidArgumentException if the helper is not defined
472     *
473     * @api
474     */
475    public function getHelper($name)
476    {
477        return $this->application->getHelperSet()->get($name);
478    }
479
480    /**
481     * Returns a text representation of the command.
482     *
483     * @return string A string representing the command
484     */
485    public function asText()
486    {
487        $messages = array(
488            '<comment>Usage:</comment>',
489            ' '.$this->getSynopsis(),
490            '',
491        );
492
493        if ($this->getAliases()) {
494            $messages[] = '<comment>Aliases:</comment> <info>'.implode(', ', $this->getAliases()).'</info>';
495        }
496
497        $messages[] = $this->definition->asText();
498
499        if ($help = $this->getProcessedHelp()) {
500            $messages[] = '<comment>Help:</comment>';
501            $messages[] = ' '.implode("\n ", explode("\n", $help))."\n";
502        }
503
504        return implode("\n", $messages);
505    }
506
507    /**
508     * Returns an XML representation of the command.
509     *
510     * @param Boolean $asDom Whether to return a DOM or an XML string
511     *
512     * @return string|DOMDocument An XML string representing the command
513     */
514    public function asXml($asDom = false)
515    {
516        $dom = new \DOMDocument('1.0', 'UTF-8');
517        $dom->formatOutput = true;
518        $dom->appendChild($commandXML = $dom->createElement('command'));
519        $commandXML->setAttribute('id', $this->name);
520        $commandXML->setAttribute('name', $this->name);
521
522        $commandXML->appendChild($usageXML = $dom->createElement('usage'));
523        $usageXML->appendChild($dom->createTextNode(sprintf($this->getSynopsis(), '')));
524
525        $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
526        $descriptionXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $this->getDescription()))));
527
528        $commandXML->appendChild($helpXML = $dom->createElement('help'));
529        $help = $this->help;
530        $helpXML->appendChild($dom->createTextNode(implode("\n ", explode("\n", $help))));
531
532        $commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
533        foreach ($this->getAliases() as $alias) {
534            $aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
535            $aliasXML->appendChild($dom->createTextNode($alias));
536        }
537
538        $definition = $this->definition->asXml(true);
539        $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('arguments')->item(0), true));
540        $commandXML->appendChild($dom->importNode($definition->getElementsByTagName('options')->item(0), true));
541
542        return $asDom ? $dom : $dom->saveXml();
543    }
544
545    private function validateName($name)
546    {
547        if (!preg_match('/^[^\:]+(\:[^\:]+)*$/', $name)) {
548            throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
549        }
550    }
551}
Note: See TracBrowser for help on using the repository browser.