Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Command.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 19.13 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\Console\Command;
013   
014  use Symfony\Component\Console\Application;
015  use Symfony\Component\Console\Exception\ExceptionInterface;
016  use Symfony\Component\Console\Exception\InvalidArgumentException;
017  use Symfony\Component\Console\Exception\LogicException;
018  use Symfony\Component\Console\Helper\HelperSet;
019  use Symfony\Component\Console\Input\InputArgument;
020  use Symfony\Component\Console\Input\InputDefinition;
021  use Symfony\Component\Console\Input\InputInterface;
022  use Symfony\Component\Console\Input\InputOption;
023  use Symfony\Component\Console\Output\OutputInterface;
024   
025  /**
026   * Base class for all commands.
027   *
028   * @author Fabien Potencier <fabien@symfony.com>
029   */
030  class Command
031  {
032      /**
033       * @var string|null The default command name
034       */
035      protected static $defaultName;
036   
037      private $application;
038      private $name;
039      private $processTitle;
040      private $aliases = [];
041      private $definition;
042      private $hidden = false;
043      private $help = '';
044      private $description = '';
045      private $ignoreValidationErrors = false;
046      private $applicationDefinitionMerged = false;
047      private $applicationDefinitionMergedWithArgs = false;
048      private $code;
049      private $synopsis = [];
050      private $usages = [];
051      private $helperSet;
052   
053      /**
054       * @return string|null The default command name or null when no default name is set
055       */
056      public static function getDefaultName()
057      {
058          $class = static::class;
059          $r = new \ReflectionProperty($class, 'defaultName');
060   
061          return $class === $r->class ? static::$defaultName : null;
062      }
063   
064      /**
065       * @param string|null $name The name of the command; passing null means it must be set in configure()
066       *
067       * @throws LogicException When the command name is empty
068       */
069      public function __construct($name = null)
070      {
071          $this->definition = new InputDefinition();
072   
073          if (null !== $name || null !== $name = static::getDefaultName()) {
074              $this->setName($name);
075          }
076   
077          $this->configure();
078      }
079   
080      /**
081       * Ignores validation errors.
082       *
083       * This is mainly useful for the help command.
084       */
085      public function ignoreValidationErrors()
086      {
087          $this->ignoreValidationErrors = true;
088      }
089   
090      public function setApplication(Application $application = null)
091      {
092          $this->application = $application;
093          if ($application) {
094              $this->setHelperSet($application->getHelperSet());
095          } else {
096              $this->helperSet = null;
097          }
098      }
099   
100      public function setHelperSet(HelperSet $helperSet)
101      {
102          $this->helperSet = $helperSet;
103      }
104   
105      /**
106       * Gets the helper set.
107       *
108       * @return HelperSet|null A HelperSet instance
109       */
110      public function getHelperSet()
111      {
112          return $this->helperSet;
113      }
114   
115      /**
116       * Gets the application instance for this command.
117       *
118       * @return Application|null An Application instance
119       */
120      public function getApplication()
121      {
122          return $this->application;
123      }
124   
125      /**
126       * Checks whether the command is enabled or not in the current environment.
127       *
128       * Override this to check for x or y and return false if the command can not
129       * run properly under the current conditions.
130       *
131       * @return bool
132       */
133      public function isEnabled()
134      {
135          return true;
136      }
137   
138      /**
139       * Configures the current command.
140       */
141      protected function configure()
142      {
143      }
144   
145      /**
146       * Executes the current command.
147       *
148       * This method is not abstract because you can use this class
149       * as a concrete class. In this case, instead of defining the
150       * execute() method, you set the code to execute by passing
151       * a Closure to the setCode() method.
152       *
153       * @return int|null null or 0 if everything went fine, or an error code
154       *
155       * @throws LogicException When this abstract method is not implemented
156       *
157       * @see setCode()
158       */
159      protected function execute(InputInterface $input, OutputInterface $output)
160      {
161          throw new LogicException('You must override the execute() method in the concrete command class.');
162      }
163   
164      /**
165       * Interacts with the user.
166       *
167       * This method is executed before the InputDefinition is validated.
168       * This means that this is the only place where the command can
169       * interactively ask for values of missing required arguments.
170       */
171      protected function interact(InputInterface $input, OutputInterface $output)
172      {
173      }
174   
175      /**
176       * Initializes the command after the input has been bound and before the input
177       * is validated.
178       *
179       * This is mainly useful when a lot of commands extends one main command
180       * where some things need to be initialized based on the input arguments and options.
181       *
182       * @see InputInterface::bind()
183       * @see InputInterface::validate()
184       */
185      protected function initialize(InputInterface $input, OutputInterface $output)
186      {
187      }
188   
189      /**
190       * Runs the command.
191       *
192       * The code to execute is either defined directly with the
193       * setCode() method or by overriding the execute() method
194       * in a sub-class.
195       *
196       * @return int The command exit code
197       *
198       * @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}.
199       *
200       * @see setCode()
201       * @see execute()
202       */
203      public function run(InputInterface $input, OutputInterface $output)
204      {
205          // force the creation of the synopsis before the merge with the app definition
206          $this->getSynopsis(true);
207          $this->getSynopsis(false);
208   
209          // add the application arguments and options
210          $this->mergeApplicationDefinition();
211   
212          // bind the input against the command specific arguments/options
213          try {
214              $input->bind($this->definition);
215          } catch (ExceptionInterface $e) {
216              if (!$this->ignoreValidationErrors) {
217                  throw $e;
218              }
219          }
220   
221          $this->initialize($input, $output);
222   
223          if (null !== $this->processTitle) {
224              if (\function_exists('cli_set_process_title')) {
225                  if (!@cli_set_process_title($this->processTitle)) {
226                      if ('Darwin' === \PHP_OS) {
227                          $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
228                      } else {
229                          cli_set_process_title($this->processTitle);
230                      }
231                  }
232              } elseif (\function_exists('setproctitle')) {
233                  setproctitle($this->processTitle);
234              } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
235                  $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
236              }
237          }
238   
239          if ($input->isInteractive()) {
240              $this->interact($input, $output);
241          }
242   
243          // The command name argument is often omitted when a command is executed directly with its run() method.
244          // It would fail the validation if we didn't make sure the command argument is present,
245          // since it's required by the application.
246          if ($input->hasArgument('command') && null === $input->getArgument('command')) {
247              $input->setArgument('command', $this->getName());
248          }
249   
250          $input->validate();
251   
252          if ($this->code) {
253              $statusCode = \call_user_func($this->code, $input, $output);
254          } else {
255              $statusCode = $this->execute($input, $output);
256          }
257   
258          return is_numeric($statusCode) ? (int) $statusCode : 0;
259      }
260   
261      /**
262       * Sets the code to execute when running this command.
263       *
264       * If this method is used, it overrides the code defined
265       * in the execute() method.
266       *
267       * @param callable $code A callable(InputInterface $input, OutputInterface $output)
268       *
269       * @return $this
270       *
271       * @throws InvalidArgumentException
272       *
273       * @see execute()
274       */
275      public function setCode(callable $code)
276      {
277          if ($code instanceof \Closure) {
278              $r = new \ReflectionFunction($code);
279              if (null === $r->getClosureThis()) {
280                  if (\PHP_VERSION_ID < 70000) {
281                      // Bug in PHP5: https://bugs.php.net/64761
282                      // This means that we cannot bind static closures and therefore we must
283                      // ignore any errors here.  There is no way to test if the closure is
284                      // bindable.
285                      $code = @\Closure::bind($code, $this);
286                  } else {
287                      $code = \Closure::bind($code, $this);
288                  }
289              }
290          }
291   
292          $this->code = $code;
293   
294          return $this;
295      }
296   
297      /**
298       * Merges the application definition with the command definition.
299       *
300       * This method is not part of public API and should not be used directly.
301       *
302       * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments
303       */
304      public function mergeApplicationDefinition($mergeArgs = true)
305      {
306          if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
307              return;
308          }
309   
310          $this->definition->addOptions($this->application->getDefinition()->getOptions());
311   
312          $this->applicationDefinitionMerged = true;
313   
314          if ($mergeArgs) {
315              $currentArguments = $this->definition->getArguments();
316              $this->definition->setArguments($this->application->getDefinition()->getArguments());
317              $this->definition->addArguments($currentArguments);
318   
319              $this->applicationDefinitionMergedWithArgs = true;
320          }
321      }
322   
323      /**
324       * Sets an array of argument and option instances.
325       *
326       * @param array|InputDefinition $definition An array of argument and option instances or a definition instance
327       *
328       * @return $this
329       */
330      public function setDefinition($definition)
331      {
332          if ($definition instanceof InputDefinition) {
333              $this->definition = $definition;
334          } else {
335              $this->definition->setDefinition($definition);
336          }
337   
338          $this->applicationDefinitionMerged = false;
339   
340          return $this;
341      }
342   
343      /**
344       * Gets the InputDefinition attached to this Command.
345       *
346       * @return InputDefinition An InputDefinition instance
347       */
348      public function getDefinition()
349      {
350          if (null === $this->definition) {
351              throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
352          }
353   
354          return $this->definition;
355      }
356   
357      /**
358       * Gets the InputDefinition to be used to create representations of this Command.
359       *
360       * Can be overridden to provide the original command representation when it would otherwise
361       * be changed by merging with the application InputDefinition.
362       *
363       * This method is not part of public API and should not be used directly.
364       *
365       * @return InputDefinition An InputDefinition instance
366       */
367      public function getNativeDefinition()
368      {
369          return $this->getDefinition();
370      }
371   
372      /**
373       * Adds an argument.
374       *
375       * @param string               $name        The argument name
376       * @param int|null             $mode        The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
377       * @param string               $description A description text
378       * @param string|string[]|null $default     The default value (for InputArgument::OPTIONAL mode only)
379       *
380       * @throws InvalidArgumentException When argument mode is not valid
381       *
382       * @return $this
383       */
384      public function addArgument($name, $mode = null, $description = '', $default = null)
385      {
386          $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
387   
388          return $this;
389      }
390   
391      /**
392       * Adds an option.
393       *
394       * @param string                        $name        The option name
395       * @param string|array|null             $shortcut    The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
396       * @param int|null                      $mode        The option mode: One of the InputOption::VALUE_* constants
397       * @param string                        $description A description text
398       * @param string|string[]|int|bool|null $default     The default value (must be null for InputOption::VALUE_NONE)
399       *
400       * @throws InvalidArgumentException If option mode is invalid or incompatible
401       *
402       * @return $this
403       */
404      public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
405      {
406          $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
407   
408          return $this;
409      }
410   
411      /**
412       * Sets the name of the command.
413       *
414       * This method can set both the namespace and the name if
415       * you separate them by a colon (:)
416       *
417       *     $command->setName('foo:bar');
418       *
419       * @param string $name The command name
420       *
421       * @return $this
422       *
423       * @throws InvalidArgumentException When the name is invalid
424       */
425      public function setName($name)
426      {
427          $this->validateName($name);
428   
429          $this->name = $name;
430   
431          return $this;
432      }
433   
434      /**
435       * Sets the process title of the command.
436       *
437       * This feature should be used only when creating a long process command,
438       * like a daemon.
439       *
440       * @param string $title The process title
441       *
442       * @return $this
443       */
444      public function setProcessTitle($title)
445      {
446          $this->processTitle = $title;
447   
448          return $this;
449      }
450   
451      /**
452       * Returns the command name.
453       *
454       * @return string|null
455       */
456      public function getName()
457      {
458          return $this->name;
459      }
460   
461      /**
462       * @param bool $hidden Whether or not the command should be hidden from the list of commands
463       *
464       * @return Command The current instance
465       */
466      public function setHidden($hidden)
467      {
468          $this->hidden = (bool) $hidden;
469   
470          return $this;
471      }
472   
473      /**
474       * @return bool whether the command should be publicly shown or not
475       */
476      public function isHidden()
477      {
478          return $this->hidden;
479      }
480   
481      /**
482       * Sets the description for the command.
483       *
484       * @param string $description The description for the command
485       *
486       * @return $this
487       */
488      public function setDescription($description)
489      {
490          $this->description = $description;
491   
492          return $this;
493      }
494   
495      /**
496       * Returns the description for the command.
497       *
498       * @return string The description for the command
499       */
500      public function getDescription()
501      {
502          return $this->description;
503      }
504   
505      /**
506       * Sets the help for the command.
507       *
508       * @param string $help The help for the command
509       *
510       * @return $this
511       */
512      public function setHelp($help)
513      {
514          $this->help = $help;
515   
516          return $this;
517      }
518   
519      /**
520       * Returns the help for the command.
521       *
522       * @return string The help for the command
523       */
524      public function getHelp()
525      {
526          return $this->help;
527      }
528   
529      /**
530       * Returns the processed help for the command replacing the %command.name% and
531       * %command.full_name% patterns with the real values dynamically.
532       *
533       * @return string The processed help for the command
534       */
535      public function getProcessedHelp()
536      {
537          $name = $this->name;
538          $isSingleCommand = $this->application && $this->application->isSingleCommand();
539   
540          $placeholders = [
541              '%command.name%',
542              '%command.full_name%',
543          ];
544          $replacements = [
545              $name,
546              $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
547          ];
548   
549          return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
550      }
551   
552      /**
553       * Sets the aliases for the command.
554       *
555       * @param string[] $aliases An array of aliases for the command
556       *
557       * @return $this
558       *
559       * @throws InvalidArgumentException When an alias is invalid
560       */
561      public function setAliases($aliases)
562      {
563          if (!\is_array($aliases) && !$aliases instanceof \Traversable) {
564              throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable.');
565          }
566   
567          foreach ($aliases as $alias) {
568              $this->validateName($alias);
569          }
570   
571          $this->aliases = $aliases;
572   
573          return $this;
574      }
575   
576      /**
577       * Returns the aliases for the command.
578       *
579       * @return array An array of aliases for the command
580       */
581      public function getAliases()
582      {
583          return $this->aliases;
584      }
585   
586      /**
587       * Returns the synopsis for the command.
588       *
589       * @param bool $short Whether to show the short version of the synopsis (with options folded) or not
590       *
591       * @return string The synopsis
592       */
593      public function getSynopsis($short = false)
594      {
595          $key = $short ? 'short' : 'long';
596   
597          if (!isset($this->synopsis[$key])) {
598              $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
599          }
600   
601          return $this->synopsis[$key];
602      }
603   
604      /**
605       * Add a command usage example.
606       *
607       * @param string $usage The usage, it'll be prefixed with the command name
608       *
609       * @return $this
610       */
611      public function addUsage($usage)
612      {
613          if (0 !== strpos($usage, $this->name)) {
614              $usage = sprintf('%s %s', $this->name, $usage);
615          }
616   
617          $this->usages[] = $usage;
618   
619          return $this;
620      }
621   
622      /**
623       * Returns alternative usages of the command.
624       *
625       * @return array
626       */
627      public function getUsages()
628      {
629          return $this->usages;
630      }
631   
632      /**
633       * Gets a helper instance by name.
634       *
635       * @param string $name The helper name
636       *
637       * @return mixed The helper value
638       *
639       * @throws LogicException           if no HelperSet is defined
640       * @throws InvalidArgumentException if the helper is not defined
641       */
642      public function getHelper($name)
643      {
644          if (null === $this->helperSet) {
645              throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
646          }
647   
648          return $this->helperSet->get($name);
649      }
650   
651      /**
652       * Validates a command name.
653       *
654       * It must be non-empty and parts can optionally be separated by ":".
655       *
656       * @param string $name
657       *
658       * @throws InvalidArgumentException When the name is invalid
659       */
660      private function validateName($name)
661      {
662          if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
663              throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
664          }
665      }
666  }
667