Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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