Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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

Application.php

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 38.04 KiB


 0001  <?php
 0002   
 0003  /*
 0004   * This file is part of the Symfony package.
 0005   *
 0006   * (c) Fabien Potencier <fabien@symfony.com>
 0007   *
 0008   * For the full copyright and license information, please view the LICENSE
 0009   * file that was distributed with this source code.
 0010   */
 0011   
 0012  namespace Symfony\Component\Console;
 0013   
 0014  use Symfony\Component\Console\Descriptor\TextDescriptor;
 0015  use Symfony\Component\Console\Descriptor\XmlDescriptor;
 0016  use Symfony\Component\Console\Exception\ExceptionInterface;
 0017  use Symfony\Component\Console\Helper\DebugFormatterHelper;
 0018  use Symfony\Component\Console\Helper\ProcessHelper;
 0019  use Symfony\Component\Console\Helper\QuestionHelper;
 0020  use Symfony\Component\Console\Input\InputInterface;
 0021  use Symfony\Component\Console\Input\ArgvInput;
 0022  use Symfony\Component\Console\Input\ArrayInput;
 0023  use Symfony\Component\Console\Input\InputDefinition;
 0024  use Symfony\Component\Console\Input\InputOption;
 0025  use Symfony\Component\Console\Input\InputArgument;
 0026  use Symfony\Component\Console\Input\InputAwareInterface;
 0027  use Symfony\Component\Console\Output\BufferedOutput;
 0028  use Symfony\Component\Console\Output\OutputInterface;
 0029  use Symfony\Component\Console\Output\ConsoleOutput;
 0030  use Symfony\Component\Console\Output\ConsoleOutputInterface;
 0031  use Symfony\Component\Console\Command\Command;
 0032  use Symfony\Component\Console\Command\HelpCommand;
 0033  use Symfony\Component\Console\Command\ListCommand;
 0034  use Symfony\Component\Console\Helper\HelperSet;
 0035  use Symfony\Component\Console\Helper\FormatterHelper;
 0036  use Symfony\Component\Console\Helper\DialogHelper;
 0037  use Symfony\Component\Console\Helper\ProgressHelper;
 0038  use Symfony\Component\Console\Helper\TableHelper;
 0039  use Symfony\Component\Console\Event\ConsoleCommandEvent;
 0040  use Symfony\Component\Console\Event\ConsoleExceptionEvent;
 0041  use Symfony\Component\Console\Event\ConsoleTerminateEvent;
 0042  use Symfony\Component\Console\Exception\CommandNotFoundException;
 0043  use Symfony\Component\Console\Exception\LogicException;
 0044  use Symfony\Component\Debug\Exception\FatalThrowableError;
 0045  use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 0046   
 0047  /**
 0048   * An Application is the container for a collection of commands.
 0049   *
 0050   * It is the main entry point of a Console application.
 0051   *
 0052   * This class is optimized for a standard CLI environment.
 0053   *
 0054   * Usage:
 0055   *
 0056   *     $app = new Application('myapp', '1.0 (stable)');
 0057   *     $app->add(new SimpleCommand());
 0058   *     $app->run();
 0059   *
 0060   * @author Fabien Potencier <fabien@symfony.com>
 0061   */
 0062  class Application
 0063  {
 0064      private $commands = array();
 0065      private $wantHelps = false;
 0066      private $runningCommand;
 0067      private $name;
 0068      private $version;
 0069      private $catchExceptions = true;
 0070      private $autoExit = true;
 0071      private $definition;
 0072      private $helperSet;
 0073      private $dispatcher;
 0074      private $terminalDimensions;
 0075      private $defaultCommand;
 0076   
 0077      /**
 0078       * Constructor.
 0079       *
 0080       * @param string $name    The name of the application
 0081       * @param string $version The version of the application
 0082       */
 0083      public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
 0084      {
 0085          $this->name = $name;
 0086          $this->version = $version;
 0087          $this->defaultCommand = 'list';
 0088          $this->helperSet = $this->getDefaultHelperSet();
 0089          $this->definition = $this->getDefaultInputDefinition();
 0090   
 0091          foreach ($this->getDefaultCommands() as $command) {
 0092              $this->add($command);
 0093          }
 0094      }
 0095   
 0096      public function setDispatcher(EventDispatcherInterface $dispatcher)
 0097      {
 0098          $this->dispatcher = $dispatcher;
 0099      }
 0100   
 0101      /**
 0102       * Runs the current application.
 0103       *
 0104       * @param InputInterface  $input  An Input instance
 0105       * @param OutputInterface $output An Output instance
 0106       *
 0107       * @return int 0 if everything went fine, or an error code
 0108       *
 0109       * @throws \Exception When doRun returns Exception
 0110       */
 0111      public function run(InputInterface $input = null, OutputInterface $output = null)
 0112      {
 0113          if (null === $input) {
 0114              $input = new ArgvInput();
 0115          }
 0116   
 0117          if (null === $output) {
 0118              $output = new ConsoleOutput();
 0119          }
 0120   
 0121          $this->configureIO($input, $output);
 0122   
 0123          try {
 0124              $exitCode = $this->doRun($input, $output);
 0125          } catch (\Exception $e) {
 0126              if (!$this->catchExceptions) {
 0127                  throw $e;
 0128              }
 0129   
 0130              if ($output instanceof ConsoleOutputInterface) {
 0131                  $this->renderException($e, $output->getErrorOutput());
 0132              } else {
 0133                  $this->renderException($e, $output);
 0134              }
 0135   
 0136              $exitCode = $e->getCode();
 0137              if (is_numeric($exitCode)) {
 0138                  $exitCode = (int) $exitCode;
 0139                  if (0 === $exitCode) {
 0140                      $exitCode = 1;
 0141                  }
 0142              } else {
 0143                  $exitCode = 1;
 0144              }
 0145          }
 0146   
 0147          if ($this->autoExit) {
 0148              if ($exitCode > 255) {
 0149                  $exitCode = 255;
 0150              }
 0151   
 0152              exit($exitCode);
 0153          }
 0154   
 0155          return $exitCode;
 0156      }
 0157   
 0158      /**
 0159       * Runs the current application.
 0160       *
 0161       * @param InputInterface  $input  An Input instance
 0162       * @param OutputInterface $output An Output instance
 0163       *
 0164       * @return int 0 if everything went fine, or an error code
 0165       */
 0166      public function doRun(InputInterface $input, OutputInterface $output)
 0167      {
 0168          if (true === $input->hasParameterOption(array('--version', '-V'))) {
 0169              $output->writeln($this->getLongVersion());
 0170   
 0171              return 0;
 0172          }
 0173   
 0174          $name = $this->getCommandName($input);
 0175          if (true === $input->hasParameterOption(array('--help', '-h'))) {
 0176              if (!$name) {
 0177                  $name = 'help';
 0178                  $input = new ArrayInput(array('command' => 'help'));
 0179              } else {
 0180                  $this->wantHelps = true;
 0181              }
 0182          }
 0183   
 0184          if (!$name) {
 0185              $name = $this->defaultCommand;
 0186              $input = new ArrayInput(array('command' => $this->defaultCommand));
 0187          }
 0188   
 0189          // the command name MUST be the first element of the input
 0190          $command = $this->find($name);
 0191   
 0192          $this->runningCommand = $command;
 0193          $exitCode = $this->doRunCommand($command, $input, $output);
 0194          $this->runningCommand = null;
 0195   
 0196          return $exitCode;
 0197      }
 0198   
 0199      /**
 0200       * Set a helper set to be used with the command.
 0201       *
 0202       * @param HelperSet $helperSet The helper set
 0203       */
 0204      public function setHelperSet(HelperSet $helperSet)
 0205      {
 0206          $this->helperSet = $helperSet;
 0207      }
 0208   
 0209      /**
 0210       * Get the helper set associated with the command.
 0211       *
 0212       * @return HelperSet The HelperSet instance associated with this command
 0213       */
 0214      public function getHelperSet()
 0215      {
 0216          return $this->helperSet;
 0217      }
 0218   
 0219      /**
 0220       * Set an input definition to be used with this application.
 0221       *
 0222       * @param InputDefinition $definition The input definition
 0223       */
 0224      public function setDefinition(InputDefinition $definition)
 0225      {
 0226          $this->definition = $definition;
 0227      }
 0228   
 0229      /**
 0230       * Gets the InputDefinition related to this Application.
 0231       *
 0232       * @return InputDefinition The InputDefinition instance
 0233       */
 0234      public function getDefinition()
 0235      {
 0236          return $this->definition;
 0237      }
 0238   
 0239      /**
 0240       * Gets the help message.
 0241       *
 0242       * @return string A help message
 0243       */
 0244      public function getHelp()
 0245      {
 0246          return $this->getLongVersion();
 0247      }
 0248   
 0249      /**
 0250       * Sets whether to catch exceptions or not during commands execution.
 0251       *
 0252       * @param bool $boolean Whether to catch exceptions or not during commands execution
 0253       */
 0254      public function setCatchExceptions($boolean)
 0255      {
 0256          $this->catchExceptions = (bool) $boolean;
 0257      }
 0258   
 0259      /**
 0260       * Sets whether to automatically exit after a command execution or not.
 0261       *
 0262       * @param bool $boolean Whether to automatically exit after a command execution or not
 0263       */
 0264      public function setAutoExit($boolean)
 0265      {
 0266          $this->autoExit = (bool) $boolean;
 0267      }
 0268   
 0269      /**
 0270       * Gets the name of the application.
 0271       *
 0272       * @return string The application name
 0273       */
 0274      public function getName()
 0275      {
 0276          return $this->name;
 0277      }
 0278   
 0279      /**
 0280       * Sets the application name.
 0281       *
 0282       * @param string $name The application name
 0283       */
 0284      public function setName($name)
 0285      {
 0286          $this->name = $name;
 0287      }
 0288   
 0289      /**
 0290       * Gets the application version.
 0291       *
 0292       * @return string The application version
 0293       */
 0294      public function getVersion()
 0295      {
 0296          return $this->version;
 0297      }
 0298   
 0299      /**
 0300       * Sets the application version.
 0301       *
 0302       * @param string $version The application version
 0303       */
 0304      public function setVersion($version)
 0305      {
 0306          $this->version = $version;
 0307      }
 0308   
 0309      /**
 0310       * Returns the long version of the application.
 0311       *
 0312       * @return string The long application version
 0313       */
 0314      public function getLongVersion()
 0315      {
 0316          if ('UNKNOWN' !== $this->getName()) {
 0317              if ('UNKNOWN' !== $this->getVersion()) {
 0318                  return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
 0319              }
 0320   
 0321              return sprintf('<info>%s</info>', $this->getName());
 0322          }
 0323   
 0324          return '<info>Console Tool</info>';
 0325      }
 0326   
 0327      /**
 0328       * Registers a new command.
 0329       *
 0330       * @param string $name The command name
 0331       *
 0332       * @return Command The newly created command
 0333       */
 0334      public function register($name)
 0335      {
 0336          return $this->add(new Command($name));
 0337      }
 0338   
 0339      /**
 0340       * Adds an array of command objects.
 0341       *
 0342       * If a Command is not enabled it will not be added.
 0343       *
 0344       * @param Command[] $commands An array of commands
 0345       */
 0346      public function addCommands(array $commands)
 0347      {
 0348          foreach ($commands as $command) {
 0349              $this->add($command);
 0350          }
 0351      }
 0352   
 0353      /**
 0354       * Adds a command object.
 0355       *
 0356       * If a command with the same name already exists, it will be overridden.
 0357       * If the command is not enabled it will not be added.
 0358       *
 0359       * @param Command $command A Command object
 0360       *
 0361       * @return Command|null The registered command if enabled or null
 0362       */
 0363      public function add(Command $command)
 0364      {
 0365          $command->setApplication($this);
 0366   
 0367          if (!$command->isEnabled()) {
 0368              $command->setApplication(null);
 0369   
 0370              return;
 0371          }
 0372   
 0373          if (null === $command->getDefinition()) {
 0374              throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
 0375          }
 0376   
 0377          $this->commands[$command->getName()] = $command;
 0378   
 0379          foreach ($command->getAliases() as $alias) {
 0380              $this->commands[$alias] = $command;
 0381          }
 0382   
 0383          return $command;
 0384      }
 0385   
 0386      /**
 0387       * Returns a registered command by name or alias.
 0388       *
 0389       * @param string $name The command name or alias
 0390       *
 0391       * @return Command A Command object
 0392       *
 0393       * @throws CommandNotFoundException When command name given does not exist
 0394       */
 0395      public function get($name)
 0396      {
 0397          if (!isset($this->commands[$name])) {
 0398              throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
 0399          }
 0400   
 0401          $command = $this->commands[$name];
 0402   
 0403          if ($this->wantHelps) {
 0404              $this->wantHelps = false;
 0405   
 0406              $helpCommand = $this->get('help');
 0407              $helpCommand->setCommand($command);
 0408   
 0409              return $helpCommand;
 0410          }
 0411   
 0412          return $command;
 0413      }
 0414   
 0415      /**
 0416       * Returns true if the command exists, false otherwise.
 0417       *
 0418       * @param string $name The command name or alias
 0419       *
 0420       * @return bool true if the command exists, false otherwise
 0421       */
 0422      public function has($name)
 0423      {
 0424          return isset($this->commands[$name]);
 0425      }
 0426   
 0427      /**
 0428       * Returns an array of all unique namespaces used by currently registered commands.
 0429       *
 0430       * It does not return the global namespace which always exists.
 0431       *
 0432       * @return string[] An array of namespaces
 0433       */
 0434      public function getNamespaces()
 0435      {
 0436          $namespaces = array();
 0437          foreach ($this->all() as $command) {
 0438              $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
 0439   
 0440              foreach ($command->getAliases() as $alias) {
 0441                  $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias));
 0442              }
 0443          }
 0444   
 0445          return array_values(array_unique(array_filter($namespaces)));
 0446      }
 0447   
 0448      /**
 0449       * Finds a registered namespace by a name or an abbreviation.
 0450       *
 0451       * @param string $namespace A namespace or abbreviation to search for
 0452       *
 0453       * @return string A registered namespace
 0454       *
 0455       * @throws CommandNotFoundException When namespace is incorrect or ambiguous
 0456       */
 0457      public function findNamespace($namespace)
 0458      {
 0459          $allNamespaces = $this->getNamespaces();
 0460          $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace);
 0461          $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);
 0462   
 0463          if (empty($namespaces)) {
 0464              $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
 0465   
 0466              if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
 0467                  if (1 == count($alternatives)) {
 0468                      $message .= "\n\nDid you mean this?\n    ";
 0469                  } else {
 0470                      $message .= "\n\nDid you mean one of these?\n    ";
 0471                  }
 0472   
 0473                  $message .= implode("\n    ", $alternatives);
 0474              }
 0475   
 0476              throw new CommandNotFoundException($message, $alternatives);
 0477          }
 0478   
 0479          $exact = in_array($namespace, $namespaces, true);
 0480          if (count($namespaces) > 1 && !$exact) {
 0481              throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
 0482          }
 0483   
 0484          return $exact ? $namespace : reset($namespaces);
 0485      }
 0486   
 0487      /**
 0488       * Finds a command by name or alias.
 0489       *
 0490       * Contrary to get, this command tries to find the best
 0491       * match if you give it an abbreviation of a name or alias.
 0492       *
 0493       * @param string $name A command name or a command alias
 0494       *
 0495       * @return Command A Command instance
 0496       *
 0497       * @throws CommandNotFoundException When command name is incorrect or ambiguous
 0498       */
 0499      public function find($name)
 0500      {
 0501          $allCommands = array_keys($this->commands);
 0502          $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
 0503          $commands = preg_grep('{^'.$expr.'}', $allCommands);
 0504   
 0505          if (empty($commands) || count(preg_grep('{^'.$expr.'$}', $commands)) < 1) {
 0506              if (false !== $pos = strrpos($name, ':')) {
 0507                  // check if a namespace exists and contains commands
 0508                  $this->findNamespace(substr($name, 0, $pos));
 0509              }
 0510   
 0511              $message = sprintf('Command "%s" is not defined.', $name);
 0512   
 0513              if ($alternatives = $this->findAlternatives($name, $allCommands)) {
 0514                  if (1 == count($alternatives)) {
 0515                      $message .= "\n\nDid you mean this?\n    ";
 0516                  } else {
 0517                      $message .= "\n\nDid you mean one of these?\n    ";
 0518                  }
 0519                  $message .= implode("\n    ", $alternatives);
 0520              }
 0521   
 0522              throw new CommandNotFoundException($message, $alternatives);
 0523          }
 0524   
 0525          // filter out aliases for commands which are already on the list
 0526          if (count($commands) > 1) {
 0527              $commandList = $this->commands;
 0528              $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
 0529                  $commandName = $commandList[$nameOrAlias]->getName();
 0530   
 0531                  return $commandName === $nameOrAlias || !in_array($commandName, $commands);
 0532              });
 0533          }
 0534   
 0535          $exact = in_array($name, $commands, true);
 0536          if (count($commands) > 1 && !$exact) {
 0537              $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
 0538   
 0539              throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands));
 0540          }
 0541   
 0542          return $this->get($exact ? $name : reset($commands));
 0543      }
 0544   
 0545      /**
 0546       * Gets the commands (registered in the given namespace if provided).
 0547       *
 0548       * The array keys are the full names and the values the command instances.
 0549       *
 0550       * @param string $namespace A namespace name
 0551       *
 0552       * @return Command[] An array of Command instances
 0553       */
 0554      public function all($namespace = null)
 0555      {
 0556          if (null === $namespace) {
 0557              return $this->commands;
 0558          }
 0559   
 0560          $commands = array();
 0561          foreach ($this->commands as $name => $command) {
 0562              if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
 0563                  $commands[$name] = $command;
 0564              }
 0565          }
 0566   
 0567          return $commands;
 0568      }
 0569   
 0570      /**
 0571       * Returns an array of possible abbreviations given a set of names.
 0572       *
 0573       * @param array $names An array of names
 0574       *
 0575       * @return array An array of abbreviations
 0576       */
 0577      public static function getAbbreviations($names)
 0578      {
 0579          $abbrevs = array();
 0580          foreach ($names as $name) {
 0581              for ($len = strlen($name); $len > 0; --$len) {
 0582                  $abbrev = substr($name, 0, $len);
 0583                  $abbrevs[$abbrev][] = $name;
 0584              }
 0585          }
 0586   
 0587          return $abbrevs;
 0588      }
 0589   
 0590      /**
 0591       * Returns a text representation of the Application.
 0592       *
 0593       * @param string $namespace An optional namespace name
 0594       * @param bool   $raw       Whether to return raw command list
 0595       *
 0596       * @return string A string representing the Application
 0597       *
 0598       * @deprecated since version 2.3, to be removed in 3.0.
 0599       */
 0600      public function asText($namespace = null, $raw = false)
 0601      {
 0602          @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
 0603   
 0604          $descriptor = new TextDescriptor();
 0605          $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw);
 0606          $descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true));
 0607   
 0608          return $output->fetch();
 0609      }
 0610   
 0611      /**
 0612       * Returns an XML representation of the Application.
 0613       *
 0614       * @param string $namespace An optional namespace name
 0615       * @param bool   $asDom     Whether to return a DOM or an XML string
 0616       *
 0617       * @return string|\DOMDocument An XML string representing the Application
 0618       *
 0619       * @deprecated since version 2.3, to be removed in 3.0.
 0620       */
 0621      public function asXml($namespace = null, $asDom = false)
 0622      {
 0623          @trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
 0624   
 0625          $descriptor = new XmlDescriptor();
 0626   
 0627          if ($asDom) {
 0628              return $descriptor->getApplicationDocument($this, $namespace);
 0629          }
 0630   
 0631          $output = new BufferedOutput();
 0632          $descriptor->describe($output, $this, array('namespace' => $namespace));
 0633   
 0634          return $output->fetch();
 0635      }
 0636   
 0637      /**
 0638       * Renders a caught exception.
 0639       *
 0640       * @param \Exception      $e      An exception instance
 0641       * @param OutputInterface $output An OutputInterface instance
 0642       */
 0643      public function renderException($e, $output)
 0644      {
 0645          $output->writeln('', OutputInterface::VERBOSITY_QUIET);
 0646   
 0647          do {
 0648              $title = sprintf('  [%s]  ', get_class($e));
 0649   
 0650              $len = $this->stringWidth($title);
 0651   
 0652              $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
 0653              // HHVM only accepts 32 bits integer in str_split, even when PHP_INT_MAX is a 64 bit integer: https://github.com/facebook/hhvm/issues/1327
 0654              if (defined('HHVM_VERSION') && $width > 1 << 31) {
 0655                  $width = 1 << 31;
 0656              }
 0657              $formatter = $output->getFormatter();
 0658              $lines = array();
 0659              foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) {
 0660                  foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
 0661                      // pre-format lines to get the right string length
 0662                      $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4;
 0663                      $lines[] = array($line, $lineLength);
 0664   
 0665                      $len = max($lineLength, $len);
 0666                  }
 0667              }
 0668   
 0669              $messages = array();
 0670              $messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len)));
 0671              $messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))));
 0672              foreach ($lines as $line) {
 0673                  $messages[] = $formatter->format(sprintf('<error>  %s  %s</error>', $line[0], str_repeat(' ', $len - $line[1])));
 0674              }
 0675              $messages[] = $emptyLine;
 0676              $messages[] = '';
 0677   
 0678              $output->writeln($messages, OutputInterface::OUTPUT_RAW | OutputInterface::VERBOSITY_QUIET);
 0679   
 0680              if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
 0681                  $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
 0682   
 0683                  // exception related properties
 0684                  $trace = $e->getTrace();
 0685                  array_unshift($trace, array(
 0686                      'function' => '',
 0687                      'file' => $e->getFile() !== null ? $e->getFile() : 'n/a',
 0688                      'line' => $e->getLine() !== null ? $e->getLine() : 'n/a',
 0689                      'args' => array(),
 0690                  ));
 0691   
 0692                  for ($i = 0, $count = count($trace); $i < $count; ++$i) {
 0693                      $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
 0694                      $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
 0695                      $function = $trace[$i]['function'];
 0696                      $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
 0697                      $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
 0698   
 0699                      $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), OutputInterface::VERBOSITY_QUIET);
 0700                  }
 0701   
 0702                  $output->writeln('', OutputInterface::VERBOSITY_QUIET);
 0703              }
 0704          } while ($e = $e->getPrevious());
 0705   
 0706          if (null !== $this->runningCommand) {
 0707              $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
 0708              $output->writeln('', OutputInterface::VERBOSITY_QUIET);
 0709          }
 0710      }
 0711   
 0712      /**
 0713       * Tries to figure out the terminal width in which this application runs.
 0714       *
 0715       * @return int|null
 0716       */
 0717      protected function getTerminalWidth()
 0718      {
 0719          $dimensions = $this->getTerminalDimensions();
 0720   
 0721          return $dimensions[0];
 0722      }
 0723   
 0724      /**
 0725       * Tries to figure out the terminal height in which this application runs.
 0726       *
 0727       * @return int|null
 0728       */
 0729      protected function getTerminalHeight()
 0730      {
 0731          $dimensions = $this->getTerminalDimensions();
 0732   
 0733          return $dimensions[1];
 0734      }
 0735   
 0736      /**
 0737       * Tries to figure out the terminal dimensions based on the current environment.
 0738       *
 0739       * @return array Array containing width and height
 0740       */
 0741      public function getTerminalDimensions()
 0742      {
 0743          if ($this->terminalDimensions) {
 0744              return $this->terminalDimensions;
 0745          }
 0746   
 0747          if ('\\' === DIRECTORY_SEPARATOR) {
 0748              // extract [w, H] from "wxh (WxH)"
 0749              if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
 0750                  return array((int) $matches[1], (int) $matches[2]);
 0751              }
 0752              // extract [w, h] from "wxh"
 0753              if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) {
 0754                  return array((int) $matches[1], (int) $matches[2]);
 0755              }
 0756          }
 0757   
 0758          if ($sttyString = $this->getSttyColumns()) {
 0759              // extract [w, h] from "rows h; columns w;"
 0760              if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
 0761                  return array((int) $matches[2], (int) $matches[1]);
 0762              }
 0763              // extract [w, h] from "; h rows; w columns"
 0764              if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
 0765                  return array((int) $matches[2], (int) $matches[1]);
 0766              }
 0767          }
 0768   
 0769          return array(null, null);
 0770      }
 0771   
 0772      /**
 0773       * Sets terminal dimensions.
 0774       *
 0775       * Can be useful to force terminal dimensions for functional tests.
 0776       *
 0777       * @param int $width  The width
 0778       * @param int $height The height
 0779       *
 0780       * @return Application The current application
 0781       */
 0782      public function setTerminalDimensions($width, $height)
 0783      {
 0784          $this->terminalDimensions = array($width, $height);
 0785   
 0786          return $this;
 0787      }
 0788   
 0789      /**
 0790       * Configures the input and output instances based on the user arguments and options.
 0791       *
 0792       * @param InputInterface  $input  An InputInterface instance
 0793       * @param OutputInterface $output An OutputInterface instance
 0794       */
 0795      protected function configureIO(InputInterface $input, OutputInterface $output)
 0796      {
 0797          if (true === $input->hasParameterOption(array('--ansi'))) {
 0798              $output->setDecorated(true);
 0799          } elseif (true === $input->hasParameterOption(array('--no-ansi'))) {
 0800              $output->setDecorated(false);
 0801          }
 0802   
 0803          if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
 0804              $input->setInteractive(false);
 0805          } elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) {
 0806              $inputStream = $this->getHelperSet()->get('question')->getInputStream();
 0807              if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
 0808                  $input->setInteractive(false);
 0809              }
 0810          }
 0811   
 0812          if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
 0813              $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
 0814              $input->setInteractive(false);
 0815          } else {
 0816              if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
 0817                  $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
 0818              } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
 0819                  $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
 0820              } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
 0821                  $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
 0822              }
 0823          }
 0824      }
 0825   
 0826      /**
 0827       * Runs the current command.
 0828       *
 0829       * If an event dispatcher has been attached to the application,
 0830       * events are also dispatched during the life-cycle of the command.
 0831       *
 0832       * @param Command         $command A Command instance
 0833       * @param InputInterface  $input   An Input instance
 0834       * @param OutputInterface $output  An Output instance
 0835       *
 0836       * @return int 0 if everything went fine, or an error code
 0837       *
 0838       * @throws \Exception when the command being run threw an exception
 0839       */
 0840      protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
 0841      {
 0842          foreach ($command->getHelperSet() as $helper) {
 0843              if ($helper instanceof InputAwareInterface) {
 0844                  $helper->setInput($input);
 0845              }
 0846          }
 0847   
 0848          if (null === $this->dispatcher) {
 0849              return $command->run($input, $output);
 0850          }
 0851   
 0852          // bind before the console.command event, so the listeners have access to input options/arguments
 0853          try {
 0854              $command->mergeApplicationDefinition();
 0855              $input->bind($command->getDefinition());
 0856          } catch (ExceptionInterface $e) {
 0857              // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
 0858          }
 0859   
 0860          $event = new ConsoleCommandEvent($command, $input, $output);
 0861          $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
 0862   
 0863          if ($event->commandShouldRun()) {
 0864              try {
 0865                  $e = null;
 0866                  $exitCode = $command->run($input, $output);
 0867              } catch (\Exception $x) {
 0868                  $e = $x;
 0869              } catch (\Throwable $x) {
 0870                  $e = new FatalThrowableError($x);
 0871              }
 0872              if (null !== $e) {
 0873                  $event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode());
 0874                  $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
 0875   
 0876                  if ($e !== $event->getException()) {
 0877                      $x = $e = $event->getException();
 0878                  }
 0879   
 0880                  $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
 0881                  $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
 0882   
 0883                  throw $x;
 0884              }
 0885          } else {
 0886              $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
 0887          }
 0888   
 0889          $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
 0890          $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
 0891   
 0892          return $event->getExitCode();
 0893      }
 0894   
 0895      /**
 0896       * Gets the name of the command based on input.
 0897       *
 0898       * @param InputInterface $input The input interface
 0899       *
 0900       * @return string The command name
 0901       */
 0902      protected function getCommandName(InputInterface $input)
 0903      {
 0904          return $input->getFirstArgument();
 0905      }
 0906   
 0907      /**
 0908       * Gets the default input definition.
 0909       *
 0910       * @return InputDefinition An InputDefinition instance
 0911       */
 0912      protected function getDefaultInputDefinition()
 0913      {
 0914          return new InputDefinition(array(
 0915              new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
 0916   
 0917              new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
 0918              new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
 0919              new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
 0920              new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
 0921              new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
 0922              new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
 0923              new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
 0924          ));
 0925      }
 0926   
 0927      /**
 0928       * Gets the default commands that should always be available.
 0929       *
 0930       * @return Command[] An array of default Command instances
 0931       */
 0932      protected function getDefaultCommands()
 0933      {
 0934          return array(new HelpCommand(), new ListCommand());
 0935      }
 0936   
 0937      /**
 0938       * Gets the default helper set with the helpers that should always be available.
 0939       *
 0940       * @return HelperSet A HelperSet instance
 0941       */
 0942      protected function getDefaultHelperSet()
 0943      {
 0944          return new HelperSet(array(
 0945              new FormatterHelper(),
 0946              new DialogHelper(false),
 0947              new ProgressHelper(false),
 0948              new TableHelper(false),
 0949              new DebugFormatterHelper(),
 0950              new ProcessHelper(),
 0951              new QuestionHelper(),
 0952          ));
 0953      }
 0954   
 0955      /**
 0956       * Runs and parses stty -a if it's available, suppressing any error output.
 0957       *
 0958       * @return string
 0959       */
 0960      private function getSttyColumns()
 0961      {
 0962          if (!function_exists('proc_open')) {
 0963              return;
 0964          }
 0965   
 0966          $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
 0967          $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
 0968          if (is_resource($process)) {
 0969              $info = stream_get_contents($pipes[1]);
 0970              fclose($pipes[1]);
 0971              fclose($pipes[2]);
 0972              proc_close($process);
 0973   
 0974              return $info;
 0975          }
 0976      }
 0977   
 0978      /**
 0979       * Runs and parses mode CON if it's available, suppressing any error output.
 0980       *
 0981       * @return string|null <width>x<height> or null if it could not be parsed
 0982       */
 0983      private function getConsoleMode()
 0984      {
 0985          if (!function_exists('proc_open')) {
 0986              return;
 0987          }
 0988   
 0989          $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
 0990          $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
 0991          if (is_resource($process)) {
 0992              $info = stream_get_contents($pipes[1]);
 0993              fclose($pipes[1]);
 0994              fclose($pipes[2]);
 0995              proc_close($process);
 0996   
 0997              if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
 0998                  return $matches[2].'x'.$matches[1];
 0999              }
 1000          }
 1001      }
 1002   
 1003      /**
 1004       * Returns abbreviated suggestions in string format.
 1005       *
 1006       * @param array $abbrevs Abbreviated suggestions to convert
 1007       *
 1008       * @return string A formatted string of abbreviated suggestions
 1009       */
 1010      private function getAbbreviationSuggestions($abbrevs)
 1011      {
 1012          return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
 1013      }
 1014   
 1015      /**
 1016       * Returns the namespace part of the command name.
 1017       *
 1018       * This method is not part of public API and should not be used directly.
 1019       *
 1020       * @param string $name  The full name of the command
 1021       * @param string $limit The maximum number of parts of the namespace
 1022       *
 1023       * @return string The namespace of the command
 1024       */
 1025      public function extractNamespace($name, $limit = null)
 1026      {
 1027          $parts = explode(':', $name);
 1028          array_pop($parts);
 1029   
 1030          return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
 1031      }
 1032   
 1033      /**
 1034       * Finds alternative of $name among $collection,
 1035       * if nothing is found in $collection, try in $abbrevs.
 1036       *
 1037       * @param string             $name       The string
 1038       * @param array|\Traversable $collection The collection
 1039       *
 1040       * @return string[] A sorted array of similar string
 1041       */
 1042      private function findAlternatives($name, $collection)
 1043      {
 1044          $threshold = 1e3;
 1045          $alternatives = array();
 1046   
 1047          $collectionParts = array();
 1048          foreach ($collection as $item) {
 1049              $collectionParts[$item] = explode(':', $item);
 1050          }
 1051   
 1052          foreach (explode(':', $name) as $i => $subname) {
 1053              foreach ($collectionParts as $collectionName => $parts) {
 1054                  $exists = isset($alternatives[$collectionName]);
 1055                  if (!isset($parts[$i]) && $exists) {
 1056                      $alternatives[$collectionName] += $threshold;
 1057                      continue;
 1058                  } elseif (!isset($parts[$i])) {
 1059                      continue;
 1060                  }
 1061   
 1062                  $lev = levenshtein($subname, $parts[$i]);
 1063                  if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
 1064                      $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
 1065                  } elseif ($exists) {
 1066                      $alternatives[$collectionName] += $threshold;
 1067                  }
 1068              }
 1069          }
 1070   
 1071          foreach ($collection as $item) {
 1072              $lev = levenshtein($name, $item);
 1073              if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
 1074                  $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
 1075              }
 1076          }
 1077   
 1078          $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
 1079          asort($alternatives);
 1080   
 1081          return array_keys($alternatives);
 1082      }
 1083   
 1084      /**
 1085       * Sets the default Command name.
 1086       *
 1087       * @param string $commandName The Command name
 1088       */
 1089      public function setDefaultCommand($commandName)
 1090      {
 1091          $this->defaultCommand = $commandName;
 1092      }
 1093   
 1094      private function stringWidth($string)
 1095      {
 1096          if (false === $encoding = mb_detect_encoding($string, null, true)) {
 1097              return strlen($string);
 1098          }
 1099   
 1100          return mb_strwidth($string, $encoding);
 1101      }
 1102   
 1103      private function splitStringByWidth($string, $width)
 1104      {
 1105          // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
 1106          // additionally, array_slice() is not enough as some character has doubled width.
 1107          // we need a function to split string not by character count but by string width
 1108          if (false === $encoding = mb_detect_encoding($string, null, true)) {
 1109              return str_split($string, $width);
 1110          }
 1111   
 1112          $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
 1113          $lines = array();
 1114          $line = '';
 1115          foreach (preg_split('//u', $utf8String) as $char) {
 1116              // test if $char could be appended to current line
 1117              if (mb_strwidth($line.$char, 'utf8') <= $width) {
 1118                  $line .= $char;
 1119                  continue;
 1120              }
 1121              // if not, push current line to array and make new line
 1122              $lines[] = str_pad($line, $width);
 1123              $line = $char;
 1124          }
 1125          if ('' !== $line) {
 1126              $lines[] = count($lines) ? str_pad($line, $width) : $line;
 1127          }
 1128   
 1129          mb_convert_variables($encoding, 'utf8', $lines);
 1130   
 1131          return $lines;
 1132      }
 1133   
 1134      /**
 1135       * Returns all namespaces of the command name.
 1136       *
 1137       * @param string $name The full name of the command
 1138       *
 1139       * @return string[] The namespaces of the command
 1140       */
 1141      private function extractAllNamespaces($name)
 1142      {
 1143          // -1 as third argument is needed to skip the command short name when exploding
 1144          $parts = explode(':', $name, -1);
 1145          $namespaces = array();
 1146   
 1147          foreach ($parts as $part) {
 1148              if (count($namespaces)) {
 1149                  $namespaces[] = end($namespaces).':'.$part;
 1150              } else {
 1151                  $namespaces[] = $part;
 1152              }
 1153          }
 1154   
 1155          return $namespaces;
 1156      }
 1157  }
 1158