Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions bin/demo
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ require __DIR__ . '/../vendor/autoload.php';
use Yannoff\Component\Console\Application;
use Yannoff\Component\Console\Tests\Command\HelloCommand;

$application = new Application('foobar', '0.0.0');
$application = new Application('greeting', '0.0.0');

$application->addCommands([
new HelloCommand(),
]);

$application->run();
$application
->add(new HelloCommand('hello'))
->run();
24 changes: 24 additions & 0 deletions bin/mono
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env php
<?php
/**
* This file is part of the yannoff/console library
* (c) Yannoff (https://github.com/yannoff)
*
* @project yannoff/console
* @link https://github.com/yannoff/console
* @license https://github.com/yannoff/console/blob/master/LICENSE
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

// Mute PHP deprecation warnings & notices
error_reporting(E_ERROR);

require __DIR__ . '/../vendor/autoload.php';

use Yannoff\Component\Console\Application;
use Yannoff\Component\Console\Tests\Command\HelloCommand;

(new Application('greeting - mono', '0.0.0', new HelloCommand('hello')))
->run();
30 changes: 30 additions & 0 deletions bin/multi
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env php
<?php
/**
* This file is part of the yannoff/console library
* (c) Yannoff (https://github.com/yannoff)
*
* @project yannoff/console
* @link https://github.com/yannoff/console
* @license https://github.com/yannoff/console/blob/master/LICENSE
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

// Mute PHP deprecation warnings & notices
error_reporting(E_ERROR);

require __DIR__ . '/../vendor/autoload.php';

use Yannoff\Component\Console\Application;
use Yannoff\Component\Console\Tests\Command\HelloCommand;

$application = new Application('greeting - multi', '0.0.0');

$application->addCommands([
new HelloCommand('ciao'),
new HelloCommand('coucou'),
]);

$application->run();
151 changes: 92 additions & 59 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,32 @@ class Application extends StreamAware implements FormatterAware
protected $commands;

/**
* Name of the default command to be used if none was supplied
* Is this application a Mono-Command Application ?
*
* @var string
* @var bool
*/
protected $default;
protected $mono = false;

/**
* Application constructor.
*
* @param string $name The application name
* @param string $version The application version
* @param string $name The application name
* @param string $version The application version
* @param Command|null $main Main command (only for MCA)
*/
public function __construct($name, $version)
public function __construct($name, $version, Command $main = null)
{
$this->name = $name;
$this->version = $version;
$this->formatter = FormatterFactory::create();

// For Mono-Command Applications, the command can be passed as a 3rd constructor arg
if ($main instanceof Command) {
$this
->add($main)
->mono = true;
}

$this->init();
}

Expand Down Expand Up @@ -153,31 +161,10 @@ public function run($args = [])
}

$this->script = array_shift($args);
$command = array_shift($args);

// Invoke the appropriated command for special global options like --help, --version, etc
switch ($command):
case '--version':
$command = self::COMMAND_VERS;
break;

case 'list':
case '--help':
case '-h':
case '--usage':
$command = self::COMMAND_HELP;
break;

case null:
$command = $this->getDefault();
break;

default:
break;
endswitch;

try {
return $this->get($command)->run($args);
$info = $this->parse($args);
return $this->get($info['command'])->run($info['args']);
} catch (LogicException $e) {
$error = sprintf('%s, exiting.', (string) $e);
$this->iowrite($error);
Expand Down Expand Up @@ -283,28 +270,90 @@ public function getUsage($tab = Formatter::TAB, $width = Formatter::PAD)
$lines[] = sprintf("${tab}%s <command> [<options>] -- [<arguments>]", $this->script);
$lines[] = "<strong>Commands</strong>";

foreach ($this->commands as $name => $command) {
// Don't display help or version commands
if (in_array($name, [self::COMMAND_HELP, self::COMMAND_VERS])) {
continue;
}

foreach ($this->getUserCommands() as $name => $command) {
$lines[] = sprintf("${tab}%-{$width}s %s", $name, $command->getHelp());
}

return implode(Formatter::LF, $lines);
}

/**
* Find command name and arguments from the command-line invocation
*
* @param array $args The command-line parameters list
*
* @return array An associative array of the form ['command' => '...', 'args' => array(...)]
*/
public function parse($args)
{
if (in_array('--version', $args)) {
return [
'command' => self::COMMAND_VERS,
'args' => array_filter($args, function ($a) { return $a !== '--version'; })
];
}

if ($this->isMono()) {
return ['command' => $this->getDefault(), 'args' => $args];
}

$command = array_shift($args);

switch ($command):
case 'list':
case '--help':
case '-h':
case null:
$command = self::COMMAND_HELP;
break;

default:
break;
endswitch;

return ['command' => $command, 'args' => $args];
}

/**
* Setter for the mono-command application flag
*
* @param bool $mono
*
* @return self
*/
public function setMono($mono)
{
$this->mono = $mono;

return $this;
}

/**
* Getter for the mono-command application flag
*
* @return bool
*/
public function isMono()
{
return $this->mono;
}

/**
* @return Command[]
*/
public function getUserCommands()
{
return array_filter($this->commands, function (Command $command) { return (!$command->isSystem()); });
}

/**
* Hook for initialization tasks, called at the end of the constructor:
* - add common commands (help, version)
* - set default command name
*/
protected function init()
{
$this
->addBaseCommands()
->setDefault(self::COMMAND_HELP);
->addBaseCommands();
}

/**
Expand All @@ -326,32 +375,16 @@ public function addBaseCommands()
* Getter for the default command name
*
* @return string
* @throws LogicException If the application has no user-defined command
*/
public function getDefault()
{
return $this->default;
}
$commands = $this->getUserCommands();

/**
* Setter for the default command name
* Allow easy configuration in user-defined applications
*
* @param string|Command $command Name of the default command
* A command object may also be passed, thanks to force to-string type-casting
*
* @return self
* @throws UnknownCommandException
*/
public function setDefault($command)
{
$command = (string) $command;

if (!$this->has($command)) {
throw new UnknownCommandException($command);
if (0 === count($commands)) {
throw new LogicException('Mono-command applications need at least 1 command defined');
}

$this->default = $command;

return $this;
return $commands[0]->getName();
}
}
25 changes: 22 additions & 3 deletions src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -331,18 +331,37 @@ public function getUsage($tab = Formatter::TAB, $width = Formatter::PAD)
return implode(Formatter::LF, $lines) . Formatter::LF;
}

/**
* Discriminate user-defined vs built-in commands
*
* @return bool
*/
public function isSystem()
{
return false;
}

/**
* Get the command synopsis
*
* @param string $tab The tabulation string (defaults to `\n`)
* @param string $tab The tabulation string (defaults to `\t`)
*
* @return string
*/
protected function getSynopsis($tab = Formatter::TAB)
{
$format = "{$tab}%s %s [options] [--] %s";
$help = [];

$help[] = sprintf('%s%s', $tab, $this->application->getScript());

if (! $this->getApplication()->isMono()) {
$help[] = $this->name;
}

$help[] = '[options] [--]';
$help[] = $this->definition->getArgSynopsis();

return sprintf($format, $this->application->getScript(), $this->name, $this->definition->getArgSynopsis());
return implode(' ', $help);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions src/Command/HelpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@
*/
class HelpCommand extends Command
{
/**
* {@inheritdoc}
*/
public function isSystem()
{
return true;
}

/**
* {@inheritdoc}
*/
Expand Down
8 changes: 8 additions & 0 deletions src/Command/VersionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
*/
class VersionCommand extends Command
{
/**
* {@inheritdoc}
*/
public function isSystem()
{
return true;
}

/**
* {@inheritdoc}
*/
Expand Down
3 changes: 1 addition & 2 deletions src/Tests/Command/HelloCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public function configure()
{
// the content of the configure method is almost identical...
$this
->setName('hello')
->setHelp('Hello world')
->setDescription('Hello world demo application')
// ...except for argument type delaration
Expand Down Expand Up @@ -60,7 +59,7 @@ public function execute()
// the same goes for the option getter
$upper = $this->getOption('upper');

$message = 'Hello ' . $name;
$message = ucfirst($this->name) . ' ' . $name;
if ($upper) {
$message = strtoupper($message);
}
Expand Down
Loading