Skip to content

Commit 04157fb

Browse files
Adds AsCommand annotation and ClosureCommand support (#5930)
Co-authored-by: 李铭昕 <715557344@qq.com>
1 parent c268551 commit 04157fb

10 files changed

Lines changed: 436 additions & 10 deletions

File tree

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
"extra": {
4242
"branch-alias": {
4343
"dev-master": "3.0-dev"
44+
},
45+
"hyperf": {
46+
"config": "Hyperf\\Command\\ConfigProvider"
4447
}
4548
}
4649
}

publish/console.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
use Hyperf\Command\Console;
13+
14+
Console::command('hello', function () {
15+
$this->comment('Hello, Hyperf!');
16+
})->describe('This a closure command demo.');

src/Annotation/AsCommand.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Command\Annotation;
13+
14+
use Attribute;
15+
use Hyperf\Di\Annotation\AbstractMultipleAnnotation;
16+
17+
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
18+
final class AsCommand extends AbstractMultipleAnnotation
19+
{
20+
public string $id;
21+
22+
public function __construct(
23+
public string $signature = '',
24+
public string $description = '',
25+
public string $handle = 'handle',
26+
public array $aliases = [],
27+
) {
28+
}
29+
30+
public function collectClass(string $className): void
31+
{
32+
$this->collectMethod($className, $this->handle);
33+
}
34+
35+
public function collectMethod(string $className, ?string $target): void
36+
{
37+
$this->id = sprintf('%s@%s:%s', $className, $target, crc32($this->signature));
38+
39+
parent::collectMethod($className, $target);
40+
}
41+
}

src/AsCommand.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Command;
13+
14+
use Hyperf\Command\Concerns\InteractsWithIO;
15+
use Psr\Container\ContainerInterface;
16+
17+
use function Hyperf\Support\class_uses_recursive;
18+
19+
final class AsCommand extends Command
20+
{
21+
private ParameterParser $parameterParser;
22+
23+
public function __construct(
24+
private ContainerInterface $container,
25+
string $signature,
26+
private string $class,
27+
private string $method,
28+
) {
29+
$this->signature = $signature;
30+
$this->parameterParser = $container->get(ParameterParser::class);
31+
32+
parent::__construct();
33+
}
34+
35+
public function handle()
36+
{
37+
$inputs = array_merge($this->input->getArguments(), $this->input->getOptions());
38+
$parameters = $this->parameterParser->parseMethodParameters($this->class, $this->method, $inputs);
39+
$instance = $this->container->get($this->class);
40+
41+
if (in_array(InteractsWithIO::class, class_uses_recursive($this->class))) {
42+
(function ($input, $output) {
43+
$this->input = $input;
44+
$this->output = $output;
45+
})->call($instance, $this->input, $this->output);
46+
}
47+
48+
return (fn ($method) => $this->{$method}(...$parameters))->call($instance, $this->method);
49+
}
50+
}

src/ClosureCommand.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Command;
13+
14+
use Closure;
15+
use Psr\Container\ContainerInterface;
16+
17+
final class ClosureCommand extends Command
18+
{
19+
private ParameterParser $parameterParser;
20+
21+
public function __construct(
22+
private ContainerInterface $container,
23+
string $signature,
24+
private Closure $closure
25+
) {
26+
$this->signature = $signature;
27+
$this->parameterParser = $container->get(ParameterParser::class);
28+
29+
parent::__construct();
30+
}
31+
32+
public function handle()
33+
{
34+
$inputs = array_merge($this->input->getArguments(), $this->input->getOptions());
35+
$parameters = $this->parameterParser->parseClosureParameters($this->closure, $inputs);
36+
37+
return $this->closure->call($this, ...$parameters);
38+
}
39+
40+
public function describe(string $description): self
41+
{
42+
$this->setDescription($description);
43+
44+
return $this;
45+
}
46+
}

src/Concerns/InteractsWithIO.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public function options()
128128
*/
129129
public function confirm($question, $default = false)
130130
{
131-
return $this->output->confirm($question, $default);
131+
return $this->output?->confirm($question, $default);
132132
}
133133

134134
/**
@@ -140,7 +140,7 @@ public function confirm($question, $default = false)
140140
*/
141141
public function ask($question, $default = null)
142142
{
143-
return $this->output->ask($question, $default);
143+
return $this->output?->ask($question, $default);
144144
}
145145

146146
/**
@@ -172,7 +172,7 @@ public function askWithCompletion($question, $choices, $default = null)
172172
? $question->setAutocompleterCallback($choices)
173173
: $question->setAutocompleterValues($choices);
174174

175-
return $this->output->askQuestion($question);
175+
return $this->output?->askQuestion($question);
176176
}
177177

178178
/**
@@ -188,7 +188,7 @@ public function secret($question, $fallback = true)
188188

189189
$question->setHidden(true)->setHiddenFallback($fallback);
190190

191-
return $this->output->askQuestion($question);
191+
return $this->output?->askQuestion($question);
192192
}
193193

194194
/**
@@ -206,7 +206,7 @@ public function choice($question, array $choices, $default = null, $attempts = n
206206

207207
$question->setMaxAttempts($attempts)->setMultiselect($multiple);
208208

209-
return $this->output->askQuestion($question);
209+
return $this->output?->askQuestion($question);
210210
}
211211

212212
/**
@@ -241,7 +241,7 @@ public function table($headers, $rows, $tableStyle = 'default', array $columnSty
241241
*/
242242
public function withProgressBar($totalSteps, Closure $callback)
243243
{
244-
$bar = $this->output->createProgressBar(
244+
$bar = $this->output?->createProgressBar(
245245
is_iterable($totalSteps) ? count($totalSteps) : $totalSteps
246246
);
247247

@@ -286,7 +286,7 @@ public function line($string, $style = null, $verbosity = null)
286286
{
287287
$styled = $style ? "<{$style}>{$string}</{$style}>" : $string;
288288

289-
$this->output->writeln($styled, $this->parseVerbosity($verbosity));
289+
$this->output?->writeln($styled, $this->parseVerbosity($verbosity));
290290
}
291291

292292
/**
@@ -330,10 +330,10 @@ public function error($string, $verbosity = null)
330330
*/
331331
public function warn($string, $verbosity = null)
332332
{
333-
if (! $this->output->getFormatter()->hasStyle('warning')) {
333+
if (! $this->output?->getFormatter()->hasStyle('warning')) {
334334
$style = new OutputFormatterStyle('yellow');
335335

336-
$this->output->getFormatter()->setStyle('warning', $style);
336+
$this->output?->getFormatter()->setStyle('warning', $style);
337337
}
338338

339339
$this->line($string, 'warning', $verbosity);
@@ -364,7 +364,7 @@ public function alert($string, $verbosity = null)
364364
*/
365365
public function newLine($count = 1)
366366
{
367-
$this->output->newLine($count);
367+
$this->output?->newLine($count);
368368

369369
return $this;
370370
}

src/ConfigProvider.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Command;
13+
14+
use Hyperf\Command\Listener\RegisterCommandListener;
15+
16+
class ConfigProvider
17+
{
18+
public function __invoke(): array
19+
{
20+
return [
21+
'listeners' => [
22+
RegisterCommandListener::class,
23+
],
24+
'publish' => [
25+
[
26+
'id' => 'config',
27+
'description' => 'The console route file of command.',
28+
'source' => __DIR__ . '/../publish/console.php',
29+
'destination' => Console::ROUTE,
30+
],
31+
],
32+
];
33+
}
34+
}

src/Console.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Command;
13+
14+
use Closure;
15+
16+
use function Hyperf\Support\make;
17+
use function Hyperf\Tappable\tap;
18+
19+
class Console
20+
{
21+
public const ROUTE = BASE_PATH . '/config/console.php';
22+
23+
/**
24+
* @var ClosureCommand[]
25+
*/
26+
protected static $commands = [];
27+
28+
public static function command(string $signature, Closure $command): ClosureCommand
29+
{
30+
return tap(make(ClosureCommand::class, [
31+
'signature' => $signature,
32+
'closure' => $command,
33+
]), static function ($handler) {
34+
$handlerId = spl_object_hash($handler);
35+
self::$commands[$handlerId] = $handler;
36+
});
37+
}
38+
39+
/**
40+
* @return ClosureCommand[]
41+
*/
42+
public static function getCommands(): array
43+
{
44+
return self::$commands;
45+
}
46+
}

0 commit comments

Comments
 (0)