Added as command for static method (#6978)

This commit is contained in:
宣言就是Siam 2024-07-31 13:43:47 +08:00 committed by GitHub
parent e2191cfa73
commit 4414bd2965
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 76 additions and 5 deletions

View File

@ -1,5 +1,9 @@
# v3.1.34 - TBD # v3.1.34 - TBD
## Added
- [#6978](https://github.com/hyperf/hyperf/pull/6978) Added as command for static method.
# v3.1.33 - 2024-07-25 # v3.1.33 - 2024-07-25
## Optimized ## Optimized

View File

@ -12,7 +12,9 @@ declare(strict_types=1);
namespace Hyperf\Command; namespace Hyperf\Command;
use Closure;
use Hyperf\Command\Concerns\InteractsWithIO; use Hyperf\Command\Concerns\InteractsWithIO;
use Hyperf\Di\ReflectionManager;
use Hyperf\Stringable\Str; use Hyperf\Stringable\Str;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
@ -56,6 +58,12 @@ final class AsCommand extends Command
{ {
$inputs = array_merge($this->input->getArguments(), $this->input->getOptions()); $inputs = array_merge($this->input->getArguments(), $this->input->getOptions());
$parameters = $this->parameterParser->parseMethodParameters($this->class, $this->method, $inputs); $parameters = $this->parameterParser->parseMethodParameters($this->class, $this->method, $inputs);
if (ReflectionManager::reflectMethod($this->class, $this->method)->isStatic()) {
Closure::bind(fn ($method) => self::{$method}(...$parameters), null, $this->class)($this->method);
return;
}
$instance = $this->container->get($this->class); $instance = $this->container->get($this->class);
if (in_array(InteractsWithIO::class, class_uses_recursive($this->class))) { if (in_array(InteractsWithIO::class, class_uses_recursive($this->class))) {

View File

@ -17,6 +17,7 @@ use Hyperf\Crontab\Crontab;
use Hyperf\Crontab\Schedule; use Hyperf\Crontab\Schedule;
use Hyperf\Stringable\Str; use Hyperf\Stringable\Str;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use ReflectionFunction;
use function Hyperf\Tappable\tap; use function Hyperf\Tappable\tap;
@ -57,6 +58,12 @@ final class ClosureCommand extends Command
{ {
$inputs = array_merge($this->input->getArguments(), $this->input->getOptions()); $inputs = array_merge($this->input->getArguments(), $this->input->getOptions());
$parameters = $this->parameterParser->parseClosureParameters($this->closure, $inputs); $parameters = $this->parameterParser->parseClosureParameters($this->closure, $inputs);
$ref = new ReflectionFunction($this->closure);
if ($ref->isStatic()) {
($this->closure)(...$parameters);
return;
}
$this->closure->call($this, ...$parameters); $this->closure->call($this, ...$parameters);
} }

View File

@ -37,6 +37,9 @@ use HyperfTest\Command\Command\Annotation\TestAsCommand;
use Mockery; use Mockery;
use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use RuntimeException;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
/** /**
* @internal * @internal
@ -84,7 +87,7 @@ class AsCommandAndClosureCommandTest extends TestCase
); );
$commands = array_values($this->containerSet); $commands = array_values($this->containerSet);
$this->assertCount(3, $commands); $this->assertCount(4, $commands);
$runCommand = $commands[0]; $runCommand = $commands[0];
$runCommandDefinition = $runCommand->getDefinition(); $runCommandDefinition = $runCommand->getDefinition();
@ -110,29 +113,71 @@ class AsCommandAndClosureCommandTest extends TestCase
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('name')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('name'));
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('age')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('age'));
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('testBool')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('testBool'));
$runStaticCommand = $commands[3];
$runStaticCommand->setInput(new ArrayInput([]));
$runStaticCommand->setOutput(new BufferedOutput());
$runStaticCommandDefinition = $runStaticCommand->getDefinition();
$this->assertEquals($this->getSignature($runStaticCommand), 'command:as-command:runStatic');
$this->assertEquals(count($runStaticCommandDefinition->getOptions()), 1);
$this->assertEquals(count($runStaticCommandDefinition->getArguments()), 0);
// assert runtime exception
try {
$runStaticCommand->handle();
} catch (RuntimeException $e) {
$this->assertEquals('command:as-command:runStatic', $e->getMessage());
}
} }
public function testRegisterClosureCommand() public function testRegisterClosureCommand()
{ {
$runCommand = Console::command('command:closure:run', function () { $runCommand = Console::command('command:closure:run', function () {
return 'closure'; throw new RuntimeException('command:closure:run');
}); });
$runCommand->setInput(new ArrayInput([]));
$runCommand->setOutput(new BufferedOutput());
$runCommandDefinition = $runCommand->getDefinition(); $runCommandDefinition = $runCommand->getDefinition();
$this->assertEquals($this->getSignature($runCommand), 'command:closure:run'); $this->assertEquals($this->getSignature($runCommand), 'command:closure:run');
$this->assertEquals(count($runCommandDefinition->getOptions()), 1); $this->assertEquals(count($runCommandDefinition->getOptions()), 1);
$this->assertEquals(count($runCommandDefinition->getArguments()), 0); $this->assertEquals(count($runCommandDefinition->getArguments()), 0);
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher')); $this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher'));
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('command:closure:run');
$runCommand->handle();
}
public function testRegisterStaticClosureCommand()
{
$runCommand = Console::command('command:closure:run-static', static function () {
throw new RuntimeException('command:closure:run-static');
});
$runCommand->setInput(new ArrayInput([]));
$runCommand->setOutput(new BufferedOutput());
$runCommandDefinition = $runCommand->getDefinition();
$this->assertEquals($this->getSignature($runCommand), 'command:closure:run-static');
$this->assertEquals(count($runCommandDefinition->getOptions()), 1);
$this->assertEquals(count($runCommandDefinition->getArguments()), 0);
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher'));
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('command:closure:run-static');
$runCommand->handle();
}
public function testRegisterClosureCommandWithDefineOptions()
{
$runWithDefinedOptionsCommand = Console::command('command:closure:withDefineOptions {--name=}', function (string $name) { $runWithDefinedOptionsCommand = Console::command('command:closure:withDefineOptions {--name=}', function (string $name) {
return 'with define options'; return $name;
}); });
$runWithDefinedOptionsCommandDefinition = $runWithDefinedOptionsCommand->getDefinition(); $runWithDefinedOptionsCommandDefinition = $runWithDefinedOptionsCommand->getDefinition();
$this->assertEquals($this->getSignature($runWithDefinedOptionsCommand), 'command:closure:withDefineOptions {--name=}'); $this->assertEquals($this->getSignature($runWithDefinedOptionsCommand), 'command:closure:withDefineOptions {--name=}');
$this->assertEquals(count($runWithDefinedOptionsCommandDefinition->getOptions()), 2); $this->assertEquals(count($runWithDefinedOptionsCommandDefinition->getOptions()), 2);
$this->assertEquals(count($runWithDefinedOptionsCommandDefinition->getArguments()), 0); $this->assertEquals(count($runWithDefinedOptionsCommandDefinition->getArguments()), 0);
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher')); $this->assertNotNull($runWithDefinedOptionsCommandDefinition->getOption('disable-event-dispatcher'));
$this->assertNotNull($runWithDefinedOptionsCommandDefinition->getOption('name')); $this->assertNotNull($runWithDefinedOptionsCommandDefinition->getOption('name'));
}
public function testRegisterClosureCommandWithoutDefineOptions()
{
$runWithoutOptionsCommand = Console::command('command:closure:withoutDefineOptions', function (string $name, int $age = 9, bool $testBool = false) { $runWithoutOptionsCommand = Console::command('command:closure:withoutDefineOptions', function (string $name, int $age = 9, bool $testBool = false) {
return 'with define options'; return 'with define options';
}); });
@ -140,7 +185,7 @@ class AsCommandAndClosureCommandTest extends TestCase
$this->assertEquals($this->getSignature($runWithoutOptionsCommand), 'command:closure:withoutDefineOptions'); $this->assertEquals($this->getSignature($runWithoutOptionsCommand), 'command:closure:withoutDefineOptions');
$this->assertEquals(count($runWithoutOptionsCommandDefinition->getOptions()), 4); $this->assertEquals(count($runWithoutOptionsCommandDefinition->getOptions()), 4);
$this->assertEquals(count($runWithoutOptionsCommandDefinition->getArguments()), 0); $this->assertEquals(count($runWithoutOptionsCommandDefinition->getArguments()), 0);
$this->assertNotNull($runCommandDefinition->getOption('disable-event-dispatcher')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('disable-event-dispatcher'));
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('name')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('name'));
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('age')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('age'));
$this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('testBool')); $this->assertNotNull($runWithoutOptionsCommandDefinition->getOption('testBool'));

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace HyperfTest\Command\Command\Annotation; namespace HyperfTest\Command\Command\Annotation;
use Hyperf\Command\Annotation\AsCommand; use Hyperf\Command\Annotation\AsCommand;
use RuntimeException;
class TestAsCommand class TestAsCommand
{ {
@ -33,4 +34,10 @@ class TestAsCommand
{ {
return 'runWithoutOptions'; return 'runWithoutOptions';
} }
#[AsCommand('command:as-command:runStatic')]
protected static function runStatic()
{
throw new RuntimeException('command:as-command:runStatic');
}
} }