From 774d63b849572330e96bb3ed0ad6c0274e44355c Mon Sep 17 00:00:00 2001 From: c33s Date: Fri, 18 Nov 2022 23:38:34 +0100 Subject: [PATCH 1/3] added required options handling aka named parameters --- src/Symfony/Component/Console/Input/Input.php | 9 +++++++++ .../Component/Console/Input/InputOption.php | 18 +++++++++++++++++- .../Console/Tests/Input/InputOptionTest.php | 14 ++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php index 7b90713c865f..4dab6169d912 100644 --- a/src/Symfony/Component/Console/Input/Input.php +++ b/src/Symfony/Component/Console/Input/Input.php @@ -61,6 +61,7 @@ public function validate() { $definition = $this->definition; $givenArguments = $this->arguments; + $givenOptions = $this->options; $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) { return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); @@ -69,6 +70,14 @@ public function validate() if (\count($missingArguments) > 0) { throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } + + $missingOptions = array_filter(array_keys($definition->getOptions()), function ($option) use ($definition, $givenOptions) { + return !\array_key_exists($option, $givenOptions) && $definition->getOption($option)->isRequired(); + }); + + if (\count($missingOptions) > 0) { + throw new RuntimeException(sprintf('Missing options (missing: "%s").', implode(', ', $missingOptions))); + } } public function isInteractive(): bool diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 452c9f7fdec3..cdf5b95d9b5e 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -50,6 +50,11 @@ class InputOption */ public const VALUE_NEGATABLE = 16; + /** + * The option aka "named parameter" must be passed. + */ + public const REQUIRED = 32; + private string $name; private string|array|null $shortcut; private int $mode; @@ -94,7 +99,7 @@ public function __construct(string $name, string|array $shortcut = null, int $mo if (null === $mode) { $mode = self::VALUE_NONE; - } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { + } elseif ($mode >= (self::REQUIRED << 1) || $mode < 1) { throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); } @@ -133,6 +138,16 @@ public function getName(): string return $this->name; } + /** + * Returns true if the argument is required. + * + * @return bool true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired(): bool + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + /** * Returns true if the option accepts a value. * @@ -247,6 +262,7 @@ public function equals(self $option): bool && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() && $option->isValueOptional() === $this->isValueOptional() + && $option->isRequired() === $this->isRequired() ; } } diff --git a/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php b/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php index 0b5271b324ae..561b67e4e979 100644 --- a/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php +++ b/src/Symfony/Component/Console/Tests/Input/InputOptionTest.php @@ -67,26 +67,37 @@ public function testModes() $this->assertFalse($option->acceptValue(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); $this->assertFalse($option->isValueRequired(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); $this->assertFalse($option->isValueOptional(), '__construct() gives a "InputOption::VALUE_NONE" mode by default'); + $this->assertFalse($option->isRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $option = new InputOption('foo', 'f', null); $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $option = new InputOption('foo', 'f', InputOption::VALUE_NONE); $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); + $this->assertFalse($option->isRequired(), '__construct() can take "InputOption::VALUE_NONE" as its mode'); $option = new InputOption('foo', 'f', InputOption::VALUE_REQUIRED); $this->assertTrue($option->acceptValue(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); $this->assertTrue($option->isValueRequired(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); $this->assertFalse($option->isValueOptional(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); + $this->assertFalse($option->isRequired(), '__construct() can take "InputOption::VALUE_REQUIRED" as its mode'); $option = new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL); $this->assertTrue($option->acceptValue(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); $this->assertTrue($option->isValueOptional(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + $this->assertFalse($option->isRequired(), '__construct() can take "InputOption::VALUE_OPTIONAL" as its mode'); + + $option = new InputOption('foo', 'f', InputOption::REQUIRED); + $this->assertFalse($option->acceptValue(), '__construct() can take "InputOption::REQUIRED" as its mode'); + $this->assertFalse($option->isValueRequired(), '__construct() can take "InputOption::REQUIRED" as its mode'); + $this->assertTrue($option->isValueOptional(), '__construct() can take "InputOption::REQUIRED" as its mode'); + $this->assertTrue($option->isRequired(), '__construct() can take "InputOption::REQUIRED" as its mode'); } public function testInvalidModes() @@ -145,6 +156,9 @@ public function testGetDefault() $option = new InputOption('foo', null, InputOption::VALUE_NONE); $this->assertFalse($option->getDefault(), '->getDefault() returns false if the option does not take a value'); + + $option = new InputOption('foo', null, InputOption::REQUIRED); + $this->assertFalse($option->getDefault(), '->getDefault() returns false if the option is required'); } public function testSetDefault() From 6e4d9aeb4fad029d97be2dbb635d8f82eab53c26 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 19 Nov 2022 01:16:06 +0100 Subject: [PATCH 2/3] fixed copy/paste error Co-authored-by: Oskar Stark --- src/Symfony/Component/Console/Input/InputOption.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index cdf5b95d9b5e..031ad17a851c 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -139,7 +139,7 @@ public function getName(): string } /** - * Returns true if the argument is required. + * Returns true if the option is required. * * @return bool true if parameter mode is self::REQUIRED, false otherwise */ From cb2b9d2976feeb673795d8d54b1c700ebc10ca26 Mon Sep 17 00:00:00 2001 From: c33s Date: Sat, 19 Nov 2022 01:19:24 +0100 Subject: [PATCH 3/3] renamed named parameter to named argument --- src/Symfony/Component/Console/Input/InputOption.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 031ad17a851c..c3002afdc533 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -51,7 +51,7 @@ class InputOption public const VALUE_NEGATABLE = 16; /** - * The option aka "named parameter" must be passed. + * The option aka "named argument" must be passed. */ public const REQUIRED = 32;