Skip to content

Commit beea196

Browse files
committed
Add support for Invokable Commands in CommandTester
1 parent 50d7b25 commit beea196

File tree

4 files changed

+45
-1
lines changed

4 files changed

+45
-1
lines changed

src/Symfony/Component/Console/Command/Command.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,26 @@ public static function getDefaultDescription(): ?string
8282
return null;
8383
}
8484

85+
/**
86+
* Creates a Command from an object that uses #[AsCommand] attribute.
87+
*/
88+
public static function createFromAttribute(object $command) : self
89+
{
90+
if ($command instanceof self) {
91+
return $command;
92+
}
93+
94+
if (!is_callable($command)) {
95+
throw new \InvalidArgumentException(\sprintf('The command "%s" must be a callable.', $command::class));
96+
}
97+
98+
if (!$attribute = (new \ReflectionClass($command))->getAttributes(AsCommand::class)) {
99+
throw new \InvalidArgumentException(\sprintf('The command "%s" does not have the `#[%s]` attribute.', $command::class, AsCommand::class));
100+
}
101+
102+
return (new self($attribute[0]->newInstance()->name))->setCode($command);
103+
}
104+
85105
/**
86106
* @param string|null $name The name of the command; passing null means it must be set in configure()
87107
*

src/Symfony/Component/Console/Tester/CommandTester.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ class CommandTester
2424
{
2525
use TesterTrait;
2626

27+
private Command $command;
28+
2729
public function __construct(
28-
private Command $command,
30+
object $command,
2931
) {
32+
$this->command = Command::createFromAttribute($command);
3033
}
3134

3235
/**

src/Symfony/Component/Console/Tests/Command/CommandTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static function setUpBeforeClass(): void
3838
{
3939
self::$fixturesPath = __DIR__.'/../Fixtures/';
4040
require_once self::$fixturesPath.'/TestCommand.php';
41+
require_once self::$fixturesPath.'/InvokableTestCommand.php';
4142
}
4243

4344
public function testConstructor()
@@ -304,6 +305,13 @@ public function testRunInteractive()
304305
$this->assertEquals('interact called'.\PHP_EOL.'execute called'.\PHP_EOL, $tester->getDisplay(), '->run() calls the interact() method if the input is interactive');
305306
}
306307

308+
public function testInvokableCommand()
309+
{
310+
$tester = new CommandTester(new \InvokableTestCommand());
311+
312+
$this->assertSame(Command::SUCCESS, $tester->execute([]));
313+
}
314+
307315
public function testRunNonInteractive()
308316
{
309317
$tester = new CommandTester(new \TestCommand());
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use Symfony\Component\Console\Attribute\AsCommand;
4+
use Symfony\Component\Console\Command\Command;
5+
6+
#[AsCommand('invokable:test')]
7+
class InvokableTestCommand
8+
{
9+
public function __invoke(): int
10+
{
11+
return Command::SUCCESS;
12+
}
13+
}

0 commit comments

Comments
 (0)