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');