Skip to content

Commit aa08fbe

Browse files
bug symfony#61367 [Console] Fix name/alias/usages when an invokable command has an alias (weitzman)
This PR was squashed before being merged into the 7.4 branch. Discussion ---------- [Console] Fix name/alias/usages when an invokable command has an alias | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | yes | New feature? | no <!-- if yes, also update src/**/CHANGELOG.md --> | Deprecations? | no <!-- if yes, also update UPGRADE-*.md and src/**/CHANGELOG.md --> | Issues | | License | MIT Invokable commands don't construct their command name properly when an alias is present. This makes the command uncallable. The name has a pipe and alias appended such as `example:name | my-alias`. This appending is done by `#[AsCommand]`. You can see the effect by looking [the test failure in the first commit](https://github.com/symfony/symfony/actions/runs/16842451165/job/47716168358) to this PR. The PR fixes the issue by removing a `return` when handling of invokables in Command::__construct(). We can mostly use same logic as non-invokables. I discovered this while moving Drush (Drupal's CLI) to invokable commands. Commits ------- c787a07 [Console] Fix name/alias/usages when an invokable command has an alias
2 parents cb78c31 + c787a07 commit aa08fbe

File tree

3 files changed

+15
-19
lines changed

3 files changed

+15
-19
lines changed

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

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,19 @@ public static function getDefaultDescription(): ?string
8989
*/
9090
public function __construct(?string $name = null, ?callable $code = null)
9191
{
92-
$this->definition = new InputDefinition();
93-
9492
if (null !== $code) {
9593
if (!\is_object($code) || $code instanceof \Closure) {
9694
throw new InvalidArgumentException(\sprintf('The command must be an instance of "%s" or an invokable object.', self::class));
9795
}
98-
9996
/** @var AsCommand $attribute */
10097
$attribute = ((new \ReflectionObject($code))->getAttributes(AsCommand::class)[0] ?? null)?->newInstance()
10198
?? throw new LogicException(\sprintf('The command must use the "%s" attribute.', AsCommand::class));
102-
103-
$this->setName($name ?? $attribute->name)
104-
->setDescription($attribute->description ?? '')
105-
->setHelp($attribute->help ?? '')
106-
->setCode($code);
107-
108-
foreach ($attribute->usages as $usage) {
109-
$this->addUsage($usage);
110-
}
111-
112-
return;
99+
$this->setCode($code);
100+
} else {
101+
$attribute = ((new \ReflectionClass(static::class))->getAttributes(AsCommand::class)[0] ?? null)?->newInstance();
113102
}
114103

115-
$attribute = ((new \ReflectionClass(static::class))->getAttributes(AsCommand::class)[0] ?? null)?->newInstance();
116-
104+
$this->definition = new InputDefinition();
117105
if (null === $name) {
118106
if (self::class !== (new \ReflectionMethod($this, 'getDefaultName'))->class) {
119107
trigger_deprecation('symfony/console', '7.3', 'Overriding "Command::getDefaultName()" in "%s" is deprecated and will be removed in Symfony 8.0, use the #[AsCommand] attribute instead.', static::class);
@@ -159,7 +147,7 @@ public function __construct(?string $name = null, ?callable $code = null)
159147
$this->addUsage($usage);
160148
}
161149

162-
if (\is_callable($this) && self::class === (new \ReflectionMethod($this, 'execute'))->getDeclaringClass()->name) {
150+
if (!$code && \is_callable($this) && self::class === (new \ReflectionMethod($this, 'execute'))->getDeclaringClass()->name) {
163151
$this->code = new InvokableCommand($this, $this(...));
164152
}
165153

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,15 @@ public function testRunInteractive()
304304

305305
public function testInvokableCommand()
306306
{
307-
$tester = new CommandTester(new InvokableTestCommand());
307+
$invokable = new InvokableTestCommand();
308+
$command = new Command(null, $invokable);
309+
$this->assertSame('invokable:test', $command->getName());
310+
$this->assertSame(['inv-test'], $command->getAliases());
311+
$this->assertSame(['invokable:test usage1', 'invokable:test usage2'], $command->getUsages());
312+
$this->assertSame('desc', $command->getDescription());
313+
$this->assertSame('help me', $command->getHelp());
314+
315+
$tester = new CommandTester($invokable);
308316

309317
$this->assertSame(Command::SUCCESS, $tester->execute([]));
310318
}

src/Symfony/Component/Console/Tests/Fixtures/InvokableTestCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Symfony\Component\Console\Attribute\AsCommand;
66
use Symfony\Component\Console\Command\Command;
77

8-
#[AsCommand('invokable:test')]
8+
#[AsCommand('invokable:test', aliases: ['inv-test'], usages: ['usage1', 'usage2'], description: 'desc', help: 'help me')]
99
class InvokableTestCommand
1010
{
1111
public function __invoke(): int

0 commit comments

Comments
 (0)