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

Skip to content

[Console] Improve AsCommand DX for simple arguments and options #57225

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

Closed
Closed
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
14 changes: 10 additions & 4 deletions src/Symfony/Component/Console/Attribute/AsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,29 @@

namespace Symfony\Component\Console\Attribute;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;

/**
* Service tag to autoconfigure commands.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
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<InputArgument|InputOption>|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 $inputDefinition = [],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the $inputDefinition name a bit long but I don't have a better idea at the moment

) {
if (!$hidden && !$aliases) {
return;
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.2
---

* Add the `inputDefinition` option to configure arguments and options in the `AsCommand` attribute

7.1
---

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 @@ -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()->inputDefinition);
}

$this->configure();
}

Expand Down
45 changes: 45 additions & 0 deletions src/Symfony/Component/Console/Tests/Command/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,30 @@ 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'));
}

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
Expand Down Expand Up @@ -490,3 +514,24 @@ class MyAnnotatedCommand extends Command

protected static $defaultDescription = 'This description should be ignored.';
}

#[AsCommand(
name: 'my:command:with-definition',
inputDefinition: [
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null),
new InputOption('symlink', null, InputOption::VALUE_NONE),
]
)]
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
{
}