From 62172db2629c0c959f4006458f9bb4d58726b960 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Wed, 29 May 2024 12:24:43 +0200 Subject: [PATCH 1/2] Add the definition option int AsCommand attribute --- .../Component/Console/Attribute/AsCommand.php | 13 +++++++---- src/Symfony/Component/Console/CHANGELOG.md | 5 ++++ .../Component/Console/Command/Command.php | 4 ++++ .../Console/Tests/Command/CommandTest.php | 23 +++++++++++++++++++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Attribute/AsCommand.php b/src/Symfony/Component/Console/Attribute/AsCommand.php index 6066d7c533d54..29e9b884bef06 100644 --- a/src/Symfony/Component/Console/Attribute/AsCommand.php +++ b/src/Symfony/Component/Console/Attribute/AsCommand.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Console\Attribute; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; + /** * Service tag to autoconfigure commands. */ @@ -18,16 +21,18 @@ class AsCommand { /** - * @param string $name The name of the command, used when calling it (i.e. "cache:clear") - * @param string|null $description The description of the command, displayed with the help page - * @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 $name The name of the command, used when calling it (i.e. "cache:clear") + * @param string|null $description The description of the command, displayed with the help page + * @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 array|InputDefinition $definition The list of argument and option instances */ public function __construct( public string $name, public ?string $description = null, array $aliases = [], bool $hidden = false, + public array|InputDefinition $definition = [], ) { if (!$hidden && !$aliases) { return; diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 25d7f7179723c..696b5c34c0cfe 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Add the `definition` option to configure arguments and options in the `AsCommand` attribute + 7.1 --- diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 03da6db43f335..be44cfa162ffe 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -100,6 +100,10 @@ public function __construct(?string $name = null) $this->setDescription(static::getDefaultDescription() ?? ''); } + if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class)) { + $this->setDefinition($attribute[0]->newInstance()->definition); + } + $this->configure(); } diff --git a/src/Symfony/Component/Console/Tests/Command/CommandTest.php b/src/Symfony/Component/Console/Tests/Command/CommandTest.php index f3e4b51d16991..14d42f991e2ef 100644 --- a/src/Symfony/Component/Console/Tests/Command/CommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -462,6 +462,18 @@ public function testDefaultCommand() $this->assertEquals('foo2', $property->getValue($apl)); } + + public function testCommandWithDefinitionAttribute() + { + $this->assertSame('my:command:with-definition', CommandWithDefinition::getDefaultName()); + + $command = new CommandWithDefinition(); + + $this->assertSame('my:command:with-definition', $command->getName()); + + $this->assertTrue($command->getDefinition()->hasArgument('target')); + $this->assertTrue($command->getDefinition()->hasOption('symlink')); + } } // In order to get an unbound closure, we should create it outside a class @@ -490,3 +502,14 @@ class MyAnnotatedCommand extends Command protected static $defaultDescription = 'This description should be ignored.'; } + +#[AsCommand( + name: 'my:command:with-definition', + definition: [ + new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null), + new InputOption('symlink', null, InputOption::VALUE_NONE), + ] +)] +class CommandWithDefinition extends Command +{ +} From c8c35de65ce302080fe29b60ccac2830c8cd301e Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 30 May 2024 11:51:42 +0200 Subject: [PATCH 2/2] Fix CR issues --- .../Component/Console/Attribute/AsCommand.php | 13 +++++----- src/Symfony/Component/Console/CHANGELOG.md | 2 +- .../Component/Console/Command/Command.php | 2 +- .../Console/Tests/Command/CommandTest.php | 24 ++++++++++++++++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Console/Attribute/AsCommand.php b/src/Symfony/Component/Console/Attribute/AsCommand.php index 29e9b884bef06..4f98a712212f2 100644 --- a/src/Symfony/Component/Console/Attribute/AsCommand.php +++ b/src/Symfony/Component/Console/Attribute/AsCommand.php @@ -13,6 +13,7 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputOption; /** * Service tag to autoconfigure commands. @@ -21,18 +22,18 @@ class AsCommand { /** - * @param string $name The name of the command, used when calling it (i.e. "cache:clear") - * @param string|null $description The description of the command, displayed with the help page - * @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 array|InputDefinition $definition The list of argument and option instances + * @param string $name The name of the command, used when calling it (i.e. "cache:clear") + * @param string|null $description The description of the command, displayed with the help page + * @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 array|InputDefinition $inputDefinition The list of argument and option instances */ public function __construct( public string $name, public ?string $description = null, array $aliases = [], bool $hidden = false, - public array|InputDefinition $definition = [], + public array|InputDefinition $inputDefinition = [], ) { if (!$hidden && !$aliases) { return; diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 696b5c34c0cfe..877ebbb2d176d 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 7.2 --- - * Add the `definition` option to configure arguments and options in the `AsCommand` attribute + * Add the `inputDefinition` option to configure arguments and options in the `AsCommand` attribute 7.1 --- diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index be44cfa162ffe..376cf641b67c4 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -101,7 +101,7 @@ public function __construct(?string $name = null) } if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class)) { - $this->setDefinition($attribute[0]->newInstance()->definition); + $this->setDefinition($attribute[0]->newInstance()->inputDefinition); } $this->configure(); diff --git a/src/Symfony/Component/Console/Tests/Command/CommandTest.php b/src/Symfony/Component/Console/Tests/Command/CommandTest.php index 14d42f991e2ef..8e51e0fb6330d 100644 --- a/src/Symfony/Component/Console/Tests/Command/CommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -474,6 +474,18 @@ public function testCommandWithDefinitionAttribute() $this->assertTrue($command->getDefinition()->hasArgument('target')); $this->assertTrue($command->getDefinition()->hasOption('symlink')); } + + public function testCommandWithDefinitionObjectAttribute() + { + $this->assertSame('my:command:with-definition-object', CommandWithDefinitionObject::getDefaultName()); + + $command = new CommandWithDefinitionObject(); + + $this->assertSame('my:command:with-definition-object', $command->getName()); + + $this->assertTrue($command->getDefinition()->hasArgument('target')); + $this->assertTrue($command->getDefinition()->hasOption('symlink')); + } } // In order to get an unbound closure, we should create it outside a class @@ -505,7 +517,7 @@ class MyAnnotatedCommand extends Command #[AsCommand( name: 'my:command:with-definition', - definition: [ + inputDefinition: [ new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null), new InputOption('symlink', null, InputOption::VALUE_NONE), ] @@ -513,3 +525,13 @@ class MyAnnotatedCommand extends Command class CommandWithDefinition extends Command { } +#[AsCommand( + name: 'my:command:with-definition-object', + inputDefinition: new InputDefinition([ + new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null), + new InputOption('symlink', null, InputOption::VALUE_NONE), + ]) +)] +class CommandWithDefinitionObject extends Command +{ +}