diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 9c301471c6581..15c088a48f1ef 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -72,6 +72,10 @@ */ class Application implements ResetInterface { + /** + * Description of the command to be executed. + */ + public const COMMAND_ARGUMENT_DESCRIPTION = 'The command to execute'; private array $commands = []; private bool $wantHelps = false; private ?Command $runningCommand = null; @@ -1082,7 +1086,7 @@ protected function getCommandName(InputInterface $input): ?string protected function getDefaultInputDefinition(): InputDefinition { return new InputDefinition([ - new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), + new InputArgument('command', InputArgument::REQUIRED, self::COMMAND_ARGUMENT_DESCRIPTION), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the '.$this->defaultCommand.' command'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 25d7f7179723c..19fc62382359c 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add `ArgvInput::getRawTokens()` + * Throws `InvalidArgumentException` if an argument was created with the reserved keyword `command` as name and is not the `command name` argument. 7.0 --- diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 03da6db43f335..ca64f3031cbf0 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -407,7 +407,7 @@ public function getNativeDefinition(): InputDefinition * * @return $this * - * @throws InvalidArgumentException When argument mode is not valid + * @throws InvalidArgumentException When argument name is "command" or mode is not valid */ public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static { diff --git a/src/Symfony/Component/Console/Input/InputArgument.php b/src/Symfony/Component/Console/Input/InputArgument.php index a5d949277748e..89366d60b1574 100644 --- a/src/Symfony/Component/Console/Input/InputArgument.php +++ b/src/Symfony/Component/Console/Input/InputArgument.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Input; +use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; @@ -50,7 +51,7 @@ class InputArgument * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * - * @throws InvalidArgumentException When argument mode is not valid + * @throws InvalidArgumentException When argument name is "command" or mode is not valid */ public function __construct( private string $name, @@ -59,6 +60,9 @@ public function __construct( string|bool|int|float|array|null $default = null, private \Closure|array $suggestedValues = [], ) { + if ('command' === $name && Application::COMMAND_ARGUMENT_DESCRIPTION !== $description) { + throw new InvalidArgumentException('The "command" keyword cannot be used as the argument name of a command.'); + } if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode >= (self::IS_ARRAY << 1) || $mode < 1) { diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index ca85c24b1f754..a4955710019ee 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -1303,7 +1303,7 @@ public function testAddingAlreadySetDefinitionElementData($def) public static function getAddingAlreadySetDefinitionElementData(): array { return [ - [new InputArgument('command', InputArgument::REQUIRED)], + [new InputArgument('command', InputArgument::REQUIRED, Application::COMMAND_ARGUMENT_DESCRIPTION)], [new InputOption('quiet', '', InputOption::VALUE_NONE)], [new InputOption('query', 'q', InputOption::VALUE_NONE)], ]; diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index 80ea06d67fdac..28a57965cf567 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Tests\Input; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; @@ -316,7 +317,7 @@ public static function provideInvalidInput(): array ], [ ['cli.php', 'acme:foo', 'bar'], - new InputDefinition([new InputArgument('command', InputArgument::REQUIRED)]), + new InputDefinition([new InputArgument('command', InputArgument::REQUIRED, Application::COMMAND_ARGUMENT_DESCRIPTION)]), 'No arguments expected for "acme:foo" command, got "bar"', ], [ diff --git a/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php b/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php index 05447426cc468..9acfab6b4ac7a 100644 --- a/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php +++ b/src/Symfony/Component/Console/Tests/Input/InputArgumentTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Input\InputArgument; @@ -26,6 +27,13 @@ public function testConstructor() $this->assertEquals('foo', $argument->getName(), '__construct() takes a name as its first argument'); } + public function testCommandAsArgumentName() + { + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage('The "command" keyword cannot be used as the argument name of a command.'); + new InputArgument('command'); + } + public function testModes() { $argument = new InputArgument('foo'); diff --git a/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php b/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php index ce0a24b99fda3..d5d9fbf34de60 100644 --- a/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php +++ b/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\Output; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\Question; @@ -30,7 +31,7 @@ class CommandTesterTest extends TestCase protected function setUp(): void { $this->command = new Command('foo'); - $this->command->addArgument('command'); + $this->command->addArgument('command', InputArgument::REQUIRED, Application::COMMAND_ARGUMENT_DESCRIPTION); $this->command->addArgument('foo'); $this->command->setCode(function ($input, $output) { $output->writeln('foo'); }); @@ -231,7 +232,7 @@ public function testSymfonyStyleCommandWithInputs() public function testErrorOutput() { $command = new Command('foo'); - $command->addArgument('command'); + $command->addArgument('command', InputArgument::REQUIRED, Application::COMMAND_ARGUMENT_DESCRIPTION); $command->addArgument('foo'); $command->setCode(function ($input, $output) { $output->getErrorOutput()->write('foo');