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