2010-01-04 14:42:28 +00:00
< ? php
2011-01-15 13:29:43 +00:00
/*
* This file is part of the Symfony package .
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2011-01-15 13:29:43 +00:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2010-08-20 22:09:55 +01:00
namespace Symfony\Component\Console ;
2010-01-09 11:57:15 +00:00
2013-03-22 13:40:47 +00:00
use Symfony\Component\Console\Descriptor\TextDescriptor ;
use Symfony\Component\Console\Descriptor\XmlDescriptor ;
2014-04-03 09:19:54 +01:00
use Symfony\Component\Console\Helper\DebugFormatterHelper ;
use Symfony\Component\Console\Helper\ProcessHelper ;
2014-04-01 13:42:24 +01:00
use Symfony\Component\Console\Helper\QuestionHelper ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Input\ArgvInput ;
use Symfony\Component\Console\Input\ArrayInput ;
use Symfony\Component\Console\Input\InputDefinition ;
use Symfony\Component\Console\Input\InputOption ;
use Symfony\Component\Console\Input\InputArgument ;
2013-07-09 10:28:35 +01:00
use Symfony\Component\Console\Input\InputAwareInterface ;
2013-07-08 20:00:49 +01:00
use Symfony\Component\Console\Output\BufferedOutput ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\Console\Output\OutputInterface ;
use Symfony\Component\Console\Output\ConsoleOutput ;
2011-12-16 14:08:35 +00:00
use Symfony\Component\Console\Output\ConsoleOutputInterface ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\Console\Command\Command ;
use Symfony\Component\Console\Command\HelpCommand ;
use Symfony\Component\Console\Command\ListCommand ;
use Symfony\Component\Console\Helper\HelperSet ;
use Symfony\Component\Console\Helper\FormatterHelper ;
use Symfony\Component\Console\Helper\DialogHelper ;
2012-09-29 21:11:59 +01:00
use Symfony\Component\Console\Helper\ProgressHelper ;
2012-12-15 15:08:23 +00:00
use Symfony\Component\Console\Helper\TableHelper ;
2013-03-24 09:08:12 +00:00
use Symfony\Component\Console\Event\ConsoleCommandEvent ;
2013-05-27 11:36:30 +01:00
use Symfony\Component\Console\Event\ConsoleExceptionEvent ;
2013-03-24 09:08:12 +00:00
use Symfony\Component\Console\Event\ConsoleTerminateEvent ;
2013-05-28 20:36:15 +01:00
use Symfony\Component\EventDispatcher\EventDispatcherInterface ;
2010-01-04 14:42:28 +00:00
/**
2010-01-04 18:51:21 +00:00
* An Application is the container for a collection of commands .
2010-01-04 14:42:28 +00:00
*
2010-01-09 11:57:15 +00:00
* It is the main entry point of a Console application .
2010-01-04 14:42:28 +00:00
*
* This class is optimized for a standard CLI environment .
*
* Usage :
*
* $app = new Application ( 'myapp' , '1.0 (stable)' );
2010-11-23 08:42:19 +00:00
* $app -> add ( new SimpleCommand ());
2010-01-04 14:42:28 +00:00
* $app -> run ();
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2011-03-24 08:39:53 +00:00
*
* @ api
2010-01-04 14:42:28 +00:00
*/
class Application
{
2013-10-08 16:44:03 +01:00
private $commands = array ();
2011-03-11 11:53:42 +00:00
private $wantHelps = false ;
private $runningCommand ;
private $name ;
private $version ;
2013-10-08 16:44:03 +01:00
private $catchExceptions = true ;
private $autoExit = true ;
2011-03-11 11:53:42 +00:00
private $definition ;
private $helperSet ;
2013-03-24 09:08:12 +00:00
private $dispatcher ;
2013-07-29 22:04:28 +01:00
private $terminalDimensions ;
2013-12-14 12:57:08 +00:00
private $defaultCommand ;
2010-05-06 12:25:53 +01:00
/**
* Constructor .
*
2012-05-15 21:19:31 +01:00
* @ param string $name The name of the application
* @ param string $version The version of the application
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function __construct ( $name = 'UNKNOWN' , $version = 'UNKNOWN' )
{
$this -> name = $name ;
$this -> version = $version ;
2013-12-14 12:57:08 +00:00
$this -> defaultCommand = 'list' ;
2011-10-25 16:11:49 +01:00
$this -> helperSet = $this -> getDefaultHelperSet ();
$this -> definition = $this -> getDefaultInputDefinition ();
2010-05-06 12:25:53 +01:00
2011-10-25 16:11:49 +01:00
foreach ( $this -> getDefaultCommands () as $command ) {
$this -> add ( $command );
}
2010-05-06 12:25:53 +01:00
}
2013-05-28 20:36:15 +01:00
public function setDispatcher ( EventDispatcherInterface $dispatcher )
2013-03-24 09:08:12 +00:00
{
$this -> dispatcher = $dispatcher ;
}
2010-05-06 12:25:53 +01:00
/**
* Runs the current application .
*
* @ param InputInterface $input An Input instance
* @ param OutputInterface $output An Output instance
*
2014-04-15 11:04:31 +01:00
* @ return int 0 if everything went fine , or an error code
2010-05-06 12:25:53 +01:00
*
* @ throws \Exception When doRun returns Exception
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function run ( InputInterface $input = null , OutputInterface $output = null )
{
2010-05-07 15:09:11 +01:00
if ( null === $input ) {
2010-05-06 12:25:53 +01:00
$input = new ArgvInput ();
}
2010-01-04 14:42:28 +00:00
2010-05-07 15:09:11 +01:00
if ( null === $output ) {
2010-05-06 12:25:53 +01:00
$output = new ConsoleOutput ();
}
2010-01-04 14:42:28 +00:00
2013-05-09 09:57:19 +01:00
$this -> configureIO ( $input , $output );
2010-05-07 15:09:11 +01:00
try {
2013-03-24 09:08:12 +00:00
$exitCode = $this -> doRun ( $input , $output );
2010-05-07 15:09:11 +01:00
} catch ( \Exception $e ) {
2010-05-08 14:32:30 +01:00
if ( ! $this -> catchExceptions ) {
2010-05-06 12:25:53 +01:00
throw $e ;
}
2011-12-16 14:08:35 +00:00
if ( $output instanceof ConsoleOutputInterface ) {
$this -> renderException ( $e , $output -> getErrorOutput ());
} else {
$this -> renderException ( $e , $output );
}
2010-05-06 12:25:53 +01:00
2013-06-11 08:15:14 +01:00
$exitCode = $e -> getCode ();
if ( is_numeric ( $exitCode )) {
$exitCode = ( int ) $exitCode ;
if ( 0 === $exitCode ) {
$exitCode = 1 ;
2013-06-05 09:14:54 +01:00
}
} else {
2013-06-11 08:15:14 +01:00
$exitCode = 1 ;
2013-06-05 09:14:54 +01:00
}
2010-05-06 12:25:53 +01:00
}
2010-05-07 15:09:11 +01:00
if ( $this -> autoExit ) {
2013-03-24 09:08:12 +00:00
if ( $exitCode > 255 ) {
$exitCode = 255 ;
2010-10-12 11:57:22 +01:00
}
2014-01-02 14:42:17 +00:00
2013-03-24 09:08:12 +00:00
exit ( $exitCode );
2010-05-06 12:25:53 +01:00
}
2011-02-27 16:48:41 +00:00
2013-03-24 09:08:12 +00:00
return $exitCode ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Runs the current application .
*
* @ param InputInterface $input An Input instance
* @ param OutputInterface $output An Output instance
*
2014-04-15 11:04:31 +01:00
* @ return int 0 if everything went fine , or an error code
2010-05-06 12:25:53 +01:00
*/
public function doRun ( InputInterface $input , OutputInterface $output )
2010-01-04 14:42:28 +00:00
{
2010-05-07 15:09:11 +01:00
if ( true === $input -> hasParameterOption ( array ( '--version' , '-V' ))) {
2010-05-06 12:25:53 +01:00
$output -> writeln ( $this -> getLongVersion ());
return 0 ;
}
2013-05-09 09:40:45 +01:00
$name = $this -> getCommandName ( $input );
if ( true === $input -> hasParameterOption ( array ( '--help' , '-h' ))) {
if ( ! $name ) {
$name = 'help' ;
$input = new ArrayInput ( array ( 'command' => 'help' ));
} else {
$this -> wantHelps = true ;
}
}
2010-05-07 15:09:11 +01:00
if ( ! $name ) {
2013-12-14 12:57:08 +00:00
$name = $this -> defaultCommand ;
$input = new ArrayInput ( array ( 'command' => $this -> defaultCommand ));
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:42:28 +00:00
2010-05-06 12:25:53 +01:00
// the command name MUST be the first element of the input
2010-11-23 08:42:19 +00:00
$command = $this -> find ( $name );
2010-01-04 14:42:28 +00:00
2010-05-06 12:25:53 +01:00
$this -> runningCommand = $command ;
2013-03-24 09:08:12 +00:00
$exitCode = $this -> doRunCommand ( $command , $input , $output );
2010-05-06 12:25:53 +01:00
$this -> runningCommand = null ;
2013-05-19 20:06:00 +01:00
return $exitCode ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Set a helper set to be used with the command .
*
* @ param HelperSet $helperSet The helper set
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function setHelperSet ( HelperSet $helperSet )
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
$this -> helperSet = $helperSet ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
2011-02-07 00:34:24 +00:00
* Get the helper set associated with the command .
2010-05-06 12:25:53 +01:00
*
* @ return HelperSet The HelperSet instance associated with this command
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function getHelperSet ()
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
return $this -> helperSet ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
2012-10-01 14:15:04 +01:00
/**
2014-12-21 17:00:50 +00:00
* Set an input definition set to be used with this application .
2012-10-01 14:15:04 +01:00
*
* @ param InputDefinition $definition The input definition
*
* @ api
*/
public function setDefinition ( InputDefinition $definition )
{
$this -> definition = $definition ;
}
2010-05-06 12:25:53 +01:00
/**
* Gets the InputDefinition related to this Application .
*
* @ return InputDefinition The InputDefinition instance
*/
public function getDefinition ()
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
return $this -> definition ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Gets the help message .
*
* @ return string A help message .
*/
public function getHelp ()
2010-01-04 14:42:28 +00:00
{
2014-09-18 13:22:04 +01:00
return $this -> getLongVersion ();
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Sets whether to catch exceptions or not during commands execution .
*
2014-04-15 11:04:31 +01:00
* @ param bool $boolean Whether to catch exceptions or not during commands execution
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function setCatchExceptions ( $boolean )
2010-01-04 14:42:28 +00:00
{
2014-04-12 18:44:00 +01:00
$this -> catchExceptions = ( bool ) $boolean ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Sets whether to automatically exit after a command execution or not .
*
2014-04-15 11:04:31 +01:00
* @ param bool $boolean Whether to automatically exit after a command execution or not
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function setAutoExit ( $boolean )
2010-01-04 14:42:28 +00:00
{
2014-04-12 18:44:00 +01:00
$this -> autoExit = ( bool ) $boolean ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Gets the name of the application .
*
* @ return string The application name
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function getName ()
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
return $this -> name ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Sets the application name .
*
* @ param string $name The application name
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function setName ( $name )
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
$this -> name = $name ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Gets the application version .
*
* @ return string The application version
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function getVersion ()
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
return $this -> version ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Sets the application version .
*
* @ param string $version The application version
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function setVersion ( $version )
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
$this -> version = $version ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns the long version of the application .
*
* @ return string The long application version
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function getLongVersion ()
2010-01-04 19:01:46 +00:00
{
2010-05-07 15:09:11 +01:00
if ( 'UNKNOWN' !== $this -> getName () && 'UNKNOWN' !== $this -> getVersion ()) {
2010-05-06 12:25:53 +01:00
return sprintf ( '<info>%s</info> version <comment>%s</comment>' , $this -> getName (), $this -> getVersion ());
}
2011-02-27 16:48:41 +00:00
return '<info>Console Tool</info>' ;
2010-01-04 19:01:46 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Registers a new command .
*
* @ param string $name The command name
*
* @ return Command The newly created command
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function register ( $name )
2010-01-04 19:01:46 +00:00
{
2010-11-23 08:42:19 +00:00
return $this -> add ( new Command ( $name ));
2010-01-04 19:01:46 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Adds an array of command objects .
*
* @ param Command [] $commands An array of commands
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
public function addCommands ( array $commands )
2010-01-04 14:42:28 +00:00
{
2010-05-07 15:09:11 +01:00
foreach ( $commands as $command ) {
2010-11-23 08:42:19 +00:00
$this -> add ( $command );
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Adds a command object .
*
* If a command with the same name already exists , it will be overridden .
*
* @ param Command $command A Command object
*
* @ return Command The registered command
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
2010-11-23 08:42:19 +00:00
public function add ( Command $command )
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
$command -> setApplication ( $this );
2011-06-28 23:18:03 +01:00
if ( ! $command -> isEnabled ()) {
$command -> setApplication ( null );
2011-10-29 11:05:45 +01:00
2011-06-28 23:18:03 +01:00
return ;
}
2013-10-08 16:44:03 +01:00
if ( null === $command -> getDefinition ()) {
throw new \LogicException ( sprintf ( 'Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.' , get_class ( $command )));
2013-10-01 11:23:25 +01:00
}
2011-06-07 16:51:43 +01:00
$this -> commands [ $command -> getName ()] = $command ;
2010-05-06 12:25:53 +01:00
2010-05-07 15:09:11 +01:00
foreach ( $command -> getAliases () as $alias ) {
2011-06-07 17:14:15 +01:00
$this -> commands [ $alias ] = $command ;
2010-05-06 12:25:53 +01:00
}
return $command ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns a registered command by name or alias .
*
* @ param string $name The command name or alias
*
* @ return Command A Command object
*
* @ throws \InvalidArgumentException When command name given does not exist
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
2010-11-23 08:42:19 +00:00
public function get ( $name )
2010-01-04 14:42:28 +00:00
{
2011-06-07 17:14:15 +01:00
if ( ! isset ( $this -> commands [ $name ])) {
2010-05-06 12:25:53 +01:00
throw new \InvalidArgumentException ( sprintf ( 'The command "%s" does not exist.' , $name ));
}
2010-01-04 14:42:28 +00:00
2011-06-07 17:14:15 +01:00
$command = $this -> commands [ $name ];
2010-01-04 14:42:28 +00:00
2010-05-07 15:09:11 +01:00
if ( $this -> wantHelps ) {
2010-05-06 12:25:53 +01:00
$this -> wantHelps = false ;
2010-01-04 14:42:28 +00:00
2010-11-23 08:42:19 +00:00
$helpCommand = $this -> get ( 'help' );
2010-05-06 12:25:53 +01:00
$helpCommand -> setCommand ( $command );
2010-01-04 14:42:28 +00:00
2010-05-06 12:25:53 +01:00
return $helpCommand ;
}
2010-01-04 14:42:28 +00:00
2010-05-06 12:25:53 +01:00
return $command ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
2011-02-07 00:34:24 +00:00
* Returns true if the command exists , false otherwise .
2010-05-06 12:25:53 +01:00
*
* @ param string $name The command name or alias
*
2014-04-15 11:04:31 +01:00
* @ return bool true if the command exists , false otherwise
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
2010-11-23 08:42:19 +00:00
public function has ( $name )
2010-01-04 14:42:28 +00:00
{
2011-06-07 17:14:15 +01:00
return isset ( $this -> commands [ $name ]);
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns an array of all unique namespaces used by currently registered commands .
*
* It does not returns the global namespace which always exists .
*
* @ return array An array of namespaces
*/
public function getNamespaces ()
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
$namespaces = array ();
2010-05-07 15:09:11 +01:00
foreach ( $this -> commands as $command ) {
2015-01-07 22:10:19 +00:00
$namespaces = array_merge ( $namespaces , $this -> extractAllNamespaces ( $command -> getName ()));
2011-06-07 16:51:43 +01:00
foreach ( $command -> getAliases () as $alias ) {
2015-01-07 22:10:19 +00:00
$namespaces = array_merge ( $namespaces , $this -> extractAllNamespaces ( $alias ));
2010-05-06 12:25:53 +01:00
}
}
2011-06-07 17:26:00 +01:00
return array_values ( array_unique ( array_filter ( $namespaces )));
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Finds a registered namespace by a name or an abbreviation .
*
2011-02-07 00:34:24 +00:00
* @ param string $namespace A namespace or abbreviation to search for
*
2010-05-06 12:25:53 +01:00
* @ return string A registered namespace
*
* @ throws \InvalidArgumentException When namespace is incorrect or ambiguous
*/
public function findNamespace ( $namespace )
2010-01-04 14:42:28 +00:00
{
2013-04-07 15:34:20 +01:00
$allNamespaces = $this -> getNamespaces ();
2013-08-07 07:55:13 +01:00
$expr = preg_replace_callback ( '{([^:]+|)}' , function ( $matches ) { return preg_quote ( $matches [ 1 ]) . '[^:]*' ; }, $namespace );
$namespaces = preg_grep ( '{^' . $expr . '}' , $allNamespaces );
2012-02-11 19:38:08 +00:00
2013-08-07 07:55:13 +01:00
if ( empty ( $namespaces )) {
$message = sprintf ( 'There are no commands defined in the "%s" namespace.' , $namespace );
2012-08-07 15:16:59 +01:00
2015-06-05 14:31:22 +01:00
if ( $alternatives = $this -> findAlternatives ( $namespace , $allNamespaces )) {
2013-08-07 07:55:13 +01:00
if ( 1 == count ( $alternatives )) {
$message .= " \n \n Did you mean this? \n " ;
} else {
$message .= " \n \n Did you mean one of these? \n " ;
2012-02-11 19:38:08 +00:00
}
2013-08-07 07:55:13 +01:00
$message .= implode ( " \n " , $alternatives );
2013-04-07 15:34:20 +01:00
}
2013-08-07 07:55:13 +01:00
throw new \InvalidArgumentException ( $message );
}
2011-06-07 16:51:43 +01:00
2013-08-07 07:55:13 +01:00
$exact = in_array ( $namespace , $namespaces , true );
2013-11-26 21:48:58 +00:00
if ( count ( $namespaces ) > 1 && ! $exact ) {
throw new \InvalidArgumentException ( sprintf ( 'The namespace "%s" is ambiguous (%s).' , $namespace , $this -> getAbbreviationSuggestions ( array_values ( $namespaces ))));
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:42:28 +00:00
2013-08-07 07:55:13 +01:00
return $exact ? $namespace : reset ( $namespaces );
2010-05-06 12:25:53 +01:00
}
/**
* Finds a command by name or alias .
*
2010-11-23 08:42:19 +00:00
* Contrary to get , this command tries to find the best
2010-05-06 12:25:53 +01:00
* match if you give it an abbreviation of a name or alias .
*
2012-05-15 21:19:31 +01:00
* @ param string $name A command name or a command alias
2010-05-06 12:25:53 +01:00
*
* @ return Command A Command instance
*
* @ throws \InvalidArgumentException When command name is incorrect or ambiguous
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
2010-11-23 08:42:19 +00:00
public function find ( $name )
2010-05-06 12:25:53 +01:00
{
2013-08-07 07:55:13 +01:00
$allCommands = array_keys ( $this -> commands );
$expr = preg_replace_callback ( '{([^:]+|)}' , function ( $matches ) { return preg_quote ( $matches [ 1 ]) . '[^:]*' ; }, $name );
$commands = preg_grep ( '{^' . $expr . '}' , $allCommands );
if ( empty ( $commands ) || count ( preg_grep ( '{^' . $expr . '$}' , $commands )) < 1 ) {
if ( false !== $pos = strrpos ( $name , ':' )) {
// check if a namespace exists and contains commands
$this -> findNamespace ( substr ( $name , 0 , $pos ));
2011-06-07 17:14:15 +01:00
}
2012-02-11 01:58:39 +00:00
$message = sprintf ( 'Command "%s" is not defined.' , $name );
2015-06-05 14:31:22 +01:00
if ( $alternatives = $this -> findAlternatives ( $name , $allCommands )) {
2012-08-07 15:16:59 +01:00
if ( 1 == count ( $alternatives )) {
$message .= " \n \n Did you mean this? \n " ;
} else {
$message .= " \n \n Did you mean one of these? \n " ;
}
2012-02-11 15:33:06 +00:00
$message .= implode ( " \n " , $alternatives );
2012-02-11 01:58:39 +00:00
}
throw new \InvalidArgumentException ( $message );
2010-05-06 12:25:53 +01:00
}
2014-01-06 22:31:09 +00:00
// filter out aliases for commands which are already on the list
if ( count ( $commands ) > 1 ) {
$commandList = $this -> commands ;
$commands = array_filter ( $commands , function ( $nameOrAlias ) use ( $commandList , $commands ) {
$commandName = $commandList [ $nameOrAlias ] -> getName ();
return $commandName === $nameOrAlias || ! in_array ( $commandName , $commands );
});
}
2013-08-07 07:55:13 +01:00
$exact = in_array ( $name , $commands , true );
if ( count ( $commands ) > 1 && ! $exact ) {
$suggestions = $this -> getAbbreviationSuggestions ( array_values ( $commands ));
throw new \InvalidArgumentException ( sprintf ( 'Command "%s" is ambiguous (%s).' , $name , $suggestions ));
2010-05-06 12:25:53 +01:00
}
2013-08-07 07:55:13 +01:00
return $this -> get ( $exact ? $name : reset ( $commands ));
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Gets the commands ( registered in the given namespace if provided ) .
*
* The array keys are the full names and the values the command instances .
*
2012-05-15 21:19:31 +01:00
* @ param string $namespace A namespace name
2010-05-06 12:25:53 +01:00
*
2012-11-01 15:08:59 +00:00
* @ return Command [] An array of Command instances
2011-03-24 08:39:53 +00:00
*
* @ api
2010-05-06 12:25:53 +01:00
*/
2010-11-23 08:42:19 +00:00
public function all ( $namespace = null )
2010-01-04 14:42:28 +00:00
{
2010-05-07 15:09:11 +01:00
if ( null === $namespace ) {
2010-05-06 12:25:53 +01:00
return $this -> commands ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
$commands = array ();
2010-05-07 15:09:11 +01:00
foreach ( $this -> commands as $name => $command ) {
2011-09-26 00:05:02 +01:00
if ( $namespace === $this -> extractNamespace ( $name , substr_count ( $namespace , ':' ) + 1 )) {
2010-05-06 12:25:53 +01:00
$commands [ $name ] = $command ;
}
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
return $commands ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns an array of possible abbreviations given a set of names .
*
2010-07-01 18:38:34 +01:00
* @ param array $names An array of names
2010-05-06 12:25:53 +01:00
*
* @ return array An array of abbreviations
*/
2012-07-09 13:50:58 +01:00
public static function getAbbreviations ( $names )
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
$abbrevs = array ();
2010-05-07 15:09:11 +01:00
foreach ( $names as $name ) {
2013-04-07 15:34:20 +01:00
for ( $len = strlen ( $name ); $len > 0 ; -- $len ) {
2010-05-06 12:25:53 +01:00
$abbrev = substr ( $name , 0 , $len );
2013-04-07 15:34:20 +01:00
$abbrevs [ $abbrev ][] = $name ;
2010-05-06 12:25:53 +01:00
}
}
2010-01-04 14:42:28 +00:00
2010-05-06 12:25:53 +01:00
return $abbrevs ;
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns a text representation of the Application .
*
2014-04-15 11:04:31 +01:00
* @ param string $namespace An optional namespace name
* @ param bool $raw Whether to return raw command list
2010-05-06 12:25:53 +01:00
*
* @ return string A string representing the Application
2013-03-22 13:40:47 +00:00
*
2014-12-29 23:26:56 +00:00
* @ deprecated since version 2.3 , to be removed in 3.0 .
2010-05-06 12:25:53 +01:00
*/
2011-12-17 23:19:10 +00:00
public function asText ( $namespace = null , $raw = false )
2010-01-04 14:42:28 +00:00
{
2015-06-07 07:33:05 +01:00
@ trigger_error ( 'The ' . __METHOD__ . ' method is deprecated since version 2.3 and will be removed in 3.0.' , E_USER_DEPRECATED );
2014-12-21 11:39:54 +00:00
2013-03-22 13:40:47 +00:00
$descriptor = new TextDescriptor ();
2013-07-08 20:00:49 +01:00
$output = new BufferedOutput ( BufferedOutput :: VERBOSITY_NORMAL , ! $raw );
$descriptor -> describe ( $output , $this , array ( 'namespace' => $namespace , 'raw_output' => true ));
2010-01-04 14:42:28 +00:00
2013-07-08 20:00:49 +01:00
return $output -> fetch ();
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
* Returns an XML representation of the Application .
*
2014-04-15 11:04:31 +01:00
* @ param string $namespace An optional namespace name
* @ param bool $asDom Whether to return a DOM or an XML string
2010-05-06 12:25:53 +01:00
*
2013-03-22 13:40:47 +00:00
* @ return string | \DOMDocument An XML string representing the Application
*
2014-12-29 23:26:56 +00:00
* @ deprecated since version 2.3 , to be removed in 3.0 .
2010-05-06 12:25:53 +01:00
*/
public function asXml ( $namespace = null , $asDom = false )
2010-01-04 14:42:28 +00:00
{
2015-06-07 07:33:05 +01:00
@ trigger_error ( 'The ' . __METHOD__ . ' method is deprecated since version 2.3 and will be removed in 3.0.' , E_USER_DEPRECATED );
2014-12-21 11:39:54 +00:00
2013-03-22 13:40:47 +00:00
$descriptor = new XmlDescriptor ();
2010-05-06 12:25:53 +01:00
2013-07-08 20:00:49 +01:00
if ( $asDom ) {
return $descriptor -> getApplicationDocument ( $this , $namespace );
}
$output = new BufferedOutput ();
$descriptor -> describe ( $output , $this , array ( 'namespace' => $namespace ));
return $output -> fetch ();
2010-01-04 14:42:28 +00:00
}
2010-05-06 12:25:53 +01:00
/**
2012-05-09 17:42:13 +01:00
* Renders a caught exception .
2010-05-06 12:25:53 +01:00
*
2014-04-15 11:04:31 +01:00
* @ param \Exception $e An exception instance
2010-05-06 12:25:53 +01:00
* @ param OutputInterface $output An OutputInterface instance
*/
public function renderException ( $e , $output )
2010-01-04 14:42:28 +00:00
{
2011-01-11 07:49:57 +00:00
do {
$title = sprintf ( ' [%s] ' , get_class ( $e ));
2014-05-12 10:19:00 +01:00
2014-04-15 11:04:31 +01:00
$len = $this -> stringWidth ( $title );
2014-05-12 10:19:00 +01:00
2014-04-26 12:09:19 +01:00
$width = $this -> getTerminalWidth () ? $this -> getTerminalWidth () - 1 : PHP_INT_MAX ;
2014-01-11 03:13:54 +00:00
// 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
2014-04-26 12:09:19 +01:00
if ( defined ( 'HHVM_VERSION' ) && $width > 1 << 31 ) {
$width = 1 << 31 ;
}
2013-09-17 13:23:45 +01:00
$formatter = $output -> getFormatter ();
2011-01-11 07:49:57 +00:00
$lines = array ();
2013-01-05 17:54:53 +00:00
foreach ( preg_split ( '/\r?\n/' , $e -> getMessage ()) as $line ) {
2014-04-15 11:04:31 +01:00
foreach ( $this -> splitStringByWidth ( $line , $width - 4 ) as $line ) {
2013-09-17 13:23:45 +01:00
// pre-format lines to get the right string length
2014-04-15 11:04:31 +01:00
$lineLength = $this -> stringWidth ( preg_replace ( '/ \[[^m]*m/' , '' , $formatter -> format ( $line ))) + 4 ;
2013-09-17 13:23:45 +01:00
$lines [] = array ( $line , $lineLength );
$len = max ( $lineLength , $len );
2012-04-06 13:21:18 +01:00
}
2011-01-11 07:49:57 +00:00
}
2010-01-04 14:42:28 +00:00
2013-09-17 13:23:45 +01:00
$messages = array ( '' , '' );
$messages [] = $emptyLine = $formatter -> format ( sprintf ( '<error>%s</error>' , str_repeat ( ' ' , $len )));
2014-04-15 11:04:31 +01:00
$messages [] = $formatter -> format ( sprintf ( '<error>%s%s</error>' , $title , str_repeat ( ' ' , max ( 0 , $len - $this -> stringWidth ( $title )))));
2011-01-11 07:49:57 +00:00
foreach ( $lines as $line ) {
2013-09-17 13:23:45 +01:00
$messages [] = $formatter -> format ( sprintf ( '<error> %s %s</error>' , $line [ 0 ], str_repeat ( ' ' , $len - $line [ 1 ])));
2011-01-11 07:49:57 +00:00
}
2013-09-17 13:23:45 +01:00
$messages [] = $emptyLine ;
$messages [] = '' ;
$messages [] = '' ;
2010-01-04 14:42:28 +00:00
2013-09-17 13:23:45 +01:00
$output -> writeln ( $messages , OutputInterface :: OUTPUT_RAW );
2010-05-06 12:25:53 +01:00
2013-04-25 11:13:01 +01:00
if ( OutputInterface :: VERBOSITY_VERBOSE <= $output -> getVerbosity ()) {
2011-05-27 14:34:13 +01:00
$output -> writeln ( '<comment>Exception trace:</comment>' );
2011-01-11 07:49:57 +00:00
// exception related properties
$trace = $e -> getTrace ();
array_unshift ( $trace , array (
'function' => '' ,
2015-01-21 19:48:04 +00:00
'file' => $e -> getFile () !== null ? $e -> getFile () : 'n/a' ,
'line' => $e -> getLine () !== null ? $e -> getLine () : 'n/a' ,
2014-10-22 19:27:13 +01:00
'args' => array (),
2011-01-11 07:49:57 +00:00
));
2015-03-31 00:07:44 +01:00
for ( $i = 0 , $count = count ( $trace ); $i < $count ; ++ $i ) {
2011-01-11 07:49:57 +00:00
$class = isset ( $trace [ $i ][ 'class' ]) ? $trace [ $i ][ 'class' ] : '' ;
$type = isset ( $trace [ $i ][ 'type' ]) ? $trace [ $i ][ 'type' ] : '' ;
$function = $trace [ $i ][ 'function' ];
$file = isset ( $trace [ $i ][ 'file' ]) ? $trace [ $i ][ 'file' ] : 'n/a' ;
$line = isset ( $trace [ $i ][ 'line' ]) ? $trace [ $i ][ 'line' ] : 'n/a' ;
$output -> writeln ( sprintf ( ' %s%s%s() at <info>%s:%s</info>' , $class , $type , $function , $file , $line ));
}
2010-05-06 12:25:53 +01:00
2015-03-21 10:51:07 +00:00
$output -> writeln ( '' );
$output -> writeln ( '' );
2010-05-06 12:25:53 +01:00
}
2011-01-11 07:49:57 +00:00
} while ( $e = $e -> getPrevious ());
2010-05-06 12:25:53 +01:00
2011-01-11 07:49:57 +00:00
if ( null !== $this -> runningCommand ) {
$output -> writeln ( sprintf ( '<info>%s</info>' , sprintf ( $this -> runningCommand -> getSynopsis (), $this -> getName ())));
2015-03-21 10:51:07 +00:00
$output -> writeln ( '' );
$output -> writeln ( '' );
2010-05-06 12:25:53 +01:00
}
2010-01-04 14:42:28 +00:00
}
2012-04-06 17:25:51 +01:00
/**
2014-12-21 17:00:50 +00:00
* Tries to figure out the terminal width in which this application runs .
2012-04-06 17:25:51 +01:00
*
* @ return int | null
*/
2013-01-05 20:32:06 +00:00
protected function getTerminalWidth ()
2012-04-06 13:21:18 +01:00
{
2013-01-05 17:54:53 +00:00
$dimensions = $this -> getTerminalDimensions ();
2012-04-06 13:21:18 +01:00
2013-01-05 17:54:53 +00:00
return $dimensions [ 0 ];
2012-04-06 13:21:18 +01:00
}
2012-04-06 17:25:51 +01:00
/**
2014-12-21 17:00:50 +00:00
* Tries to figure out the terminal height in which this application runs .
2012-04-06 17:25:51 +01:00
*
* @ return int | null
*/
2013-01-05 20:32:06 +00:00
protected function getTerminalHeight ()
2013-01-05 17:54:53 +00:00
{
$dimensions = $this -> getTerminalDimensions ();
return $dimensions [ 1 ];
}
/**
2014-12-21 17:00:50 +00:00
* Tries to figure out the terminal dimensions based on the current environment .
2013-01-05 17:54:53 +00:00
*
* @ return array Array containing width and height
*/
2013-01-05 20:33:45 +00:00
public function getTerminalDimensions ()
2012-04-06 13:21:18 +01:00
{
2013-07-29 22:04:28 +01:00
if ( $this -> terminalDimensions ) {
return $this -> terminalDimensions ;
}
2014-12-29 12:05:07 +00:00
if ( '\\' === DIRECTORY_SEPARATOR ) {
2013-01-05 17:54:53 +00:00
// extract [w, H] from "wxh (WxH)"
if ( preg_match ( '/^(\d+)x\d+ \(\d+x(\d+)\)$/' , trim ( getenv ( 'ANSICON' )), $matches )) {
return array (( int ) $matches [ 1 ], ( int ) $matches [ 2 ]);
2012-06-16 09:57:49 +01:00
}
2013-01-05 17:54:53 +00:00
// extract [w, h] from "wxh"
if ( preg_match ( '/^(\d+)x(\d+)$/' , $this -> getConsoleMode (), $matches )) {
return array (( int ) $matches [ 1 ], ( int ) $matches [ 2 ]);
2012-06-16 09:57:49 +01:00
}
2012-04-06 13:21:18 +01:00
}
2013-01-05 17:54:53 +00:00
if ( $sttyString = $this -> getSttyColumns ()) {
// extract [w, h] from "rows h; columns w;"
if ( preg_match ( '/rows.(\d+);.columns.(\d+);/i' , $sttyString , $matches )) {
return array (( int ) $matches [ 2 ], ( int ) $matches [ 1 ]);
}
// extract [w, h] from "; h rows; w columns"
if ( preg_match ( '/;.(\d+).rows;.(\d+).columns/i' , $sttyString , $matches )) {
return array (( int ) $matches [ 2 ], ( int ) $matches [ 1 ]);
}
2012-04-06 13:21:18 +01:00
}
2013-01-05 17:54:53 +00:00
return array ( null , null );
2012-04-06 13:21:18 +01:00
}
2013-07-29 22:04:28 +01:00
/**
* Sets terminal dimensions .
*
* Can be useful to force terminal dimensions for functional tests .
*
2014-12-04 20:26:11 +00:00
* @ param int $width The width
* @ param int $height The height
2013-07-29 22:04:28 +01:00
*
* @ return Application The current application
*/
public function setTerminalDimensions ( $width , $height )
{
$this -> terminalDimensions = array ( $width , $height );
return $this ;
}
2013-05-09 09:57:19 +01:00
/**
* Configures the input and output instances based on the user arguments and options .
*
* @ param InputInterface $input An InputInterface instance
* @ param OutputInterface $output An OutputInterface instance
*/
protected function configureIO ( InputInterface $input , OutputInterface $output )
{
if ( true === $input -> hasParameterOption ( array ( '--ansi' ))) {
$output -> setDecorated ( true );
} elseif ( true === $input -> hasParameterOption ( array ( '--no-ansi' ))) {
$output -> setDecorated ( false );
}
if ( true === $input -> hasParameterOption ( array ( '--no-interaction' , '-n' ))) {
$input -> setInteractive ( false );
2014-11-30 08:03:32 +00:00
} elseif ( function_exists ( 'posix_isatty' ) && $this -> getHelperSet () -> has ( 'question' )) {
$inputStream = $this -> getHelperSet () -> get ( 'question' ) -> getInputStream ();
2015-03-29 09:09:29 +01:00
if ( !@ posix_isatty ( $inputStream ) && false === getenv ( 'SHELL_INTERACTIVE' )) {
2013-05-09 09:57:19 +01:00
$input -> setInteractive ( false );
}
}
if ( true === $input -> hasParameterOption ( array ( '--quiet' , '-q' ))) {
$output -> setVerbosity ( OutputInterface :: VERBOSITY_QUIET );
2013-11-21 23:45:21 +00:00
} else {
if ( $input -> hasParameterOption ( '-vvv' ) || $input -> hasParameterOption ( '--verbose=3' ) || $input -> getParameterOption ( '--verbose' ) === 3 ) {
2013-05-09 09:57:19 +01:00
$output -> setVerbosity ( OutputInterface :: VERBOSITY_DEBUG );
2013-11-21 23:45:21 +00:00
} elseif ( $input -> hasParameterOption ( '-vv' ) || $input -> hasParameterOption ( '--verbose=2' ) || $input -> getParameterOption ( '--verbose' ) === 2 ) {
2013-05-09 09:57:19 +01:00
$output -> setVerbosity ( OutputInterface :: VERBOSITY_VERY_VERBOSE );
2013-11-21 23:45:21 +00:00
} elseif ( $input -> hasParameterOption ( '-v' ) || $input -> hasParameterOption ( '--verbose=1' ) || $input -> hasParameterOption ( '--verbose' ) || $input -> getParameterOption ( '--verbose' )) {
2013-05-09 09:57:19 +01:00
$output -> setVerbosity ( OutputInterface :: VERBOSITY_VERBOSE );
}
}
}
2013-03-24 09:08:12 +00:00
/**
* Runs the current command .
*
* If an event dispatcher has been attached to the application ,
* events are also dispatched during the life - cycle of the command .
*
* @ param Command $command A Command instance
* @ param InputInterface $input An Input instance
* @ param OutputInterface $output An Output instance
*
2014-04-15 11:04:31 +01:00
* @ return int 0 if everything went fine , or an error code
2014-07-26 13:09:47 +01:00
*
* @ throws \Exception when the command being run threw an exception
2013-03-24 09:08:12 +00:00
*/
protected function doRunCommand ( Command $command , InputInterface $input , OutputInterface $output )
{
2013-07-09 10:28:35 +01:00
foreach ( $command -> getHelperSet () as $helper ) {
if ( $helper instanceof InputAwareInterface ) {
$helper -> setInput ( $input );
}
}
2013-03-24 09:08:12 +00:00
if ( null === $this -> dispatcher ) {
return $command -> run ( $input , $output );
}
$event = new ConsoleCommandEvent ( $command , $input , $output );
$this -> dispatcher -> dispatch ( ConsoleEvents :: COMMAND , $event );
2013-10-07 15:20:10 +01:00
if ( $event -> commandShouldRun ()) {
try {
$exitCode = $command -> run ( $input , $output );
} catch ( \Exception $e ) {
2015-09-10 09:05:42 +01:00
$event = new ConsoleExceptionEvent ( $command , $input , $output , $e , $e -> getCode ());
$this -> dispatcher -> dispatch ( ConsoleEvents :: EXCEPTION , $event );
2015-09-08 10:52:13 +01:00
2015-09-10 09:05:42 +01:00
$e = $event -> getException ();
2015-09-08 10:52:13 +01:00
2013-10-07 15:20:10 +01:00
$event = new ConsoleTerminateEvent ( $command , $input , $output , $e -> getCode ());
$this -> dispatcher -> dispatch ( ConsoleEvents :: TERMINATE , $event );
2013-03-24 09:08:12 +00:00
2015-09-10 09:05:42 +01:00
throw $e ;
2013-10-07 15:20:10 +01:00
}
} else {
$exitCode = ConsoleCommandEvent :: RETURN_CODE_DISABLED ;
2013-03-24 09:08:12 +00:00
}
$event = new ConsoleTerminateEvent ( $command , $input , $output , $exitCode );
$this -> dispatcher -> dispatch ( ConsoleEvents :: TERMINATE , $event );
return $event -> getExitCode ();
}
2011-02-07 00:34:24 +00:00
/**
* Gets the name of the command based on input .
*
* @ param InputInterface $input The input interface
2011-04-15 20:12:02 +01:00
*
2011-02-07 00:34:24 +00:00
* @ return string The command name
*/
2010-07-01 13:31:45 +01:00
protected function getCommandName ( InputInterface $input )
{
2012-06-24 14:06:01 +01:00
return $input -> getFirstArgument ();
2010-07-01 13:31:45 +01:00
}
2011-10-25 16:11:49 +01:00
/**
* Gets the default input definition .
*
* @ return InputDefinition An InputDefinition instance
*/
protected function getDefaultInputDefinition ()
{
return new InputDefinition ( array (
new InputArgument ( 'command' , InputArgument :: REQUIRED , 'The command to execute' ),
2015-05-15 14:45:10 +01:00
new InputOption ( '--help' , '-h' , InputOption :: VALUE_NONE , 'Display this help message' ),
new InputOption ( '--quiet' , '-q' , InputOption :: VALUE_NONE , 'Do not output any message' ),
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' ),
new InputOption ( '--version' , '-V' , InputOption :: VALUE_NONE , 'Display this application version' ),
new InputOption ( '--ansi' , '' , InputOption :: VALUE_NONE , 'Force ANSI output' ),
new InputOption ( '--no-ansi' , '' , InputOption :: VALUE_NONE , 'Disable ANSI output' ),
2015-01-04 09:47:47 +00:00
new InputOption ( '--no-interaction' , '-n' , InputOption :: VALUE_NONE , 'Do not ask any interactive question' ),
2011-10-25 16:11:49 +01:00
));
}
/**
* Gets the default commands that should always be available .
*
2012-11-01 15:08:59 +00:00
* @ return Command [] An array of default Command instances
2011-10-25 16:11:49 +01:00
*/
protected function getDefaultCommands ()
{
return array ( new HelpCommand (), new ListCommand ());
}
/**
* Gets the default helper set with the helpers that should always be available .
*
* @ return HelperSet A HelperSet instance
*/
protected function getDefaultHelperSet ()
{
return new HelperSet ( array (
new FormatterHelper (),
2014-12-01 19:40:50 +00:00
new DialogHelper ( false ),
new ProgressHelper ( false ),
new TableHelper ( false ),
2014-04-03 09:19:54 +01:00
new DebugFormatterHelper (),
new ProcessHelper (),
2014-04-01 13:42:24 +01:00
new QuestionHelper (),
2011-10-25 16:11:49 +01:00
));
}
2012-04-24 17:59:33 +01:00
/**
2014-12-21 17:00:50 +00:00
* Runs and parses stty - a if it ' s available , suppressing any error output .
2012-04-24 17:59:33 +01:00
*
* @ return string
*/
private function getSttyColumns ()
{
2012-05-21 11:40:20 +01:00
if ( ! function_exists ( 'proc_open' )) {
return ;
}
2012-04-24 17:59:33 +01:00
$descriptorspec = array ( 1 => array ( 'pipe' , 'w' ), 2 => array ( 'pipe' , 'w' ));
$process = proc_open ( 'stty -a | grep columns' , $descriptorspec , $pipes , null , null , array ( 'suppress_errors' => true ));
if ( is_resource ( $process )) {
$info = stream_get_contents ( $pipes [ 1 ]);
2012-10-15 16:06:38 +01:00
fclose ( $pipes [ 1 ]);
fclose ( $pipes [ 2 ]);
proc_close ( $process );
return $info ;
}
}
/**
2014-12-21 17:00:50 +00:00
* Runs and parses mode CON if it ' s available , suppressing any error output .
2012-10-15 16:06:38 +01:00
*
2012-12-13 17:39:04 +00:00
* @ return string < width > x < height > or null if it could not be parsed
2012-10-15 16:06:38 +01:00
*/
private function getConsoleMode ()
{
if ( ! function_exists ( 'proc_open' )) {
return ;
}
$descriptorspec = array ( 1 => array ( 'pipe' , 'w' ), 2 => array ( 'pipe' , 'w' ));
$process = proc_open ( 'mode CON' , $descriptorspec , $pipes , null , null , array ( 'suppress_errors' => true ));
if ( is_resource ( $process )) {
$info = stream_get_contents ( $pipes [ 1 ]);
2012-04-24 17:59:33 +01:00
fclose ( $pipes [ 1 ]);
fclose ( $pipes [ 2 ]);
proc_close ( $process );
2013-01-05 17:54:53 +00:00
if ( preg_match ( '/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/' , $info , $matches )) {
2012-12-13 17:39:04 +00:00
return $matches [ 2 ] . 'x' . $matches [ 1 ];
}
2012-04-24 17:59:33 +01:00
}
}
2011-02-07 00:34:24 +00:00
/**
* Returns abbreviated suggestions in string format .
*
* @ param array $abbrevs Abbreviated suggestions to convert
*
* @ return string A formatted string of abbreviated suggestions
*/
2011-03-11 11:53:42 +00:00
private function getAbbreviationSuggestions ( $abbrevs )
2010-01-04 14:42:28 +00:00
{
2010-05-06 12:25:53 +01:00
return sprintf ( '%s, %s%s' , $abbrevs [ 0 ], $abbrevs [ 1 ], count ( $abbrevs ) > 2 ? sprintf ( ' and %d more' , count ( $abbrevs ) - 2 ) : '' );
2010-01-04 14:42:28 +00:00
}
2011-06-07 16:51:43 +01:00
2011-12-28 09:22:28 +00:00
/**
* Returns the namespace part of the command name .
*
2013-03-22 13:40:47 +00:00
* This method is not part of public API and should not be used directly .
*
2011-12-28 09:22:28 +00:00
* @ param string $name The full name of the command
* @ param string $limit The maximum number of parts of the namespace
*
* @ return string The namespace of the command
*/
2013-03-22 13:40:47 +00:00
public function extractNamespace ( $name , $limit = null )
2011-06-07 16:51:43 +01:00
{
2011-06-07 17:14:15 +01:00
$parts = explode ( ':' , $name );
array_pop ( $parts );
2011-06-07 16:51:43 +01:00
2011-06-07 17:14:15 +01:00
return implode ( ':' , null === $limit ? $parts : array_slice ( $parts , 0 , $limit ));
2011-06-07 16:51:43 +01:00
}
2012-02-11 01:58:39 +00:00
/**
2012-02-12 16:53:56 +00:00
* Finds alternative of $name among $collection ,
2014-12-21 17:00:50 +00:00
* if nothing is found in $collection , try in $abbrevs .
2012-02-11 19:38:08 +00:00
*
2014-12-04 20:26:11 +00:00
* @ param string $name The string
* @ param array | \Traversable $collection The collection
2012-02-11 19:38:08 +00:00
*
* @ return array A sorted array of similar string
*/
2013-08-07 07:55:13 +01:00
private function findAlternatives ( $name , $collection )
2012-05-21 15:06:09 +01:00
{
2013-08-07 07:55:13 +01:00
$threshold = 1e3 ;
2012-02-11 01:58:39 +00:00
$alternatives = array ();
2013-08-07 07:55:13 +01:00
$collectionParts = array ();
2012-02-11 19:38:08 +00:00
foreach ( $collection as $item ) {
2013-08-07 07:55:13 +01:00
$collectionParts [ $item ] = explode ( ':' , $item );
}
2012-02-11 19:38:08 +00:00
2013-08-07 07:55:13 +01:00
foreach ( explode ( ':' , $name ) as $i => $subname ) {
foreach ( $collectionParts as $collectionName => $parts ) {
$exists = isset ( $alternatives [ $collectionName ]);
if ( ! isset ( $parts [ $i ]) && $exists ) {
$alternatives [ $collectionName ] += $threshold ;
continue ;
} elseif ( ! isset ( $parts [ $i ])) {
continue ;
}
$lev = levenshtein ( $subname , $parts [ $i ]);
2014-10-03 16:11:40 +01:00
if ( $lev <= strlen ( $subname ) / 3 || '' !== $subname && false !== strpos ( $parts [ $i ], $subname )) {
2013-08-07 07:55:13 +01:00
$alternatives [ $collectionName ] = $exists ? $alternatives [ $collectionName ] + $lev : $lev ;
} elseif ( $exists ) {
$alternatives [ $collectionName ] += $threshold ;
}
2012-02-11 01:58:39 +00:00
}
}
2013-08-07 07:55:13 +01:00
foreach ( $collection as $item ) {
$lev = levenshtein ( $name , $item );
if ( $lev <= strlen ( $name ) / 3 || false !== strpos ( $item , $name )) {
$alternatives [ $item ] = isset ( $alternatives [ $item ]) ? $alternatives [ $item ] - $lev : $lev ;
2012-02-12 16:53:56 +00:00
}
}
2015-06-05 14:31:22 +01:00
$alternatives = array_filter ( $alternatives , function ( $lev ) use ( $threshold ) { return $lev < 2 * $threshold ; });
2012-02-11 01:58:39 +00:00
asort ( $alternatives );
return array_keys ( $alternatives );
}
2013-12-14 12:57:08 +00:00
/**
* Sets the default Command name .
*
* @ param string $commandName The Command name
*/
public function setDefaultCommand ( $commandName )
{
$this -> defaultCommand = $commandName ;
}
2014-05-12 10:28:39 +01:00
2014-04-15 11:04:31 +01:00
private function stringWidth ( $string )
{
if ( ! function_exists ( 'mb_strwidth' )) {
return strlen ( $string );
}
if ( false === $encoding = mb_detect_encoding ( $string )) {
return strlen ( $string );
}
return mb_strwidth ( $string , $encoding );
}
private function splitStringByWidth ( $string , $width )
{
// str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
// additionally, array_slice() is not enough as some character has doubled width.
// we need a function to split string not by character count but by string width
if ( ! function_exists ( 'mb_strwidth' )) {
return str_split ( $string , $width );
}
if ( false === $encoding = mb_detect_encoding ( $string )) {
return str_split ( $string , $width );
}
$utf8String = mb_convert_encoding ( $string , 'utf8' , $encoding );
$lines = array ();
$line = '' ;
foreach ( preg_split ( '//u' , $utf8String ) as $char ) {
// test if $char could be appended to current line
2014-05-14 14:23:19 +01:00
if ( mb_strwidth ( $line . $char , 'utf8' ) <= $width ) {
2014-04-15 11:04:31 +01:00
$line .= $char ;
continue ;
}
// if not, push current line to array and make new line
$lines [] = str_pad ( $line , $width );
$line = $char ;
}
2015-06-06 07:25:15 +01:00
if ( '' !== $line ) {
2014-04-15 11:04:31 +01:00
$lines [] = count ( $lines ) ? str_pad ( $line , $width ) : $line ;
}
mb_convert_variables ( $encoding , 'utf8' , $lines );
return $lines ;
}
2015-01-07 22:10:19 +00:00
/**
* Returns all namespaces of the command name .
*
* @ param string $name The full name of the command
*
* @ return array The namespaces of the command
*/
private function extractAllNamespaces ( $name )
{
// -1 as third argument is needed to skip the command short name when exploding
$parts = explode ( ':' , $name , - 1 );
$namespaces = array ();
foreach ( $parts as $part ) {
if ( count ( $namespaces )) {
$namespaces [] = end ( $namespaces ) . ':' . $part ;
} else {
$namespaces [] = $part ;
}
}
return $namespaces ;
}
2010-01-04 14:42:28 +00:00
}