Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Console] Allow Usages to be specified via #[AsCommand] attribute #60767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Symfony/Component/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,10 @@ public function addCommand(callable|Command $command): ?Command
->setDescription($attribute->description ?? '')
->setHelp($attribute->help ?? '')
->setCode($command);

foreach ($attribute->usages as $usage) {
$command->addUsage($usage);
}
}

$command->setApplication($this);
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Console/Attribute/AsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ class AsCommand
* @param string[] $aliases The list of aliases of the command. The command will be executed when using one of them (i.e. "cache:clean")
* @param bool $hidden If true, the command won't be shown when listing all the available commands, but it can still be run as any other command
* @param string|null $help The help content of the command, displayed with the help page
* @param string[] $usages The list of usage examples, displayed with the help page
*/
public function __construct(
public string $name,
public ?string $description = null,
array $aliases = [],
bool $hidden = false,
public ?string $help = null,
public array $usages = [],
) {
if (!$hidden && !$aliases) {
return;
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CHANGELOG
* Introduce `Symfony\Component\Console\Application::addCommand()` to simplify using invokable commands when the component is used standalone
* Deprecate `Symfony\Component\Console\Application::add()` in favor of `Symfony\Component\Console\Application::addCommand()`
* Add `BackedEnum` support with `#[Argument]` and `#[Option]` inputs in invokable commands
* Allow Usages to be specified via #[AsCommand] attribute.

7.3
---
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Component/Console/Command/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ public function __construct(?string $name = null)
$this->setHelp($attribute?->help ?? '');
}

foreach ($attribute?->usages ?? [] as $usage) {
$this->addUsage($usage);
}

if (\is_callable($this) && (new \ReflectionMethod($this, 'execute'))->getDeclaringClass()->name === self::class) {
$this->code = new InvokableCommand($this, $this(...));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public function process(ContainerBuilder $container): void

$description = $tags[0]['description'] ?? null;
$help = $tags[0]['help'] ?? null;
$usages = $tags[0]['usages'] ?? null;

unset($tags[0]);
$lazyCommandMap[$commandName] = $id;
Expand All @@ -108,6 +109,7 @@ public function process(ContainerBuilder $container): void

$description ??= $tag['description'] ?? null;
$help ??= $tag['help'] ?? null;
$usages ??= $tag['usages'] ?? null;
}

$definition->addMethodCall('setName', [$commandName]);
Expand All @@ -124,6 +126,12 @@ public function process(ContainerBuilder $container): void
$definition->addMethodCall('setHelp', [str_replace('%', '%%', $help)]);
}

if ($usages) {
foreach ($usages as $usage) {
$definition->addMethodCall('addUsage', [$usage]);
}
}

if (!$description) {
if (Command::class !== (new \ReflectionMethod($class, 'getDefaultDescription'))->class) {
trigger_deprecation('symfony/console', '7.3', 'Overriding "Command::getDefaultDescription()" in "%s" is deprecated and will be removed in Symfony 8.0, use the #[AsCommand] attribute instead.', $class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ public function testCommandAttribute()
$this->assertSame('foo', $command->getName());
$this->assertSame('desc', $command->getDescription());
$this->assertSame('help', $command->getHelp());
$this->assertCount(2, $command->getUsages());
$this->assertStringContainsString('usage1', $command->getUsages()[0]);
$this->assertTrue($command->isHidden());
$this->assertSame(['f'], $command->getAliases());
}
Expand Down Expand Up @@ -542,7 +544,7 @@ function createClosure()
};
}

#[AsCommand(name: 'foo', description: 'desc', hidden: true, aliases: ['f'], help: 'help')]
#[AsCommand(name: 'foo', description: 'desc', usages: ['usage1', 'usage2'], hidden: true, aliases: ['f'], help: 'help')]
class Php8Command extends Command
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ public function testProcessInvokableCommand()
$definition->addTag('console.command', [
'command' => 'invokable',
'description' => 'The command description',
'usages' => ['usage1', 'usage2'],
'help' => 'The %command.name% command help content.',
]);
$container->setDefinition('invokable_command', $definition);
Expand All @@ -325,6 +326,8 @@ public function testProcessInvokableCommand()
self::assertTrue($container->has('invokable_command.command'));
self::assertSame('The command description', $command->getDescription());
self::assertSame('The %command.name% command help content.', $command->getHelp());
self::assertCount(2, $command->getUsages());
$this->assertStringContainsString('usage1', $command->getUsages()[0]);
}

public function testProcessInvokableSignalableCommand()
Expand Down
Loading