Skip to content

Commit d1f9829

Browse files
committed
feat: allow attch multi level sub-commands to command,group
1 parent cce9850 commit d1f9829

18 files changed

+510
-279
lines changed

examples/Command/TestCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TestCommand extends Command
2323

2424
protected static string $desc = 'this is a test independent command';
2525

26-
protected function commands(): array
26+
protected function subCommands(): array
2727
{
2828
return [
2929
'sub' => static function ($fs, $out): void {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Inhere\Console\Examples\Controller\Attach;
4+
5+
use Inhere\Console\Command;
6+
use Inhere\Console\IO\Input;
7+
use Inhere\Console\IO\Output;
8+
use function vdump;
9+
10+
/**
11+
* class DemoSubCommand
12+
*
13+
* @author inhere
14+
*/
15+
class DemoSubCommand extends Command
16+
{
17+
protected static string $name = 'sub1';
18+
protected static string $desc = 'alone sub command on an group';
19+
20+
public function getOptions(): array
21+
{
22+
return [
23+
'str1' => 'string option1',
24+
's2,str2' => 'string option2',
25+
];
26+
}
27+
28+
/**
29+
* Do execute command
30+
*
31+
* @param Input $input
32+
* @param Output $output
33+
*
34+
* @return void|mixed
35+
*/
36+
protected function execute(Input $input, Output $output)
37+
{
38+
vdump(__METHOD__);
39+
}
40+
}

examples/Controller/HomeController.php

+24-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
use Inhere\Console\Component\Symbol\ArtFont;
1313
use Inhere\Console\Controller;
14+
use Inhere\Console\Examples\Controller\Attach\DemoSubCommand;
15+
use Inhere\Console\Handler\CommandWrapper;
1416
use Inhere\Console\Util\Interact;
1517
use Inhere\Console\Util\ProgressBar;
1618
use Inhere\Console\Util\Show;
@@ -23,6 +25,7 @@
2325
use Toolkit\Stdlib\Php;
2426
use function sleep;
2527
use function trigger_error;
28+
use function vdump;
2629

2730
/**
2831
* default command controller. there are some command usage examples(1)
@@ -74,13 +77,30 @@ protected function init(): void
7477
/**
7578
* @return array
7679
*/
77-
protected function options(): array
80+
protected function getOptions(): array
7881
{
7982
return [
8083
'-c, --common' => 'This is a common option for all sub-commands',
8184
];
8285
}
8386

87+
protected function subCommands(): array
88+
{
89+
return [
90+
DemoSubCommand::class,
91+
CommandWrapper::wrap(static function ($fs) {
92+
vdump(__METHOD__, $fs->getOpts());
93+
}, [
94+
'name' => 'sub2',
95+
'desc' => 'an sub command in group controller',
96+
'options' => [
97+
'int1' => 'int;an int option1',
98+
'i2, int2' => 'int;an int option2',
99+
]
100+
]),
101+
];
102+
}
103+
84104
protected function disabledCommands(): array
85105
{
86106
return ['disabled'];
@@ -207,6 +227,9 @@ public function colorCheckCommand(): void
207227
* --font Set the art font name(allow: {internalFonts}).
208228
* --italic bool;Set the art font type is italic.
209229
* --style Set the art font style.
230+
*
231+
* @param FlagsParser $fs
232+
*
210233
* @return int
211234
*/
212235
public function artFontCommand(FlagsParser $fs): int

examples/Controller/ShowController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static function commandAliases(): array
4343
/**
4444
* @return array
4545
*/
46-
protected function options(): array
46+
protected function getOptions(): array
4747
{
4848
return [
4949
'-c, --common' => 'This is a common option for all sub-commands',

src/Command.php

+21-31
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Inhere\Console\Handler\AbstractHandler;
1414
use ReflectionException;
1515
use Toolkit\PFlag\FlagsParser;
16+
use function array_shift;
1617

1718
/**
1819
* Class Command
@@ -38,22 +39,17 @@ abstract class Command extends AbstractHandler implements CommandInterface
3839
*/
3940
protected ?Controller $group = null;
4041

41-
/**
42-
* @var Command|null
43-
*/
44-
protected ?Command $parent = null;
45-
4642
protected function init(): void
4743
{
48-
$this->commandName = self::getName();
44+
$this->commandName = $this->getRealName();
4945

5046
parent::init();
5147
}
5248

5349
/**
5450
* @return array
5551
*/
56-
public function getArguments(): array
52+
protected function getArguments(): array
5753
{
5854
return [];
5955
}
@@ -63,12 +59,13 @@ public function getArguments(): array
6359
*/
6460
protected function beforeInitFlagsParser(FlagsParser $fs): void
6561
{
62+
$fs->addArgsByRules($this->getArguments());
6663
$fs->setStopOnFistArg(false);
6764

6865
// old mode: options and arguments at method annotations
69-
if ($this->compatible) {
70-
$fs->setSkipOnUndefined(true);
71-
}
66+
// if ($this->compatible) {
67+
// $fs->setSkipOnUndefined(true);
68+
// }
7269
}
7370

7471
/**
@@ -93,31 +90,24 @@ protected function afterInitFlagsParser(FlagsParser $fs): void
9390
}
9491

9592
/**
96-
* @param Command $parent
97-
*/
98-
public function setParent(Command $parent): void
99-
{
100-
$this->parent = $parent;
101-
}
102-
103-
/**
104-
* @return $this
93+
* @param array $args
94+
*
95+
* @return mixed
10596
*/
106-
public function getRoot(): Command
97+
protected function doRun(array $args): mixed
10798
{
108-
if ($this->parent) {
109-
return $this->parent->getRoot();
99+
// if input sub-command name
100+
if (isset($args[0])) {
101+
$first = $args[0];
102+
$rName = $this->resolveAlias($first);
103+
104+
if ($this->isSub($rName)) {
105+
array_shift($args);
106+
return $this->dispatchSub($rName, $args);
107+
}
110108
}
111109

112-
return $this;
113-
}
114-
115-
/**
116-
* @return Command|null
117-
*/
118-
public function getParent(): ?Command
119-
{
120-
return $this->parent;
110+
return parent::doRun($args);
121111
}
122112

123113
/**

src/Component/PharCompiler.php

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use Exception;
1717
use FilesystemIterator;
1818
use Generator;
19-
use Inhere\Console\Util\Helper;
2019
use InvalidArgumentException;
2120
use Iterator;
2221
use Phar;

src/Component/ReadlineCompleter.php

+12-1
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,13 @@ public function isSupported(): bool
4444

4545
/**
4646
* @param callable $completer
47+
*
48+
* @return ReadlineCompleter
4749
*/
48-
public function setCompleter(callable $completer): void
50+
public function setCompleter(callable $completer): static
4951
{
5052
$this->completer = $completer;
53+
return $this;
5154
}
5255

5356
/**
@@ -113,4 +116,12 @@ public function setHistorySize(int $historySize): void
113116
{
114117
$this->historySize = $historySize;
115118
}
119+
120+
/**
121+
* @return callable
122+
*/
123+
public function getCompleter(): callable
124+
{
125+
return $this->completer;
126+
}
116127
}

src/Component/Router.php

+2-15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Inhere\Console\Contract\RouterInterface;
1717
use Inhere\Console\Controller;
1818
use Inhere\Console\IO\Output;
19+
use Inhere\Console\Util\ConsoleUtil;
1920
use Inhere\Console\Util\Helper;
2021
use InvalidArgumentException;
2122
use Toolkit\PFlag\FlagsParser;
@@ -206,7 +207,7 @@ public function addCommand(string $name, string|Closure|CommandInterface $handle
206207
if ($aliases = $handler::aliases()) {
207208
$config['aliases'] = array_merge($config['aliases'], $aliases);
208209
}
209-
} elseif (!is_object($handler) || !$this->isValidCmdObject($handler)) {
210+
} elseif (!is_object($handler) || !ConsoleUtil::isValidCmdObject($handler)) {
210211
Helper::throwInvalidArgument(
211212
'The command handler must is an subclass of %s OR a Closure OR a sub-object of %s',
212213
Command::class,
@@ -230,20 +231,6 @@ public function addCommand(string $name, string|Closure|CommandInterface $handle
230231
return $this;
231232
}
232233

233-
/**
234-
* @param object $handler
235-
*
236-
* @return bool
237-
*/
238-
private function isValidCmdObject(object $handler): bool
239-
{
240-
if ($handler instanceof Command) {
241-
return true;
242-
}
243-
244-
return method_exists($handler, '__invoke');
245-
}
246-
247234
/**
248235
* @param array $commands
249236
*

src/Contract/CommandHandlerInterface.php

+5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ public function getGroupName(): string;
5959
*/
6060
public function getRealName(): string;
6161

62+
/**
63+
* @return string
64+
*/
65+
public function getRealDesc(): string;
66+
6267
/**
6368
* The real group name.
6469
*

src/Controller.php

+10-5
Original file line numberDiff line numberDiff line change
@@ -300,21 +300,26 @@ public function doRun(array $args): mixed
300300
// convert 'boo-foo' to 'booFoo'
301301
$this->action = $action = Str::camelCase($command);
302302
$this->debugf("will run the '%s' group action: %s, subcommand: %s", $name, $action, $command);
303-
$this->actionMethod = $method = $this->getMethodName($action);
303+
$method = $this->getMethodName($action);
304304

305305
// fire event
306306
$this->fire(ConsoleEvent::COMMAND_RUN_BEFORE, $this);
307307
$this->beforeRun();
308308

309309
// check method not exist
310-
// - if command method not exists.
311310
if (!method_exists($this, $method)) {
311+
if ($this->isSub($command)) {
312+
return $this->dispatchSub($command, $args);
313+
}
314+
315+
// if command not exists.
312316
return $this->handleNotFound($name, $action, $args);
313317
}
314318

315319
// init flags for subcommand
316320
$fs = $this->newActionFlags();
317321

322+
$this->actionMethod = $method;
318323
$this->input->setFs($fs);
319324
$this->debugf('load flags by configure method, subcommand: %s', $command);
320325
$this->configure();
@@ -485,9 +490,9 @@ protected function newActionFlags(string $action = ''): FlagsParser
485490
});
486491

487492
// old mode: options and arguments at method annotations
488-
if ($this->compatible) {
489-
$fs->setSkipOnUndefined(true);
490-
}
493+
// if ($this->compatible) {
494+
// $fs->setSkipOnUndefined(true);
495+
// }
491496

492497
// save
493498
$this->subFss[$action] = $fs;

0 commit comments

Comments
 (0)