[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Symfony\Component\Console; 13 14 use Symfony\Component\Console\Descriptor\TextDescriptor; 15 use Symfony\Component\Console\Descriptor\XmlDescriptor; 16 use Symfony\Component\Console\Input\InputInterface; 17 use Symfony\Component\Console\Input\ArgvInput; 18 use Symfony\Component\Console\Input\ArrayInput; 19 use Symfony\Component\Console\Input\InputDefinition; 20 use Symfony\Component\Console\Input\InputOption; 21 use Symfony\Component\Console\Input\InputArgument; 22 use Symfony\Component\Console\Output\OutputInterface; 23 use Symfony\Component\Console\Output\ConsoleOutput; 24 use Symfony\Component\Console\Output\ConsoleOutputInterface; 25 use Symfony\Component\Console\Command\Command; 26 use Symfony\Component\Console\Command\HelpCommand; 27 use Symfony\Component\Console\Command\ListCommand; 28 use Symfony\Component\Console\Helper\HelperSet; 29 use Symfony\Component\Console\Helper\FormatterHelper; 30 use Symfony\Component\Console\Helper\DialogHelper; 31 use Symfony\Component\Console\Helper\ProgressHelper; 32 use Symfony\Component\Console\Helper\TableHelper; 33 use Symfony\Component\Console\Event\ConsoleCommandEvent; 34 use Symfony\Component\Console\Event\ConsoleExceptionEvent; 35 use Symfony\Component\Console\Event\ConsoleTerminateEvent; 36 use Symfony\Component\EventDispatcher\EventDispatcherInterface; 37 38 /** 39 * An Application is the container for a collection of commands. 40 * 41 * It is the main entry point of a Console application. 42 * 43 * This class is optimized for a standard CLI environment. 44 * 45 * Usage: 46 * 47 * $app = new Application('myapp', '1.0 (stable)'); 48 * $app->add(new SimpleCommand()); 49 * $app->run(); 50 * 51 * @author Fabien Potencier <fabien@symfony.com> 52 */ 53 class Application 54 { 55 private $commands; 56 private $wantHelps = false; 57 private $runningCommand; 58 private $name; 59 private $version; 60 private $catchExceptions; 61 private $autoExit; 62 private $definition; 63 private $helperSet; 64 private $dispatcher; 65 66 /** 67 * Constructor. 68 * 69 * @param string $name The name of the application 70 * @param string $version The version of the application 71 */ 72 public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') 73 { 74 $this->name = $name; 75 $this->version = $version; 76 $this->catchExceptions = true; 77 $this->autoExit = true; 78 $this->commands = array(); 79 $this->helperSet = $this->getDefaultHelperSet(); 80 $this->definition = $this->getDefaultInputDefinition(); 81 82 foreach ($this->getDefaultCommands() as $command) { 83 $this->add($command); 84 } 85 } 86 87 public function setDispatcher(EventDispatcherInterface $dispatcher) 88 { 89 $this->dispatcher = $dispatcher; 90 } 91 92 /** 93 * Runs the current application. 94 * 95 * @param InputInterface $input An Input instance 96 * @param OutputInterface $output An Output instance 97 * 98 * @return int 0 if everything went fine, or an error code 99 * 100 * @throws \Exception When doRun returns Exception 101 */ 102 public function run(InputInterface $input = null, OutputInterface $output = null) 103 { 104 if (null === $input) { 105 $input = new ArgvInput(); 106 } 107 108 if (null === $output) { 109 $output = new ConsoleOutput(); 110 } 111 112 $this->configureIO($input, $output); 113 114 try { 115 $exitCode = $this->doRun($input, $output); 116 } catch (\Exception $e) { 117 if (!$this->catchExceptions) { 118 throw $e; 119 } 120 121 if ($output instanceof ConsoleOutputInterface) { 122 $this->renderException($e, $output->getErrorOutput()); 123 } else { 124 $this->renderException($e, $output); 125 } 126 127 $exitCode = $e->getCode(); 128 if (is_numeric($exitCode)) { 129 $exitCode = (int) $exitCode; 130 if (0 === $exitCode) { 131 $exitCode = 1; 132 } 133 } else { 134 $exitCode = 1; 135 } 136 } 137 138 if ($this->autoExit) { 139 if ($exitCode > 255) { 140 $exitCode = 255; 141 } 142 // @codeCoverageIgnoreStart 143 exit($exitCode); 144 // @codeCoverageIgnoreEnd 145 } 146 147 return $exitCode; 148 } 149 150 /** 151 * Runs the current application. 152 * 153 * @param InputInterface $input An Input instance 154 * @param OutputInterface $output An Output instance 155 * 156 * @return int 0 if everything went fine, or an error code 157 */ 158 public function doRun(InputInterface $input, OutputInterface $output) 159 { 160 if (true === $input->hasParameterOption(array('--version', '-V'))) { 161 $output->writeln($this->getLongVersion()); 162 163 return 0; 164 } 165 166 $name = $this->getCommandName($input); 167 if (true === $input->hasParameterOption(array('--help', '-h'))) { 168 if (!$name) { 169 $name = 'help'; 170 $input = new ArrayInput(array('command' => 'help')); 171 } else { 172 $this->wantHelps = true; 173 } 174 } 175 176 if (!$name) { 177 $name = 'list'; 178 $input = new ArrayInput(array('command' => 'list')); 179 } 180 181 // the command name MUST be the first element of the input 182 $command = $this->find($name); 183 184 $this->runningCommand = $command; 185 $exitCode = $this->doRunCommand($command, $input, $output); 186 $this->runningCommand = null; 187 188 return $exitCode; 189 } 190 191 /** 192 * Set a helper set to be used with the command. 193 * 194 * @param HelperSet $helperSet The helper set 195 */ 196 public function setHelperSet(HelperSet $helperSet) 197 { 198 $this->helperSet = $helperSet; 199 } 200 201 /** 202 * Get the helper set associated with the command. 203 * 204 * @return HelperSet The HelperSet instance associated with this command 205 */ 206 public function getHelperSet() 207 { 208 return $this->helperSet; 209 } 210 211 /** 212 * Set an input definition set to be used with this application. 213 * 214 * @param InputDefinition $definition The input definition 215 */ 216 public function setDefinition(InputDefinition $definition) 217 { 218 $this->definition = $definition; 219 } 220 221 /** 222 * Gets the InputDefinition related to this Application. 223 * 224 * @return InputDefinition The InputDefinition instance 225 */ 226 public function getDefinition() 227 { 228 return $this->definition; 229 } 230 231 /** 232 * Gets the help message. 233 * 234 * @return string A help message. 235 */ 236 public function getHelp() 237 { 238 $messages = array( 239 $this->getLongVersion(), 240 '', 241 '<comment>Usage:</comment>', 242 ' command [options] [arguments]', 243 '', 244 '<comment>Options:</comment>', 245 ); 246 247 foreach ($this->getDefinition()->getOptions() as $option) { 248 $messages[] = sprintf(' %-29s %s %s', 249 '<info>--'.$option->getName().'</info>', 250 $option->getShortcut() ? '<info>-'.$option->getShortcut().'</info>' : ' ', 251 $option->getDescription() 252 ); 253 } 254 255 return implode(PHP_EOL, $messages); 256 } 257 258 /** 259 * Sets whether to catch exceptions or not during commands execution. 260 * 261 * @param bool $boolean Whether to catch exceptions or not during commands execution 262 */ 263 public function setCatchExceptions($boolean) 264 { 265 $this->catchExceptions = (bool) $boolean; 266 } 267 268 /** 269 * Sets whether to automatically exit after a command execution or not. 270 * 271 * @param bool $boolean Whether to automatically exit after a command execution or not 272 */ 273 public function setAutoExit($boolean) 274 { 275 $this->autoExit = (bool) $boolean; 276 } 277 278 /** 279 * Gets the name of the application. 280 * 281 * @return string The application name 282 */ 283 public function getName() 284 { 285 return $this->name; 286 } 287 288 /** 289 * Sets the application name. 290 * 291 * @param string $name The application name 292 */ 293 public function setName($name) 294 { 295 $this->name = $name; 296 } 297 298 /** 299 * Gets the application version. 300 * 301 * @return string The application version 302 */ 303 public function getVersion() 304 { 305 return $this->version; 306 } 307 308 /** 309 * Sets the application version. 310 * 311 * @param string $version The application version 312 */ 313 public function setVersion($version) 314 { 315 $this->version = $version; 316 } 317 318 /** 319 * Returns the long version of the application. 320 * 321 * @return string The long application version 322 */ 323 public function getLongVersion() 324 { 325 if ('UNKNOWN' !== $this->getName()) { 326 if ('UNKNOWN' !== $this->getVersion()) { 327 return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion()); 328 } 329 330 return sprintf('<info>%s</info>', $this->getName()); 331 } 332 333 return '<info>Console Tool</info>'; 334 } 335 336 /** 337 * Registers a new command. 338 * 339 * @param string $name The command name 340 * 341 * @return Command The newly created command 342 */ 343 public function register($name) 344 { 345 return $this->add(new Command($name)); 346 } 347 348 /** 349 * Adds an array of command objects. 350 * 351 * @param Command[] $commands An array of commands 352 */ 353 public function addCommands(array $commands) 354 { 355 foreach ($commands as $command) { 356 $this->add($command); 357 } 358 } 359 360 /** 361 * Adds a command object. 362 * 363 * If a command with the same name already exists, it will be overridden. 364 * 365 * @param Command $command A Command object 366 * 367 * @return Command The registered command 368 */ 369 public function add(Command $command) 370 { 371 $command->setApplication($this); 372 373 if (!$command->isEnabled()) { 374 $command->setApplication(null); 375 376 return; 377 } 378 379 $this->commands[$command->getName()] = $command; 380 381 foreach ($command->getAliases() as $alias) { 382 $this->commands[$alias] = $command; 383 } 384 385 return $command; 386 } 387 388 /** 389 * Returns a registered command by name or alias. 390 * 391 * @param string $name The command name or alias 392 * 393 * @return Command A Command object 394 * 395 * @throws \InvalidArgumentException When command name given does not exist 396 */ 397 public function get($name) 398 { 399 if (!isset($this->commands[$name])) { 400 throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); 401 } 402 403 $command = $this->commands[$name]; 404 405 if ($this->wantHelps) { 406 $this->wantHelps = false; 407 408 $helpCommand = $this->get('help'); 409 $helpCommand->setCommand($command); 410 411 return $helpCommand; 412 } 413 414 return $command; 415 } 416 417 /** 418 * Returns true if the command exists, false otherwise. 419 * 420 * @param string $name The command name or alias 421 * 422 * @return bool true if the command exists, false otherwise 423 */ 424 public function has($name) 425 { 426 return isset($this->commands[$name]); 427 } 428 429 /** 430 * Returns an array of all unique namespaces used by currently registered commands. 431 * 432 * It does not returns the global namespace which always exists. 433 * 434 * @return array An array of namespaces 435 */ 436 public function getNamespaces() 437 { 438 $namespaces = array(); 439 foreach ($this->all() as $command) { 440 $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); 441 442 foreach ($command->getAliases() as $alias) { 443 $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias)); 444 } 445 } 446 447 return array_values(array_unique(array_filter($namespaces))); 448 } 449 450 /** 451 * Finds a registered namespace by a name or an abbreviation. 452 * 453 * @param string $namespace A namespace or abbreviation to search for 454 * 455 * @return string A registered namespace 456 * 457 * @throws \InvalidArgumentException When namespace is incorrect or ambiguous 458 */ 459 public function findNamespace($namespace) 460 { 461 $allNamespaces = $this->getNamespaces(); 462 $found = ''; 463 foreach (explode(':', $namespace) as $i => $part) { 464 // select sub-namespaces matching the current namespace we found 465 $namespaces = array(); 466 foreach ($allNamespaces as $n) { 467 if ('' === $found || 0 === strpos($n, $found)) { 468 $namespaces[$n] = explode(':', $n); 469 } 470 } 471 472 $abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $namespaces))))); 473 474 if (!isset($abbrevs[$part])) { 475 $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); 476 477 if (1 <= $i) { 478 $part = $found.':'.$part; 479 } 480 481 if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) { 482 if (1 == count($alternatives)) { 483 $message .= "\n\nDid you mean this?\n "; 484 } else { 485 $message .= "\n\nDid you mean one of these?\n "; 486 } 487 488 $message .= implode("\n ", $alternatives); 489 } 490 491 throw new \InvalidArgumentException($message); 492 } 493 494 // there are multiple matches, but $part is an exact match of one of them so we select it 495 if (in_array($part, $abbrevs[$part])) { 496 $abbrevs[$part] = array($part); 497 } 498 499 if (count($abbrevs[$part]) > 1) { 500 throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part]))); 501 } 502 503 $found .= $found ? ':'.$abbrevs[$part][0] : $abbrevs[$part][0]; 504 } 505 506 return $found; 507 } 508 509 /** 510 * Finds a command by name or alias. 511 * 512 * Contrary to get, this command tries to find the best 513 * match if you give it an abbreviation of a name or alias. 514 * 515 * @param string $name A command name or a command alias 516 * 517 * @return Command A Command instance 518 * 519 * @throws \InvalidArgumentException When command name is incorrect or ambiguous 520 */ 521 public function find($name) 522 { 523 // namespace 524 $namespace = ''; 525 $searchName = $name; 526 if (false !== $pos = strrpos($name, ':')) { 527 $namespace = $this->findNamespace(substr($name, 0, $pos)); 528 $searchName = $namespace.substr($name, $pos); 529 } 530 531 // name 532 $commands = array(); 533 foreach ($this->all() as $command) { 534 $extractedNamespace = $this->extractNamespace($command->getName()); 535 if ($extractedNamespace === $namespace 536 || !empty($namespace) && 0 === strpos($extractedNamespace, $namespace) 537 ) { 538 $commands[] = $command->getName(); 539 } 540 } 541 542 $abbrevs = static::getAbbreviations(array_unique($commands)); 543 if (isset($abbrevs[$searchName]) && 1 == count($abbrevs[$searchName])) { 544 return $this->get($abbrevs[$searchName][0]); 545 } 546 547 if (isset($abbrevs[$searchName]) && in_array($searchName, $abbrevs[$searchName])) { 548 return $this->get($searchName); 549 } 550 551 if (isset($abbrevs[$searchName]) && count($abbrevs[$searchName]) > 1) { 552 $suggestions = $this->getAbbreviationSuggestions($abbrevs[$searchName]); 553 554 throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); 555 } 556 557 // aliases 558 $aliases = array(); 559 foreach ($this->all() as $command) { 560 foreach ($command->getAliases() as $alias) { 561 $extractedNamespace = $this->extractNamespace($alias); 562 if ($extractedNamespace === $namespace 563 || !empty($namespace) && 0 === strpos($extractedNamespace, $namespace) 564 ) { 565 $aliases[] = $alias; 566 } 567 } 568 } 569 570 $aliases = static::getAbbreviations(array_unique($aliases)); 571 if (!isset($aliases[$searchName])) { 572 $message = sprintf('Command "%s" is not defined.', $name); 573 574 if ($alternatives = $this->findAlternativeCommands($searchName, $abbrevs)) { 575 if (1 == count($alternatives)) { 576 $message .= "\n\nDid you mean this?\n "; 577 } else { 578 $message .= "\n\nDid you mean one of these?\n "; 579 } 580 $message .= implode("\n ", $alternatives); 581 } 582 583 throw new \InvalidArgumentException($message); 584 } 585 586 if (count($aliases[$searchName]) > 1) { 587 throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $this->getAbbreviationSuggestions($aliases[$searchName]))); 588 } 589 590 return $this->get($aliases[$searchName][0]); 591 } 592 593 /** 594 * Gets the commands (registered in the given namespace if provided). 595 * 596 * The array keys are the full names and the values the command instances. 597 * 598 * @param string $namespace A namespace name 599 * 600 * @return Command[] An array of Command instances 601 */ 602 public function all($namespace = null) 603 { 604 if (null === $namespace) { 605 return $this->commands; 606 } 607 608 $commands = array(); 609 foreach ($this->commands as $name => $command) { 610 if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) { 611 $commands[$name] = $command; 612 } 613 } 614 615 return $commands; 616 } 617 618 /** 619 * Returns an array of possible abbreviations given a set of names. 620 * 621 * @param array $names An array of names 622 * 623 * @return array An array of abbreviations 624 */ 625 public static function getAbbreviations($names) 626 { 627 $abbrevs = array(); 628 foreach ($names as $name) { 629 for ($len = strlen($name); $len > 0; --$len) { 630 $abbrev = substr($name, 0, $len); 631 $abbrevs[$abbrev][] = $name; 632 } 633 } 634 635 return $abbrevs; 636 } 637 638 /** 639 * Returns a text representation of the Application. 640 * 641 * @param string $namespace An optional namespace name 642 * @param bool $raw Whether to return raw command list 643 * 644 * @return string A string representing the Application 645 * 646 * @deprecated Deprecated since version 2.3, to be removed in 3.0. 647 */ 648 public function asText($namespace = null, $raw = false) 649 { 650 $descriptor = new TextDescriptor(); 651 652 return $descriptor->describe($this, array('namespace' => $namespace, 'raw_text' => $raw)); 653 } 654 655 /** 656 * Returns an XML representation of the Application. 657 * 658 * @param string $namespace An optional namespace name 659 * @param bool $asDom Whether to return a DOM or an XML string 660 * 661 * @return string|\DOMDocument An XML string representing the Application 662 * 663 * @deprecated Deprecated since version 2.3, to be removed in 3.0. 664 */ 665 public function asXml($namespace = null, $asDom = false) 666 { 667 $descriptor = new XmlDescriptor(); 668 669 return $descriptor->describe($this, array('namespace' => $namespace, 'as_dom' => $asDom)); 670 } 671 672 /** 673 * Renders a caught exception. 674 * 675 * @param \Exception $e An exception instance 676 * @param OutputInterface $output An OutputInterface instance 677 */ 678 public function renderException($e, $output) 679 { 680 $output->writeln(''); 681 682 do { 683 $title = sprintf(' [%s] ', get_class($e)); 684 685 $len = $this->stringWidth($title); 686 687 $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX; 688 // 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 689 if (defined('HHVM_VERSION') && $width > 1 << 31) { 690 $width = 1 << 31; 691 } 692 $formatter = $output->getFormatter(); 693 $lines = array(); 694 foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) { 695 foreach ($this->splitStringByWidth($line, $width - 4) as $line) { 696 // pre-format lines to get the right string length 697 $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4; 698 $lines[] = array($line, $lineLength); 699 700 $len = max($lineLength, $len); 701 } 702 } 703 704 $messages = array(); 705 $messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len))); 706 $messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title))))); 707 foreach ($lines as $line) { 708 $messages[] = $formatter->format(sprintf('<error> %s %s</error>', $line[0], str_repeat(' ', $len - $line[1]))); 709 } 710 $messages[] = $emptyLine; 711 $messages[] = ''; 712 713 $output->writeln($messages, OutputInterface::OUTPUT_RAW); 714 715 if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { 716 $output->writeln('<comment>Exception trace:</comment>'); 717 718 // exception related properties 719 $trace = $e->getTrace(); 720 array_unshift($trace, array( 721 'function' => '', 722 'file' => $e->getFile() !== null ? $e->getFile() : 'n/a', 723 'line' => $e->getLine() !== null ? $e->getLine() : 'n/a', 724 'args' => array(), 725 )); 726 727 for ($i = 0, $count = count($trace); $i < $count; ++$i) { 728 $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; 729 $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : ''; 730 $function = $trace[$i]['function']; 731 $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a'; 732 $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a'; 733 734 $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line)); 735 } 736 737 $output->writeln(''); 738 } 739 } while ($e = $e->getPrevious()); 740 741 if (null !== $this->runningCommand) { 742 $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName()))); 743 $output->writeln(''); 744 } 745 } 746 747 /** 748 * Tries to figure out the terminal width in which this application runs. 749 * 750 * @return int|null 751 */ 752 protected function getTerminalWidth() 753 { 754 $dimensions = $this->getTerminalDimensions(); 755 756 return $dimensions[0]; 757 } 758 759 /** 760 * Tries to figure out the terminal height in which this application runs. 761 * 762 * @return int|null 763 */ 764 protected function getTerminalHeight() 765 { 766 $dimensions = $this->getTerminalDimensions(); 767 768 return $dimensions[1]; 769 } 770 771 /** 772 * Tries to figure out the terminal dimensions based on the current environment. 773 * 774 * @return array Array containing width and height 775 */ 776 public function getTerminalDimensions() 777 { 778 if ('\\' === DIRECTORY_SEPARATOR) { 779 // extract [w, H] from "wxh (WxH)" 780 if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { 781 return array((int) $matches[1], (int) $matches[2]); 782 } 783 // extract [w, h] from "wxh" 784 if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) { 785 return array((int) $matches[1], (int) $matches[2]); 786 } 787 } 788 789 if ($sttyString = $this->getSttyColumns()) { 790 // extract [w, h] from "rows h; columns w;" 791 if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { 792 return array((int) $matches[2], (int) $matches[1]); 793 } 794 // extract [w, h] from "; h rows; w columns" 795 if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { 796 return array((int) $matches[2], (int) $matches[1]); 797 } 798 } 799 800 return array(null, null); 801 } 802 803 /** 804 * Configures the input and output instances based on the user arguments and options. 805 * 806 * @param InputInterface $input An InputInterface instance 807 * @param OutputInterface $output An OutputInterface instance 808 */ 809 protected function configureIO(InputInterface $input, OutputInterface $output) 810 { 811 if (true === $input->hasParameterOption(array('--ansi'))) { 812 $output->setDecorated(true); 813 } elseif (true === $input->hasParameterOption(array('--no-ansi'))) { 814 $output->setDecorated(false); 815 } 816 817 if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) { 818 $input->setInteractive(false); 819 } elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('dialog')) { 820 $inputStream = $this->getHelperSet()->get('dialog')->getInputStream(); 821 if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) { 822 $input->setInteractive(false); 823 } 824 } 825 826 if (true === $input->hasParameterOption(array('--quiet', '-q'))) { 827 $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); 828 } else { 829 if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { 830 $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); 831 } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { 832 $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); 833 } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { 834 $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); 835 } 836 } 837 } 838 839 /** 840 * Runs the current command. 841 * 842 * If an event dispatcher has been attached to the application, 843 * events are also dispatched during the life-cycle of the command. 844 * 845 * @param Command $command A Command instance 846 * @param InputInterface $input An Input instance 847 * @param OutputInterface $output An Output instance 848 * 849 * @return int 0 if everything went fine, or an error code 850 * 851 * @throws \Exception when the command being run threw an exception 852 */ 853 protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) 854 { 855 if (null === $this->dispatcher) { 856 return $command->run($input, $output); 857 } 858 859 $event = new ConsoleCommandEvent($command, $input, $output); 860 $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event); 861 862 try { 863 $exitCode = $command->run($input, $output); 864 } catch (\Exception $e) { 865 $event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode()); 866 $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event); 867 868 $e = $event->getException(); 869 870 $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode()); 871 $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); 872 873 throw $e; 874 } 875 876 $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); 877 $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); 878 879 return $event->getExitCode(); 880 } 881 882 /** 883 * Gets the name of the command based on input. 884 * 885 * @param InputInterface $input The input interface 886 * 887 * @return string The command name 888 */ 889 protected function getCommandName(InputInterface $input) 890 { 891 return $input->getFirstArgument(); 892 } 893 894 /** 895 * Gets the default input definition. 896 * 897 * @return InputDefinition An InputDefinition instance 898 */ 899 protected function getDefaultInputDefinition() 900 { 901 return new InputDefinition(array( 902 new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), 903 904 new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'), 905 new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), 906 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'), 907 new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), 908 new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'), 909 new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'), 910 new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), 911 )); 912 } 913 914 /** 915 * Gets the default commands that should always be available. 916 * 917 * @return Command[] An array of default Command instances 918 */ 919 protected function getDefaultCommands() 920 { 921 return array(new HelpCommand(), new ListCommand()); 922 } 923 924 /** 925 * Gets the default helper set with the helpers that should always be available. 926 * 927 * @return HelperSet A HelperSet instance 928 */ 929 protected function getDefaultHelperSet() 930 { 931 return new HelperSet(array( 932 new FormatterHelper(), 933 new DialogHelper(), 934 new ProgressHelper(), 935 new TableHelper(), 936 )); 937 } 938 939 /** 940 * Runs and parses stty -a if it's available, suppressing any error output. 941 * 942 * @return string 943 */ 944 private function getSttyColumns() 945 { 946 if (!function_exists('proc_open')) { 947 return; 948 } 949 950 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); 951 $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); 952 if (is_resource($process)) { 953 $info = stream_get_contents($pipes[1]); 954 fclose($pipes[1]); 955 fclose($pipes[2]); 956 proc_close($process); 957 958 return $info; 959 } 960 } 961 962 /** 963 * Runs and parses mode CON if it's available, suppressing any error output. 964 * 965 * @return string <width>x<height> or null if it could not be parsed 966 */ 967 private function getConsoleMode() 968 { 969 if (!function_exists('proc_open')) { 970 return; 971 } 972 973 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); 974 $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); 975 if (is_resource($process)) { 976 $info = stream_get_contents($pipes[1]); 977 fclose($pipes[1]); 978 fclose($pipes[2]); 979 proc_close($process); 980 981 if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { 982 return $matches[2].'x'.$matches[1]; 983 } 984 } 985 } 986 987 /** 988 * Returns abbreviated suggestions in string format. 989 * 990 * @param array $abbrevs Abbreviated suggestions to convert 991 * 992 * @return string A formatted string of abbreviated suggestions 993 */ 994 private function getAbbreviationSuggestions($abbrevs) 995 { 996 return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); 997 } 998 999 /** 1000 * Returns the namespace part of the command name. 1001 * 1002 * This method is not part of public API and should not be used directly. 1003 * 1004 * @param string $name The full name of the command 1005 * @param string $limit The maximum number of parts of the namespace 1006 * 1007 * @return string The namespace of the command 1008 */ 1009 public function extractNamespace($name, $limit = null) 1010 { 1011 $parts = explode(':', $name); 1012 array_pop($parts); 1013 1014 return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit)); 1015 } 1016 1017 /** 1018 * Finds alternative commands of $name. 1019 * 1020 * @param string $name The full name of the command 1021 * @param array $abbrevs The abbreviations 1022 * 1023 * @return array A sorted array of similar commands 1024 */ 1025 private function findAlternativeCommands($name, $abbrevs) 1026 { 1027 $callback = function ($item) { 1028 return $item->getName(); 1029 }; 1030 1031 return $this->findAlternatives($name, $this->all(), $abbrevs, $callback); 1032 } 1033 1034 /** 1035 * Finds alternative namespace of $name. 1036 * 1037 * @param string $name The full name of the namespace 1038 * @param array $abbrevs The abbreviations 1039 * 1040 * @return array A sorted array of similar namespace 1041 */ 1042 private function findAlternativeNamespace($name, $abbrevs) 1043 { 1044 return $this->findAlternatives($name, $this->getNamespaces(), $abbrevs); 1045 } 1046 1047 /** 1048 * Finds alternative of $name among $collection, 1049 * if nothing is found in $collection, try in $abbrevs. 1050 * 1051 * @param string $name The string 1052 * @param array|\Traversable $collection The collection 1053 * @param array $abbrevs The abbreviations 1054 * @param callable $callback The callable to transform collection item before comparison 1055 * 1056 * @return array A sorted array of similar string 1057 */ 1058 private function findAlternatives($name, $collection, $abbrevs, $callback = null) 1059 { 1060 $alternatives = array(); 1061 1062 foreach ($collection as $item) { 1063 if (null !== $callback) { 1064 $item = call_user_func($callback, $item); 1065 } 1066 1067 $lev = levenshtein($name, $item); 1068 if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { 1069 $alternatives[$item] = $lev; 1070 } 1071 } 1072 1073 if (!$alternatives) { 1074 foreach ($abbrevs as $key => $values) { 1075 $lev = levenshtein($name, $key); 1076 if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) { 1077 foreach ($values as $value) { 1078 $alternatives[$value] = $lev; 1079 } 1080 } 1081 } 1082 } 1083 1084 asort($alternatives); 1085 1086 return array_keys($alternatives); 1087 } 1088 1089 private function stringWidth($string) 1090 { 1091 if (!function_exists('mb_strwidth')) { 1092 return strlen($string); 1093 } 1094 1095 if (false === $encoding = mb_detect_encoding($string, null, true)) { 1096 return strlen($string); 1097 } 1098 1099 return mb_strwidth($string, $encoding); 1100 } 1101 1102 private function splitStringByWidth($string, $width) 1103 { 1104 // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. 1105 // additionally, array_slice() is not enough as some character has doubled width. 1106 // we need a function to split string not by character count but by string width 1107 1108 if (!function_exists('mb_strwidth')) { 1109 return str_split($string, $width); 1110 } 1111 1112 if (false === $encoding = mb_detect_encoding($string, null, true)) { 1113 return str_split($string, $width); 1114 } 1115 1116 $utf8String = mb_convert_encoding($string, 'utf8', $encoding); 1117 $lines = array(); 1118 $line = ''; 1119 foreach (preg_split('//u', $utf8String) as $char) { 1120 // test if $char could be appended to current line 1121 if (mb_strwidth($line.$char, 'utf8') <= $width) { 1122 $line .= $char; 1123 continue; 1124 } 1125 // if not, push current line to array and make new line 1126 $lines[] = str_pad($line, $width); 1127 $line = $char; 1128 } 1129 if ('' !== $line) { 1130 $lines[] = count($lines) ? str_pad($line, $width) : $line; 1131 } 1132 1133 mb_convert_variables($encoding, 'utf8', $lines); 1134 1135 return $lines; 1136 } 1137 1138 /** 1139 * Returns all namespaces of the command name. 1140 * 1141 * @param string $name The full name of the command 1142 * 1143 * @return array The namespaces of the command 1144 */ 1145 private function extractAllNamespaces($name) 1146 { 1147 // -1 as third argument is needed to skip the command short name when exploding 1148 $parts = explode(':', $name, -1); 1149 $namespaces = array(); 1150 1151 foreach ($parts as $part) { 1152 if (count($namespaces)) { 1153 $namespaces[] = end($namespaces).':'.$part; 1154 } else { 1155 $namespaces[] = $part; 1156 } 1157 } 1158 1159 return $namespaces; 1160 } 1161 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |