Skip to content

Commit ee7d4a4

Browse files
committed
[application] Improve Mono-Command Apps support
1 parent a85b986 commit ee7d4a4

8 files changed

Lines changed: 189 additions & 70 deletions

File tree

bin/demo

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ require __DIR__ . '/../vendor/autoload.php';
2020
use Yannoff\Component\Console\Application;
2121
use Yannoff\Component\Console\Tests\Command\HelloCommand;
2222

23-
$application = new Application('foobar', '0.0.0');
23+
$application = new Application('greeting', '0.0.0');
2424

25-
$application->addCommands([
26-
new HelloCommand(),
27-
]);
28-
29-
$application->run();
25+
$application
26+
->add(new HelloCommand('hello'))
27+
->run();

bin/mono

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env php
2+
<?php
3+
/**
4+
* This file is part of the yannoff/console library
5+
* (c) Yannoff (https://github.com/yannoff)
6+
*
7+
* @project yannoff/console
8+
* @link https://github.com/yannoff/console
9+
* @license https://github.com/yannoff/console/blob/master/LICENSE
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
// Mute PHP deprecation warnings & notices
16+
error_reporting(E_ERROR);
17+
18+
require __DIR__ . '/../vendor/autoload.php';
19+
20+
use Yannoff\Component\Console\Application;
21+
use Yannoff\Component\Console\Tests\Command\HelloCommand;
22+
23+
(new Application('greeting - mono', '0.0.0', new HelloCommand('hello')))
24+
->run();

bin/multi

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env php
2+
<?php
3+
/**
4+
* This file is part of the yannoff/console library
5+
* (c) Yannoff (https://github.com/yannoff)
6+
*
7+
* @project yannoff/console
8+
* @link https://github.com/yannoff/console
9+
* @license https://github.com/yannoff/console/blob/master/LICENSE
10+
*
11+
* For the full copyright and license information, please view the LICENSE
12+
* file that was distributed with this source code.
13+
*/
14+
15+
// Mute PHP deprecation warnings & notices
16+
error_reporting(E_ERROR);
17+
18+
require __DIR__ . '/../vendor/autoload.php';
19+
20+
use Yannoff\Component\Console\Application;
21+
use Yannoff\Component\Console\Tests\Command\HelloCommand;
22+
23+
$application = new Application('greeting - multi', '0.0.0');
24+
25+
$application->addCommands([
26+
new HelloCommand('ciao'),
27+
new HelloCommand('coucou'),
28+
]);
29+
30+
$application->run();

src/Application.php

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -77,24 +77,32 @@ class Application extends StreamAware implements FormatterAware
7777
protected $commands;
7878

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

8686
/**
8787
* Application constructor.
8888
*
89-
* @param string $name The application name
90-
* @param string $version The application version
89+
* @param string $name The application name
90+
* @param string $version The application version
91+
* @param Command|null $main Main command (only for MCA)
9192
*/
92-
public function __construct($name, $version)
93+
public function __construct($name, $version, Command $main = null)
9394
{
9495
$this->name = $name;
9596
$this->version = $version;
9697
$this->formatter = FormatterFactory::create();
9798

99+
// For Mono-Command Applications, the command can be passed as a 3rd constructor arg
100+
if ($main instanceof Command) {
101+
$this
102+
->add($main)
103+
->mono = true;
104+
}
105+
98106
$this->init();
99107
}
100108

@@ -153,31 +161,10 @@ public function run($args = [])
153161
}
154162

155163
$this->script = array_shift($args);
156-
$command = array_shift($args);
157-
158-
// Invoke the appropriated command for special global options like --help, --version, etc
159-
switch ($command):
160-
case '--version':
161-
$command = self::COMMAND_VERS;
162-
break;
163-
164-
case 'list':
165-
case '--help':
166-
case '-h':
167-
case '--usage':
168-
$command = self::COMMAND_HELP;
169-
break;
170-
171-
case null:
172-
$command = $this->getDefault();
173-
break;
174-
175-
default:
176-
break;
177-
endswitch;
178164

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

286-
foreach ($this->commands as $name => $command) {
287-
// Don't display help or version commands
288-
if (in_array($name, [self::COMMAND_HELP, self::COMMAND_VERS])) {
289-
continue;
290-
}
291-
273+
foreach ($this->getUserCommands() as $name => $command) {
292274
$lines[] = sprintf("${tab}%-{$width}s %s", $name, $command->getHelp());
293275
}
294276

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

280+
/**
281+
* Find command name and arguments from the command-line invocation
282+
*
283+
* @param array $args The command-line parameters list
284+
*
285+
* @return array An associative array of the form ['command' => '...', 'args' => array(...)]
286+
*/
287+
public function parse($args)
288+
{
289+
if (in_array('--version', $args)) {
290+
return [
291+
'command' => self::COMMAND_VERS,
292+
'args' => array_filter($args, function ($a) { return $a !== '--version'; })
293+
];
294+
}
295+
296+
if ($this->isMono()) {
297+
return ['command' => $this->getDefault(), 'args' => $args];
298+
}
299+
300+
$command = array_shift($args);
301+
302+
switch ($command):
303+
case 'list':
304+
case '--help':
305+
case '-h':
306+
case null:
307+
$command = self::COMMAND_HELP;
308+
break;
309+
310+
default:
311+
break;
312+
endswitch;
313+
314+
return ['command' => $command, 'args' => $args];
315+
}
316+
317+
/**
318+
* Setter for the mono-command application flag
319+
*
320+
* @param bool $mono
321+
*
322+
* @return self
323+
*/
324+
public function setMono($mono)
325+
{
326+
$this->mono = $mono;
327+
328+
return $this;
329+
}
330+
331+
/**
332+
* Getter for the mono-command application flag
333+
*
334+
* @return bool
335+
*/
336+
public function isMono()
337+
{
338+
return $this->mono;
339+
}
340+
341+
/**
342+
* @return Command[]
343+
*/
344+
public function getUserCommands()
345+
{
346+
return array_filter($this->commands, function (Command $command) { return (!$command->isSystem()); });
347+
}
348+
298349
/**
299350
* Hook for initialization tasks, called at the end of the constructor:
300351
* - add common commands (help, version)
301-
* - set default command name
302352
*/
303353
protected function init()
304354
{
305355
$this
306-
->addBaseCommands()
307-
->setDefault(self::COMMAND_HELP);
356+
->addBaseCommands();
308357
}
309358

310359
/**
@@ -326,32 +375,16 @@ public function addBaseCommands()
326375
* Getter for the default command name
327376
*
328377
* @return string
378+
* @throws LogicException If the application has no user-defined command
329379
*/
330380
public function getDefault()
331381
{
332-
return $this->default;
333-
}
382+
$commands = $this->getUserCommands();
334383

335-
/**
336-
* Setter for the default command name
337-
* Allow easy configuration in user-defined applications
338-
*
339-
* @param string|Command $command Name of the default command
340-
* A command object may also be passed, thanks to force to-string type-casting
341-
*
342-
* @return self
343-
* @throws UnknownCommandException
344-
*/
345-
public function setDefault($command)
346-
{
347-
$command = (string) $command;
348-
349-
if (!$this->has($command)) {
350-
throw new UnknownCommandException($command);
384+
if (0 === count($commands)) {
385+
throw new LogicException('Mono-command applications need at least 1 command defined');
351386
}
352387

353-
$this->default = $command;
354-
355-
return $this;
388+
return $commands[0]->getName();
356389
}
357390
}

src/Command.php

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,18 +331,37 @@ public function getUsage($tab = Formatter::TAB, $width = Formatter::PAD)
331331
return implode(Formatter::LF, $lines) . Formatter::LF;
332332
}
333333

334+
/**
335+
* Discriminate user-defined vs built-in commands
336+
*
337+
* @return bool
338+
*/
339+
public function isSystem()
340+
{
341+
return false;
342+
}
343+
334344
/**
335345
* Get the command synopsis
336346
*
337-
* @param string $tab The tabulation string (defaults to `\n`)
347+
* @param string $tab The tabulation string (defaults to `\t`)
338348
*
339349
* @return string
340350
*/
341351
protected function getSynopsis($tab = Formatter::TAB)
342352
{
343-
$format = "{$tab}%s %s [options] [--] %s";
353+
$help = [];
354+
355+
$help[] = sprintf('%s%s', $tab, $this->application->getScript());
356+
357+
if (! $this->getApplication()->isMono()) {
358+
$help[] = $this->name;
359+
}
360+
361+
$help[] = '[options] [--]';
362+
$help[] = $this->definition->getArgSynopsis();
344363

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

348367
/**

src/Command/HelpCommand.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
*/
2828
class HelpCommand extends Command
2929
{
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public function isSystem()
34+
{
35+
return true;
36+
}
37+
3038
/**
3139
* {@inheritdoc}
3240
*/

src/Command/VersionCommand.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
*/
2626
class VersionCommand extends Command
2727
{
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
public function isSystem()
32+
{
33+
return true;
34+
}
35+
2836
/**
2937
* {@inheritdoc}
3038
*/

src/Tests/Command/HelloCommand.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ public function configure()
3131
{
3232
// the content of the configure method is almost identical...
3333
$this
34-
->setName('hello')
3534
->setHelp('Hello world')
3635
->setDescription('Hello world demo application')
3736
// ...except for argument type delaration
@@ -60,7 +59,7 @@ public function execute()
6059
// the same goes for the option getter
6160
$upper = $this->getOption('upper');
6261

63-
$message = 'Hello ' . $name;
62+
$message = ucfirst($this->name). ' ' . $name;
6463
if ($upper) {
6564
$message = strtoupper($message);
6665
}

0 commit comments

Comments
 (0)