diff --git a/UPGRADE-6.1.md b/UPGRADE-6.1.md index 7c1c91fd4e62e..4800052c26206 100644 --- a/UPGRADE-6.1.md +++ b/UPGRADE-6.1.md @@ -1,6 +1,11 @@ UPGRADE FROM 6.0 to 6.1 ======================= +Console +------- + + * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead. + Serializer ---------- diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index e7f9325125c25..8a34f80b0b6af 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add method `__toString()` to `InputInterface` + * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead. 6.0 --- diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 0bd3426c07eb3..e84307207a92f 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -39,11 +39,15 @@ class Command /** * @var string|null The default command name + * + * @deprecated since Symfony 6.1, use the AsCommand attribute instead */ protected static $defaultName; /** * @var string|null The default command description + * + * @deprecated since Symfony 6.1, use the AsCommand attribute instead */ protected static $defaultDescription; @@ -72,7 +76,13 @@ public static function getDefaultName(): ?string $r = new \ReflectionProperty($class, 'defaultName'); - return $class === $r->class ? static::$defaultName : null; + if ($class !== $r->class || null === static::$defaultName) { + return null; + } + + trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); + + return static::$defaultName; } public static function getDefaultDescription(): ?string @@ -85,7 +95,13 @@ public static function getDefaultDescription(): ?string $r = new \ReflectionProperty($class, 'defaultDescription'); - return $class === $r->class ? static::$defaultDescription : null; + if ($class !== $r->class || null === static::$defaultDescription) { + return null; + } + + trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); + + return static::$defaultDescription; } /** diff --git a/src/Symfony/Component/Console/Command/CompleteCommand.php b/src/Symfony/Component/Console/Command/CompleteCommand.php index 4fb3398eb9586..882f5b72f58e5 100644 --- a/src/Symfony/Component/Console/Command/CompleteCommand.php +++ b/src/Symfony/Component/Console/Command/CompleteCommand.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Command; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Output\BashCompletionOutput; @@ -27,9 +28,17 @@ * * @author Wouter de Jong */ +#[AsCommand(name: '|_complete', description: 'Internal command to provide shell completion suggestions')] final class CompleteCommand extends Command { + /** + * @deprecated since Symfony 6.1 + */ protected static $defaultName = '|_complete'; + + /** + * @deprecated since Symfony 6.1 + */ protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; private $completionOutputs; diff --git a/src/Symfony/Component/Console/Command/DumpCompletionCommand.php b/src/Symfony/Component/Console/Command/DumpCompletionCommand.php index 697ade52741af..6b9364ada48a8 100644 --- a/src/Symfony/Component/Console/Command/DumpCompletionCommand.php +++ b/src/Symfony/Component/Console/Command/DumpCompletionCommand.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Command; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\InputArgument; @@ -25,9 +26,17 @@ * * @author Wouter de Jong */ +#[AsCommand(name: 'completion', description: 'Dump the shell completion script')] final class DumpCompletionCommand extends Command { + /** + * @deprecated since Symfony 6.1 + */ protected static $defaultName = 'completion'; + + /** + * @deprecated since Symfony 6.1 + */ protected static $defaultDescription = 'Dump the shell completion script'; public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index c5acd5c8666fe..77764de3cdbc1 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\HelpCommand; use Symfony\Component\Console\Command\LazyCommand; @@ -1968,13 +1969,12 @@ public function isEnabled(): bool } } +#[AsCommand(name: 'signal')] class SignableCommand extends Command implements SignalableCommandInterface { public $signaled = false; public $loop = 100; - protected static $defaultName = 'signal'; - public function getSubscribedSignals(): array { return SignalRegistry::isSupported() ? [\SIGALRM] : []; diff --git a/src/Symfony/Component/Console/Tests/Command/CommandTest.php b/src/Symfony/Component/Console/Tests/Command/CommandTest.php index 1ce203860d8c4..d14c55df26628 100644 --- a/src/Symfony/Component/Console/Tests/Command/CommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Tests\Command; use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Console\Application; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -28,6 +29,8 @@ class CommandTest extends TestCase { + use ExpectDeprecationTrait; + protected static $fixturesPath; public static function setUpBeforeClass(): void @@ -420,6 +423,48 @@ public function testCommandAttribute() $this->assertSame(['f'], $command->getAliases()); } + /** + * @group legacy + */ + public function testDefaultNameProperty() + { + $this->expectDeprecation('Since symfony/console 6.1: Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "Symfony\Component\Console\Attribute\AsCommand" attribute to the "Symfony\Component\Console\Tests\Command\MyCommand" class instead.'); + + $this->assertSame('my:command', MyCommand::getDefaultName()); + } + + /** + * @group legacy + */ + public function testDefaultDescriptionProperty() + { + $this->expectDeprecation('Since symfony/console 6.1: Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "Symfony\Component\Console\Attribute\AsCommand" attribute to the "Symfony\Component\Console\Tests\Command\MyCommand" class instead.'); + + $this->assertSame('This is a command I wrote all by myself', MyCommand::getDefaultDescription()); + } + + /** + * @group legacy + */ + public function testStaticDefaultProperties() + { + $command = new MyCommand(); + + $this->assertSame('my:command', $command->getName()); + $this->assertSame('This is a command I wrote all by myself', $command->getDescription()); + } + + public function testAttributeOverridesProperty() + { + $this->assertSame('my:command', MyAnnotatedCommand::getDefaultName()); + $this->assertSame('This is a command I wrote all by myself', MyAnnotatedCommand::getDefaultDescription()); + + $command = new MyAnnotatedCommand(); + + $this->assertSame('my:command', $command->getName()); + $this->assertSame('This is a command I wrote all by myself', $command->getDescription()); + } + public function testDefaultCommand() { $apl = new Application(); @@ -455,3 +500,16 @@ class Php8Command extends Command class Php8Command2 extends Command { } + +class MyCommand extends Command +{ + protected static $defaultName = 'my:command'; + protected static $defaultDescription = 'This is a command I wrote all by myself'; +} + +#[AsCommand(name: 'my:command', description: 'This is a command I wrote all by myself')] +class MyAnnotatedCommand extends Command +{ + protected static $defaultName = 'i-shall-be-ignored'; + protected static $defaultDescription = 'This description should be ignored.'; +} diff --git a/src/Symfony/Component/Console/Tests/ConsoleEventsTest.php b/src/Symfony/Component/Console/Tests/ConsoleEventsTest.php index 45eb2220d1743..6f50e7401732a 100644 --- a/src/Symfony/Component/Console/Tests/ConsoleEventsTest.php +++ b/src/Symfony/Component/Console/Tests/ConsoleEventsTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleCommandEvent; @@ -75,10 +76,9 @@ public function observe(object $event): void } } +#[AsCommand(name: 'fail')] class FailingCommand extends Command { - protected static $defaultName = 'fail'; - protected function execute(InputInterface $input, OutputInterface $output): int { throw new \RuntimeException('I failed. Sorry.'); diff --git a/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php b/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php index aa92c76f159c3..adbc61e85d1bb 100644 --- a/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php +++ b/src/Symfony/Component/Console/Tests/DependencyInjection/AddConsoleCommandPassTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\LazyCommand; use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; @@ -281,18 +282,16 @@ class MyCommand extends Command { } +#[AsCommand(name: 'default')] class NamedCommand extends Command { - protected static $defaultName = 'default'; } +#[AsCommand(name: '|cmdname|cmdalias', description: 'Just testing')] class DescribedCommand extends Command { public static $initCounter = 0; - protected static $defaultName = '|cmdname|cmdalias'; - protected static $defaultDescription = 'Just testing'; - public function __construct() { ++self::$initCounter; diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index 7d3947fcc7ec1..4045b7f2154c2 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": ">=8.0.2", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^1.1|^2|^3", "symfony/string": "^5.4|^6.0" diff --git a/src/Symfony/Component/Dotenv/Command/DebugCommand.php b/src/Symfony/Component/Dotenv/Command/DebugCommand.php index 925d99328eeb9..8827460caf432 100644 --- a/src/Symfony/Component/Dotenv/Command/DebugCommand.php +++ b/src/Symfony/Component/Dotenv/Command/DebugCommand.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Dotenv\Command; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -22,9 +23,17 @@ * * @author Christopher Hertel */ +#[AsCommand(name: 'debug:dotenv', description: 'Lists all dotenv files with variables and values')] final class DebugCommand extends Command { + /** + * @deprecated since Symfony 6.1 + */ protected static $defaultName = 'debug:dotenv'; + + /** + * @deprecated since Symfony 6.1 + */ protected static $defaultDescription = 'Lists all dotenv files with variables and values'; private $kernelEnvironment; diff --git a/src/Symfony/Component/Dotenv/composer.json b/src/Symfony/Component/Dotenv/composer.json index 2bea7d4842100..d5e7aed8dd499 100644 --- a/src/Symfony/Component/Dotenv/composer.json +++ b/src/Symfony/Component/Dotenv/composer.json @@ -22,6 +22,9 @@ "symfony/console": "^5.4|^6.0", "symfony/process": "^5.4|^6.0" }, + "conflict": { + "symfony/console": "<5.4" + }, "autoload": { "psr-4": { "Symfony\\Component\\Dotenv\\": "" }, "exclude-from-classmap": [