[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/symfony/console/Command/ -> Command.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <[email protected]>
   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\Application;
  15  use Symfony\Component\Console\Attribute\AsCommand;
  16  use Symfony\Component\Console\Completion\CompletionInput;
  17  use Symfony\Component\Console\Completion\CompletionSuggestions;
  18  use Symfony\Component\Console\Exception\ExceptionInterface;
  19  use Symfony\Component\Console\Exception\InvalidArgumentException;
  20  use Symfony\Component\Console\Exception\LogicException;
  21  use Symfony\Component\Console\Helper\HelperSet;
  22  use Symfony\Component\Console\Input\InputArgument;
  23  use Symfony\Component\Console\Input\InputDefinition;
  24  use Symfony\Component\Console\Input\InputInterface;
  25  use Symfony\Component\Console\Input\InputOption;
  26  use Symfony\Component\Console\Output\OutputInterface;
  27  
  28  /**
  29   * Base class for all commands.
  30   *
  31   * @author Fabien Potencier <[email protected]>
  32   */
  33  class Command
  34  {
  35      // see https://tldp.org/LDP/abs/html/exitcodes.html
  36      public const SUCCESS = 0;
  37      public const FAILURE = 1;
  38      public const INVALID = 2;
  39  
  40      /**
  41       * @var string|null The default command name
  42       */
  43      protected static $defaultName;
  44  
  45      /**
  46       * @var string|null The default command description
  47       */
  48      protected static $defaultDescription;
  49  
  50      private $application;
  51      private $name;
  52      private $processTitle;
  53      private $aliases = [];
  54      private $definition;
  55      private $hidden = false;
  56      private $help = '';
  57      private $description = '';
  58      private $fullDefinition;
  59      private $ignoreValidationErrors = false;
  60      private $code;
  61      private $synopsis = [];
  62      private $usages = [];
  63      private $helperSet;
  64  
  65      /**
  66       * @return string|null
  67       */
  68      public static function getDefaultName()
  69      {
  70          $class = static::class;
  71  
  72          if (\PHP_VERSION_ID >= 80000 && $attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
  73              return $attribute[0]->newInstance()->name;
  74          }
  75  
  76          $r = new \ReflectionProperty($class, 'defaultName');
  77  
  78          return $class === $r->class ? static::$defaultName : null;
  79      }
  80  
  81      public static function getDefaultDescription(): ?string
  82      {
  83          $class = static::class;
  84  
  85          if (\PHP_VERSION_ID >= 80000 && $attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
  86              return $attribute[0]->newInstance()->description;
  87          }
  88  
  89          $r = new \ReflectionProperty($class, 'defaultDescription');
  90  
  91          return $class === $r->class ? static::$defaultDescription : null;
  92      }
  93  
  94      /**
  95       * @param string|null $name The name of the command; passing null means it must be set in configure()
  96       *
  97       * @throws LogicException When the command name is empty
  98       */
  99      public function __construct(string $name = null)
 100      {
 101          $this->definition = new InputDefinition();
 102  
 103          if (null === $name && null !== $name = static::getDefaultName()) {
 104              $aliases = explode('|', $name);
 105  
 106              if ('' === $name = array_shift($aliases)) {
 107                  $this->setHidden(true);
 108                  $name = array_shift($aliases);
 109              }
 110  
 111              $this->setAliases($aliases);
 112          }
 113  
 114          if (null !== $name) {
 115              $this->setName($name);
 116          }
 117  
 118          if ('' === $this->description) {
 119              $this->setDescription(static::getDefaultDescription() ?? '');
 120          }
 121  
 122          $this->configure();
 123      }
 124  
 125      /**
 126       * Ignores validation errors.
 127       *
 128       * This is mainly useful for the help command.
 129       */
 130      public function ignoreValidationErrors()
 131      {
 132          $this->ignoreValidationErrors = true;
 133      }
 134  
 135      public function setApplication(Application $application = null)
 136      {
 137          $this->application = $application;
 138          if ($application) {
 139              $this->setHelperSet($application->getHelperSet());
 140          } else {
 141              $this->helperSet = null;
 142          }
 143  
 144          $this->fullDefinition = null;
 145      }
 146  
 147      public function setHelperSet(HelperSet $helperSet)
 148      {
 149          $this->helperSet = $helperSet;
 150      }
 151  
 152      /**
 153       * Gets the helper set.
 154       *
 155       * @return HelperSet|null
 156       */
 157      public function getHelperSet()
 158      {
 159          return $this->helperSet;
 160      }
 161  
 162      /**
 163       * Gets the application instance for this command.
 164       *
 165       * @return Application|null
 166       */
 167      public function getApplication()
 168      {
 169          return $this->application;
 170      }
 171  
 172      /**
 173       * Checks whether the command is enabled or not in the current environment.
 174       *
 175       * Override this to check for x or y and return false if the command cannot
 176       * run properly under the current conditions.
 177       *
 178       * @return bool
 179       */
 180      public function isEnabled()
 181      {
 182          return true;
 183      }
 184  
 185      /**
 186       * Configures the current command.
 187       */
 188      protected function configure()
 189      {
 190      }
 191  
 192      /**
 193       * Executes the current command.
 194       *
 195       * This method is not abstract because you can use this class
 196       * as a concrete class. In this case, instead of defining the
 197       * execute() method, you set the code to execute by passing
 198       * a Closure to the setCode() method.
 199       *
 200       * @return int 0 if everything went fine, or an exit code
 201       *
 202       * @throws LogicException When this abstract method is not implemented
 203       *
 204       * @see setCode()
 205       */
 206      protected function execute(InputInterface $input, OutputInterface $output)
 207      {
 208          throw new LogicException('You must override the execute() method in the concrete command class.');
 209      }
 210  
 211      /**
 212       * Interacts with the user.
 213       *
 214       * This method is executed before the InputDefinition is validated.
 215       * This means that this is the only place where the command can
 216       * interactively ask for values of missing required arguments.
 217       */
 218      protected function interact(InputInterface $input, OutputInterface $output)
 219      {
 220      }
 221  
 222      /**
 223       * Initializes the command after the input has been bound and before the input
 224       * is validated.
 225       *
 226       * This is mainly useful when a lot of commands extends one main command
 227       * where some things need to be initialized based on the input arguments and options.
 228       *
 229       * @see InputInterface::bind()
 230       * @see InputInterface::validate()
 231       */
 232      protected function initialize(InputInterface $input, OutputInterface $output)
 233      {
 234      }
 235  
 236      /**
 237       * Runs the command.
 238       *
 239       * The code to execute is either defined directly with the
 240       * setCode() method or by overriding the execute() method
 241       * in a sub-class.
 242       *
 243       * @return int The command exit code
 244       *
 245       * @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}.
 246       *
 247       * @see setCode()
 248       * @see execute()
 249       */
 250      public function run(InputInterface $input, OutputInterface $output)
 251      {
 252          // add the application arguments and options
 253          $this->mergeApplicationDefinition();
 254  
 255          // bind the input against the command specific arguments/options
 256          try {
 257              $input->bind($this->getDefinition());
 258          } catch (ExceptionInterface $e) {
 259              if (!$this->ignoreValidationErrors) {
 260                  throw $e;
 261              }
 262          }
 263  
 264          $this->initialize($input, $output);
 265  
 266          if (null !== $this->processTitle) {
 267              if (\function_exists('cli_set_process_title')) {
 268                  if (!@cli_set_process_title($this->processTitle)) {
 269                      if ('Darwin' === \PHP_OS) {
 270                          $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
 271                      } else {
 272                          cli_set_process_title($this->processTitle);
 273                      }
 274                  }
 275              } elseif (\function_exists('setproctitle')) {
 276                  setproctitle($this->processTitle);
 277              } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
 278                  $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
 279              }
 280          }
 281  
 282          if ($input->isInteractive()) {
 283              $this->interact($input, $output);
 284          }
 285  
 286          // The command name argument is often omitted when a command is executed directly with its run() method.
 287          // It would fail the validation if we didn't make sure the command argument is present,
 288          // since it's required by the application.
 289          if ($input->hasArgument('command') && null === $input->getArgument('command')) {
 290              $input->setArgument('command', $this->getName());
 291          }
 292  
 293          $input->validate();
 294  
 295          if ($this->code) {
 296              $statusCode = ($this->code)($input, $output);
 297          } else {
 298              $statusCode = $this->execute($input, $output);
 299  
 300              if (!\is_int($statusCode)) {
 301                  throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode)));
 302              }
 303          }
 304  
 305          return is_numeric($statusCode) ? (int) $statusCode : 0;
 306      }
 307  
 308      /**
 309       * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).
 310       */
 311      public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
 312      {
 313      }
 314  
 315      /**
 316       * Sets the code to execute when running this command.
 317       *
 318       * If this method is used, it overrides the code defined
 319       * in the execute() method.
 320       *
 321       * @param callable $code A callable(InputInterface $input, OutputInterface $output)
 322       *
 323       * @return $this
 324       *
 325       * @throws InvalidArgumentException
 326       *
 327       * @see execute()
 328       */
 329      public function setCode(callable $code)
 330      {
 331          if ($code instanceof \Closure) {
 332              $r = new \ReflectionFunction($code);
 333              if (null === $r->getClosureThis()) {
 334                  set_error_handler(static function () {});
 335                  try {
 336                      if ($c = \Closure::bind($code, $this)) {
 337                          $code = $c;
 338                      }
 339                  } finally {
 340                      restore_error_handler();
 341                  }
 342              }
 343          }
 344  
 345          $this->code = $code;
 346  
 347          return $this;
 348      }
 349  
 350      /**
 351       * Merges the application definition with the command definition.
 352       *
 353       * This method is not part of public API and should not be used directly.
 354       *
 355       * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments
 356       *
 357       * @internal
 358       */
 359      public function mergeApplicationDefinition(bool $mergeArgs = true)
 360      {
 361          if (null === $this->application) {
 362              return;
 363          }
 364  
 365          $this->fullDefinition = new InputDefinition();
 366          $this->fullDefinition->setOptions($this->definition->getOptions());
 367          $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions());
 368  
 369          if ($mergeArgs) {
 370              $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments());
 371              $this->fullDefinition->addArguments($this->definition->getArguments());
 372          } else {
 373              $this->fullDefinition->setArguments($this->definition->getArguments());
 374          }
 375      }
 376  
 377      /**
 378       * Sets an array of argument and option instances.
 379       *
 380       * @param array|InputDefinition $definition An array of argument and option instances or a definition instance
 381       *
 382       * @return $this
 383       */
 384      public function setDefinition($definition)
 385      {
 386          if ($definition instanceof InputDefinition) {
 387              $this->definition = $definition;
 388          } else {
 389              $this->definition->setDefinition($definition);
 390          }
 391  
 392          $this->fullDefinition = null;
 393  
 394          return $this;
 395      }
 396  
 397      /**
 398       * Gets the InputDefinition attached to this Command.
 399       *
 400       * @return InputDefinition
 401       */
 402      public function getDefinition()
 403      {
 404          return $this->fullDefinition ?? $this->getNativeDefinition();
 405      }
 406  
 407      /**
 408       * Gets the InputDefinition to be used to create representations of this Command.
 409       *
 410       * Can be overridden to provide the original command representation when it would otherwise
 411       * be changed by merging with the application InputDefinition.
 412       *
 413       * This method is not part of public API and should not be used directly.
 414       *
 415       * @return InputDefinition
 416       */
 417      public function getNativeDefinition()
 418      {
 419          if (null === $this->definition) {
 420              throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
 421          }
 422  
 423          return $this->definition;
 424      }
 425  
 426      /**
 427       * Adds an argument.
 428       *
 429       * @param int|null $mode    The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
 430       * @param mixed    $default The default value (for InputArgument::OPTIONAL mode only)
 431       *
 432       * @throws InvalidArgumentException When argument mode is not valid
 433       *
 434       * @return $this
 435       */
 436      public function addArgument(string $name, int $mode = null, string $description = '', $default = null)
 437      {
 438          $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
 439          if (null !== $this->fullDefinition) {
 440              $this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default));
 441          }
 442  
 443          return $this;
 444      }
 445  
 446      /**
 447       * Adds an option.
 448       *
 449       * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
 450       * @param int|null          $mode     The option mode: One of the InputOption::VALUE_* constants
 451       * @param mixed             $default  The default value (must be null for InputOption::VALUE_NONE)
 452       *
 453       * @throws InvalidArgumentException If option mode is invalid or incompatible
 454       *
 455       * @return $this
 456       */
 457      public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
 458      {
 459          $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
 460          if (null !== $this->fullDefinition) {
 461              $this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
 462          }
 463  
 464          return $this;
 465      }
 466  
 467      /**
 468       * Sets the name of the command.
 469       *
 470       * This method can set both the namespace and the name if
 471       * you separate them by a colon (:)
 472       *
 473       *     $command->setName('foo:bar');
 474       *
 475       * @return $this
 476       *
 477       * @throws InvalidArgumentException When the name is invalid
 478       */
 479      public function setName(string $name)
 480      {
 481          $this->validateName($name);
 482  
 483          $this->name = $name;
 484  
 485          return $this;
 486      }
 487  
 488      /**
 489       * Sets the process title of the command.
 490       *
 491       * This feature should be used only when creating a long process command,
 492       * like a daemon.
 493       *
 494       * @return $this
 495       */
 496      public function setProcessTitle(string $title)
 497      {
 498          $this->processTitle = $title;
 499  
 500          return $this;
 501      }
 502  
 503      /**
 504       * Returns the command name.
 505       *
 506       * @return string|null
 507       */
 508      public function getName()
 509      {
 510          return $this->name;
 511      }
 512  
 513      /**
 514       * @param bool $hidden Whether or not the command should be hidden from the list of commands
 515       *                     The default value will be true in Symfony 6.0
 516       *
 517       * @return $this
 518       *
 519       * @final since Symfony 5.1
 520       */
 521      public function setHidden(bool $hidden /*= true*/)
 522      {
 523          $this->hidden = $hidden;
 524  
 525          return $this;
 526      }
 527  
 528      /**
 529       * @return bool whether the command should be publicly shown or not
 530       */
 531      public function isHidden()
 532      {
 533          return $this->hidden;
 534      }
 535  
 536      /**
 537       * Sets the description for the command.
 538       *
 539       * @return $this
 540       */
 541      public function setDescription(string $description)
 542      {
 543          $this->description = $description;
 544  
 545          return $this;
 546      }
 547  
 548      /**
 549       * Returns the description for the command.
 550       *
 551       * @return string
 552       */
 553      public function getDescription()
 554      {
 555          return $this->description;
 556      }
 557  
 558      /**
 559       * Sets the help for the command.
 560       *
 561       * @return $this
 562       */
 563      public function setHelp(string $help)
 564      {
 565          $this->help = $help;
 566  
 567          return $this;
 568      }
 569  
 570      /**
 571       * Returns the help for the command.
 572       *
 573       * @return string
 574       */
 575      public function getHelp()
 576      {
 577          return $this->help;
 578      }
 579  
 580      /**
 581       * Returns the processed help for the command replacing the %command.name% and
 582       * %command.full_name% patterns with the real values dynamically.
 583       *
 584       * @return string
 585       */
 586      public function getProcessedHelp()
 587      {
 588          $name = $this->name;
 589          $isSingleCommand = $this->application && $this->application->isSingleCommand();
 590  
 591          $placeholders = [
 592              '%command.name%',
 593              '%command.full_name%',
 594          ];
 595          $replacements = [
 596              $name,
 597              $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
 598          ];
 599  
 600          return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
 601      }
 602  
 603      /**
 604       * Sets the aliases for the command.
 605       *
 606       * @param string[] $aliases An array of aliases for the command
 607       *
 608       * @return $this
 609       *
 610       * @throws InvalidArgumentException When an alias is invalid
 611       */
 612      public function setAliases(iterable $aliases)
 613      {
 614          $list = [];
 615  
 616          foreach ($aliases as $alias) {
 617              $this->validateName($alias);
 618              $list[] = $alias;
 619          }
 620  
 621          $this->aliases = \is_array($aliases) ? $aliases : $list;
 622  
 623          return $this;
 624      }
 625  
 626      /**
 627       * Returns the aliases for the command.
 628       *
 629       * @return array
 630       */
 631      public function getAliases()
 632      {
 633          return $this->aliases;
 634      }
 635  
 636      /**
 637       * Returns the synopsis for the command.
 638       *
 639       * @param bool $short Whether to show the short version of the synopsis (with options folded) or not
 640       *
 641       * @return string
 642       */
 643      public function getSynopsis(bool $short = false)
 644      {
 645          $key = $short ? 'short' : 'long';
 646  
 647          if (!isset($this->synopsis[$key])) {
 648              $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));
 649          }
 650  
 651          return $this->synopsis[$key];
 652      }
 653  
 654      /**
 655       * Add a command usage example, it'll be prefixed with the command name.
 656       *
 657       * @return $this
 658       */
 659      public function addUsage(string $usage)
 660      {
 661          if (!str_starts_with($usage, $this->name)) {
 662              $usage = sprintf('%s %s', $this->name, $usage);
 663          }
 664  
 665          $this->usages[] = $usage;
 666  
 667          return $this;
 668      }
 669  
 670      /**
 671       * Returns alternative usages of the command.
 672       *
 673       * @return array
 674       */
 675      public function getUsages()
 676      {
 677          return $this->usages;
 678      }
 679  
 680      /**
 681       * Gets a helper instance by name.
 682       *
 683       * @return mixed
 684       *
 685       * @throws LogicException           if no HelperSet is defined
 686       * @throws InvalidArgumentException if the helper is not defined
 687       */
 688      public function getHelper(string $name)
 689      {
 690          if (null === $this->helperSet) {
 691              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));
 692          }
 693  
 694          return $this->helperSet->get($name);
 695      }
 696  
 697      /**
 698       * Validates a command name.
 699       *
 700       * It must be non-empty and parts can optionally be separated by ":".
 701       *
 702       * @throws InvalidArgumentException When the name is invalid
 703       */
 704      private function validateName(string $name)
 705      {
 706          if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
 707              throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
 708          }
 709      }
 710  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer