Skip to content

Commit 84b2f70

Browse files
committed
[Console] Add support for extension of AsCommand attribute
1 parent f1e169e commit 84b2f70

File tree

7 files changed

+47
-6
lines changed

7 files changed

+47
-6
lines changed

src/Symfony/Component/Console/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ CHANGELOG
1212
* Deprecate methods `Command::getDefaultName()` and `Command::getDefaultDescription()` in favor of the `#[AsCommand]` attribute
1313
* Add support for Markdown format in `Table`
1414
* Add support for `LockableTrait` in invokable commands
15+
* Add support for extension of `AsCommand` attribute
1516

1617
7.2
1718
---

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static function getDefaultName(): ?string
6161
{
6262
trigger_deprecation('symfony/console', '7.3', 'Method "%s()" is deprecated and will be removed in Symfony 8.0, use the #[AsCommand] attribute instead.', __METHOD__);
6363

64-
if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class)) {
64+
if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class, \ReflectionAttribute::IS_INSTANCEOF)) {
6565
return $attribute[0]->newInstance()->name;
6666
}
6767

@@ -75,7 +75,7 @@ public static function getDefaultDescription(): ?string
7575
{
7676
trigger_deprecation('symfony/console', '7.3', 'Method "%s()" is deprecated and will be removed in Symfony 8.0, use the #[AsCommand] attribute instead.', __METHOD__);
7777

78-
if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class)) {
78+
if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class, \ReflectionAttribute::IS_INSTANCEOF)) {
7979
return $attribute[0]->newInstance()->description;
8080
}
8181

@@ -91,7 +91,7 @@ public function __construct(?string $name = null)
9191
{
9292
$this->definition = new InputDefinition();
9393

94-
$attribute = ((new \ReflectionClass(static::class))->getAttributes(AsCommand::class)[0] ?? null)?->newInstance();
94+
$attribute = ((new \ReflectionClass(static::class))->getAttributes(AsCommand::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null)?->newInstance();
9595

9696
if (null === $name) {
9797
if (self::class !== (new \ReflectionMethod($this, 'getDefaultName'))->class) {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ private function lock(?string $name = null, bool $blocking = false): bool
5555
if (!$name) {
5656
if ($this instanceof Command) {
5757
$name = $this->getName();
58-
} elseif ($attribute = (new \ReflectionClass($this::class))->getAttributes(AsCommand::class)) {
58+
} elseif ($attribute = (new \ReflectionClass($this::class))->getAttributes(AsCommand::class, \ReflectionAttribute::IS_INSTANCEOF)) {
5959
$name = $attribute[0]->newInstance()->name;
6060
} else {
6161
throw new LogicException(\sprintf('Lock name missing: provide it via "%s()", #[AsCommand] attribute, or by extending Command class.', __METHOD__));

src/Symfony/Component/Console/DependencyInjection/AddConsoleCommandPass.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function process(ContainerBuilder $container): void
6060
$definition->addTag('container.no_preload');
6161

6262
/** @var AsCommand|null $attribute */
63-
$attribute = ($r->getAttributes(AsCommand::class)[0] ?? null)?->newInstance();
63+
$attribute = ($r->getAttributes(AsCommand::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null)?->newInstance();
6464

6565
if (Command::class !== (new \ReflectionMethod($class, 'getDefaultName'))->class) {
6666
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.', $class);

src/Symfony/Component/Console/Tests/ApplicationTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
use Symfony\Component\Console\SignalRegistry\SignalRegistry;
4646
use Symfony\Component\Console\Terminal;
4747
use Symfony\Component\Console\Tester\ApplicationTester;
48+
use Symfony\Component\Console\Tests\Fixtures\AsCommandExtended;
4849
use Symfony\Component\Console\Tests\Fixtures\MockableAppliationWithTerminalWidth;
4950
use Symfony\Component\DependencyInjection\ContainerBuilder;
5051
use Symfony\Component\EventDispatcher\EventDispatcher;
@@ -559,6 +560,16 @@ public function testDontRunAlternativeCommandName()
559560
$this->assertStringContainsString('Do you want to run "foo" instead? (yes/no) [no]:', $display);
560561
}
561562

563+
public function testExtendedAsCommandAtribute()
564+
{
565+
$application = new Application();
566+
$application->add(new WithExtendedAttributeCommand());
567+
$application->setAutoExit(false);
568+
$tester = new ApplicationTester($application);
569+
$exitCode = $tester->run(['command' => 'withExtendedAttribute']);
570+
$this->assertSame(Command::FAILURE, $exitCode);
571+
}
572+
562573
public static function provideInvalidCommandNamesSingle()
563574
{
564575
return [
@@ -2642,3 +2653,11 @@ public static function getSubscribedEvents(): array
26422653
return [ConsoleAlarmEvent::class => 'onAlarm'];
26432654
}
26442655
}
2656+
2657+
#[AsCommandExtended(name: 'withExtendedAttribute', addedParam: 'addedParam')]
2658+
class WithExtendedAttributeCommand extends Command {
2659+
protected function execute(InputInterface $input, OutputInterface $output): int
2660+
{
2661+
return Command::FAILURE;
2662+
}
2663+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Symfony\Component\Console\Tests\Fixtures;
5+
6+
use Symfony\Component\Console\Attribute\AsCommand;
7+
8+
#[\Attribute(\Attribute::TARGET_CLASS)]
9+
final class AsCommandExtended extends AsCommand
10+
{
11+
public function __construct(
12+
public string $name,
13+
public ?string $description = null,
14+
array $aliases = [],
15+
bool $hidden = false,
16+
public ?string $help = null,
17+
public ?string $addedParam = null
18+
) {
19+
parent::__construct($this->name, $this->description, $aliases, $hidden, $this->help);
20+
}
21+
}

src/Symfony/Component/Scheduler/DependencyInjection/AddScheduleMessengerPass.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function process(ContainerBuilder $container): void
5757

5858
if ($serviceDefinition->hasTag('console.command')) {
5959
/** @var AsCommand|null $attribute */
60-
$attribute = ($container->getReflectionClass($serviceDefinition->getClass())->getAttributes(AsCommand::class)[0] ?? null)?->newInstance();
60+
$attribute = ($container->getReflectionClass($serviceDefinition->getClass())->getAttributes(AsCommand::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null)?->newInstance();
6161
$message = new Definition(RunCommandMessage::class, [$attribute?->name ?? $serviceDefinition->getClass()::getDefaultName().(empty($tagAttributes['arguments']) ? '' : " {$tagAttributes['arguments']}")]);
6262
} else {
6363
$message = new Definition(ServiceCallMessage::class, [$serviceId, $tagAttributes['method'] ?? '__invoke', (array) ($tagAttributes['arguments'] ?? [])]);

0 commit comments

Comments
 (0)