From 1a9a3c34c9b759b43e264ac74b77b75e942df81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 4 Jan 2021 09:45:40 +0100 Subject: [PATCH] Implement negatable option --- src/Symfony/Component/Console/Application.php | 2 +- src/Symfony/Component/Console/CHANGELOG.md | 1 + .../Console/Descriptor/JsonDescriptor.php | 22 +++- .../Console/Descriptor/MarkdownDescriptor.php | 9 +- .../Console/Descriptor/TextDescriptor.php | 17 +-- .../Console/Descriptor/XmlDescriptor.php | 16 ++- .../Component/Console/Input/ArgvInput.php | 27 ++++- .../Component/Console/Input/ArrayInput.php | 25 +++- src/Symfony/Component/Console/Input/Input.php | 30 ++--- .../Console/Input/InputDefinition.php | 55 ++++++--- .../Component/Console/Input/InputOption.php | 72 ++--------- .../Console/Input/NegatedInputOption.php | 112 ------------------ .../Console/Tests/ApplicationTest.php | 7 +- .../Console/Tests/Command/ListCommandTest.php | 3 +- .../Console/Tests/Fixtures/application_1.json | 8 +- .../Console/Tests/Fixtures/application_1.md | 42 ++++--- .../Console/Tests/Fixtures/application_1.txt | 3 +- .../Console/Tests/Fixtures/application_1.xml | 8 +- .../Console/Tests/Fixtures/application_2.json | 24 ++-- .../Console/Tests/Fixtures/application_2.md | 100 +++++++--------- .../Console/Tests/Fixtures/application_2.txt | 3 +- .../Console/Tests/Fixtures/application_2.xml | 24 ++-- .../application_filtered_namespace.txt | 3 +- .../Tests/Fixtures/application_mbstring.md | 62 +++++----- .../Tests/Fixtures/application_mbstring.txt | 3 +- .../Tests/Fixtures/application_run1.txt | 3 +- .../Tests/Fixtures/application_run2.txt | 3 +- .../Tests/Fixtures/application_run3.txt | 3 +- .../Tests/Fixtures/application_run5.txt | 3 +- .../Console/Tests/Fixtures/command_2.md | 1 + .../Tests/Fixtures/command_mbstring.md | 1 + .../Tests/Fixtures/input_definition_3.md | 1 + .../Tests/Fixtures/input_definition_4.md | 1 + .../Console/Tests/Fixtures/input_option_1.md | 1 + .../Console/Tests/Fixtures/input_option_2.md | 1 + .../Console/Tests/Fixtures/input_option_3.md | 1 + .../Console/Tests/Fixtures/input_option_4.md | 1 + .../Console/Tests/Fixtures/input_option_5.md | 1 + .../Console/Tests/Fixtures/input_option_6.md | 1 + .../input_option_with_default_inf_value.md | 1 + .../Tests/Fixtures/input_option_with_style.md | 1 + .../Fixtures/input_option_with_style_array.md | 1 + .../Console/Tests/Input/ArgvInputTest.php | 78 ++++++++++++ .../Console/Tests/Input/InputOptionTest.php | 22 ++++ .../Console/Tests/Input/InputTest.php | 1 + .../phpt/single_application/help_name.phpt | 3 +- 46 files changed, 399 insertions(+), 408 deletions(-) delete mode 100644 src/Symfony/Component/Console/Input/NegatedInputOption.php diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 3dc15b3c6b..57c073e72e 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -1033,7 +1033,7 @@ class Application implements ResetInterface 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'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), - new InputOption('--ansi', '', InputOption::VALUE_BINARY, 'Force ANSI output', null), + new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), ]); } diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index bea122185e..ea52eb2c90 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * Added `GithubActionReporter` to render annotations in a Github Action + * Added `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options. 5.2.0 ----- diff --git a/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php index 8b9c966b30..f70fc38f6b 100644 --- a/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php @@ -40,6 +40,9 @@ class JsonDescriptor extends Descriptor protected function describeInputOption(InputOption $option, array $options = []) { $this->writeData($this->getInputOptionData($option), $options); + if ($option->isNegatable()) { + $this->writeData($this->getInputOptionData($option, true), $options); + } } /** @@ -111,15 +114,22 @@ class JsonDescriptor extends Descriptor ]; } - private function getInputOptionData(InputOption $option): array + private function getInputOptionData(InputOption $option, bool $negated = false): array { - return [ + return $negated ? [ + 'name' => '--no-'.$option->getName(), + 'shortcut' => '', + 'accept_value' => false, + 'is_value_required' => false, + 'is_multiple' => false, + 'description' => 'Negate the "--'.$option->getName().'" option', + 'default' => false, + ] : [ 'name' => '--'.$option->getName(), 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), - 'is_negatable' => $option->isNegatable(), 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(), ]; @@ -134,10 +144,10 @@ class JsonDescriptor extends Descriptor $inputOptions = []; foreach ($definition->getOptions() as $name => $option) { - if ($option->isHidden()) { - continue; - } $inputOptions[$name] = $this->getInputOptionData($option); + if ($option->isNegatable()) { + $inputOptions['no-'.$name] = $this->getInputOptionData($option, true); + } } return ['arguments' => $inputArguments, 'options' => $inputOptions]; diff --git a/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php index 42043ac1d8..dddba12f88 100644 --- a/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php @@ -68,8 +68,10 @@ class MarkdownDescriptor extends Descriptor */ protected function describeInputOption(InputOption $option, array $options = []) { - $negatable = $option->isNegatable() ? '[no-]' : ''; - $name = '--'.$negatable.$option->getName(); + $name = '--'.$option->getName(); + if ($option->isNegatable()) { + $name .= '|--no-'.$option->getName(); + } if ($option->getShortcut()) { $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).''; } @@ -107,9 +109,6 @@ class MarkdownDescriptor extends Descriptor $this->write('### Options'); foreach ($definition->getOptions() as $option) { - if ($option->isHidden()) { - continue; - } $this->write("\n\n"); if (null !== $describeInputOption = $this->describeInputOption($option)) { $this->write($describeInputOption); diff --git a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php index 77a9a49e52..8598b41016 100644 --- a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php @@ -56,12 +56,10 @@ class TextDescriptor extends Descriptor */ protected function describeInputOption(InputOption $option, array $options = []) { - $default = ''; if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); - } elseif ($option->isNegatable() && (null !== $option->getDefault())) { - $negative_default = $option->getDefault() ? '' : 'no-'; - $default = sprintf(' [default: --%s%s]', $negative_default, $option->getName()); + } else { + $default = ''; } $value = ''; @@ -74,10 +72,9 @@ class TextDescriptor extends Descriptor } $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions([$option]); - $negatable = $option->isNegatable() ? '[no-]' : ''; $synopsis = sprintf('%s%s', $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', - sprintf('--%s%s%s', $negatable, $option->getName(), $value) + sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) ); $spacingWidth = $totalWidth - Helper::strlen($synopsis); @@ -120,9 +117,6 @@ class TextDescriptor extends Descriptor $this->writeText('Options:', $options); foreach ($definition->getOptions() as $option) { - if ($option->isHidden()) { - continue; - } if (\strlen($option->getShortcut()) > 1) { $laterOptions[] = $option; continue; @@ -331,8 +325,9 @@ class TextDescriptor extends Descriptor foreach ($options as $option) { // "-" + shortcut + ", --" + name $nameLength = 1 + max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName()); - - if ($option->acceptValue()) { + if ($option->isNegatable()) { + $nameLength += 6 + Helper::strlen($option->getName()); // |--no- + name + } elseif ($option->acceptValue()) { $valueLength = 1 + Helper::strlen($option->getName()); // = + value $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ] diff --git a/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php index 0ed8b24e65..d9db0b8938 100644 --- a/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php @@ -38,9 +38,7 @@ class XmlDescriptor extends Descriptor $definitionXML->appendChild($optionsXML = $dom->createElement('options')); foreach ($definition->getOptions() as $option) { - if (!$option->isHidden()) { - $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); - } + $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); } return $dom; @@ -212,7 +210,6 @@ class XmlDescriptor extends Descriptor $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); - $objectXML->setAttribute('is_negatable', $option->isNegatable() ? 1 : 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); @@ -228,6 +225,17 @@ class XmlDescriptor extends Descriptor } } + if ($option->isNegatable()) { + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--no-'.$option->getName()); + $objectXML->setAttribute('shortcut', ''); + $objectXML->setAttribute('accept_value', 0); + $objectXML->setAttribute('is_value_required', 0); + $objectXML->setAttribute('is_multiple', 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option')); + } + return $dom; } } diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index 8d8fee820a..9dd4de7803 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -208,7 +208,21 @@ class ArgvInput extends Input */ private function addLongOption(string $name, $value) { - $option = $this->getOptionDefinition($name); + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + } + + $optionName = $this->definition->negationToName($name); + if (null !== $value) { + throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + } + $this->options[$optionName] = false; + + return; + } + + $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); @@ -225,8 +239,15 @@ class ArgvInput extends Input } } - $name = $option->effectiveName(); - $value = $option->checkValue($value); + if (null === $value) { + if ($option->isValueRequired()) { + throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + } + + if (!$option->isArray() && !$option->isValueOptional()) { + $value = true; + } + } if ($option->isArray()) { $this->options[$name][] = $value; diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php index 353f6185ea..2473f806e5 100644 --- a/src/Symfony/Component/Console/Input/ArrayInput.php +++ b/src/Symfony/Component/Console/Input/ArrayInput.php @@ -164,7 +164,30 @@ class ArrayInput extends Input */ private function addLongOption(string $name, $value) { - $this->setOption($name, $value); + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name)); + } + + $optionName = $this->definition->negationToName($name); + $this->options[$optionName] = false; + + return; + } + + $option = $this->definition->getOption($name); + + if (null === $value) { + if ($option->isValueRequired()) { + throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); + } + + if (!$option->isValueOptional()) { + $value = true; + } + } + + $this->options[$name] = $value; } /** diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php index d57a0f7d4e..ff5d3170f4 100644 --- a/src/Symfony/Component/Console/Input/Input.php +++ b/src/Symfony/Component/Console/Input/Input.php @@ -146,8 +146,11 @@ abstract class Input implements InputInterface, StreamableInputInterface */ public function getOption(string $name) { - $option = $this->getOptionDefinition($name); - return \array_key_exists($name, $this->options) ? $this->options[$name] : $option->getDefault(); + if (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } /** @@ -155,8 +158,11 @@ abstract class Input implements InputInterface, StreamableInputInterface */ public function setOption(string $name, $value) { - $option = $this->getOptionDefinition($name); - $this->options[$option->effectiveName()] = $option->checkValue($value); + if (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + } + + $this->options[$name] = $value; } /** @@ -192,20 +198,4 @@ abstract class Input implements InputInterface, StreamableInputInterface { return $this->stream; } - - /** - * Look up the option definition for the given option name. - * - * @param string $name - * - * @return InputOption - */ - protected function getOptionDefinition($name) - { - if (!$this->definition->hasOption($name)) { - throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); - } - - return $this->definition->getOption($name); - } } diff --git a/src/Symfony/Component/Console/Input/InputDefinition.php b/src/Symfony/Component/Console/Input/InputDefinition.php index 0a22f2570d..56ae7185f8 100644 --- a/src/Symfony/Component/Console/Input/InputDefinition.php +++ b/src/Symfony/Component/Console/Input/InputDefinition.php @@ -33,6 +33,7 @@ class InputDefinition private $hasAnArrayArgument = false; private $hasOptional; private $options; + private $negations; private $shortcuts; /** @@ -208,6 +209,7 @@ class InputDefinition { $this->options = []; $this->shortcuts = []; + $this->negations = []; $this->addOptions($options); } @@ -227,19 +229,6 @@ class InputDefinition * @throws LogicException When option given already exist */ public function addOption(InputOption $option) - { - $this->doAddOption($option); - - if ($option->isNegatable()) { - $negatedOption = new NegatedInputOption($option); - $this->doAddOption($negatedOption); - } - } - - /** - * @throws LogicException When option given already exist - */ - private function doAddOption(InputOption $option) { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); @@ -259,6 +248,14 @@ class InputDefinition $this->shortcuts[$shortcut] = $option->getName(); } } + + if ($option->isNegatable()) { + $negatedName = 'no-'.$option->getName(); + if (isset($this->options[$negatedName])) { + throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName)); + } + $this->negations[$negatedName] = $option->getName(); + } } /** @@ -310,6 +307,14 @@ class InputDefinition return isset($this->shortcuts[$name]); } + /** + * Returns true if an InputOption object exists by negated name. + */ + public function hasNegation(string $name): bool + { + return isset($this->negations[$name]); + } + /** * Gets an InputOption by shortcut. * @@ -329,7 +334,7 @@ class InputDefinition { $values = []; foreach ($this->options as $option) { - $values[$option->effectiveName()] = $option->getDefault(); + $values[$option->getName()] = $option->getDefault(); } return $values; @@ -351,6 +356,22 @@ class InputDefinition return $this->shortcuts[$shortcut]; } + /** + * Returns the InputOption name given a negation. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function negationToName(string $negation): string + { + if (!isset($this->negations[$negation])) { + throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation)); + } + + return $this->negations[$negation]; + } + /** * Gets the synopsis. * @@ -364,9 +385,6 @@ class InputDefinition $elements[] = '[options]'; } elseif (!$short) { foreach ($this->getOptions() as $option) { - if ($option->isHidden()) { - continue; - } $value = ''; if ($option->acceptValue()) { $value = sprintf( @@ -378,7 +396,8 @@ class InputDefinition } $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; - $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value); + $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index 941d1f7726..08be6eac94 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Exception\InvalidOptionException; use Symfony\Component\Console\Exception\LogicException; /** @@ -27,8 +26,6 @@ class InputOption public const VALUE_OPTIONAL = 4; public const VALUE_IS_ARRAY = 8; public const VALUE_NEGATABLE = 16; - public const VALUE_HIDDEN = 32; - public const VALUE_BINARY = (self::VALUE_NONE | self::VALUE_NEGATABLE); private $name; private $shortcut; @@ -74,7 +71,7 @@ class InputOption if (null === $mode) { $mode = self::VALUE_NONE; - } elseif ($mode >= (self::VALUE_HIDDEN << 1) || $mode < 1) { + } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); } @@ -86,6 +83,9 @@ class InputOption if ($this->isArray() && !$this->acceptValue()) { throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); } + if ($this->isNegatable() && $this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.'); + } $this->setDefault($default); } @@ -110,11 +110,6 @@ class InputOption return $this->name; } - public function effectiveName() - { - return $this->getName(); - } - /** * Returns true if the option accepts a value. * @@ -155,39 +150,11 @@ class InputOption return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); } - /** - * Returns true if the option is negatable (option --foo can be forced - * to 'false' via the --no-foo option). - * - * @return bool true if mode is self::VALUE_NEGATABLE, false otherwise - */ - public function isNegatable() + public function isNegatable(): bool { return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } - /** - * Returns true if the option should not be shown in help (e.g. a negated - * option). - * - * @return bool true if mode is self::VALUE_HIDDEN, false otherwise - */ - public function isHidden() - { - return self::VALUE_HIDDEN === (self::VALUE_HIDDEN & $this->mode); - } - - /** - * Returns true if the option is binary (can be --foo or --no-foo, and - * nothing else). - * - * @return bool true if negatable and does not have a value. - */ - public function isBinary() - { - return $this->isNegatable() && !$this->acceptValue(); - } - /** * Sets the default value. * @@ -197,9 +164,12 @@ class InputOption */ public function setDefault($default = null) { - if (self::VALUE_NONE === ((self::VALUE_NONE | self::VALUE_NEGATABLE) & $this->mode) && null !== $default) { + if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); } + if (self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode) && null !== $default) { + throw new LogicException('Cannot set a default value when using InputOption::VALUE_NEGATABLE mode.'); + } if ($this->isArray()) { if (null === $default) { @@ -209,7 +179,7 @@ class InputOption } } - $this->default = ($this->acceptValue() || $this->isNegatable()) ? $default : false; + $this->default = $this->acceptValue() ? $default : false; } /** @@ -232,27 +202,6 @@ class InputOption return $this->description; } - /** - * Checks the validity of a value, and alters it as necessary - * - * @param mixed $value - * - * @return @mixed - */ - public function checkValue($value) - { - if (null === $value) { - if ($this->isValueRequired()) { - throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $this->getName())); - } - - if (!$this->isValueOptional()) { - return true; - } - } - return $value; - } - /** * Checks whether the given option equals this one. * @@ -263,7 +212,6 @@ class InputOption return $option->getName() === $this->getName() && $option->getShortcut() === $this->getShortcut() && $option->getDefault() === $this->getDefault() - && $option->isHidden() === $this->isHidden() && $option->isNegatable() === $this->isNegatable() && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() diff --git a/src/Symfony/Component/Console/Input/NegatedInputOption.php b/src/Symfony/Component/Console/Input/NegatedInputOption.php deleted file mode 100644 index 07a4bb6d09..0000000000 --- a/src/Symfony/Component/Console/Input/NegatedInputOption.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Input; - -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Exception\LogicException; - -/** - * Represents a command line option. - * - * @author Fabien Potencier - */ -class NegatedInputOption extends InputOption -{ - private $primaryOption; - - const VALUE_NONE = 1; - const VALUE_REQUIRED = 2; - const VALUE_OPTIONAL = 4; - const VALUE_IS_ARRAY = 8; - const VALUE_NEGATABLE = 16; - const VALUE_HIDDEN = 32; - const VALUE_BINARY = (self::VALUE_NONE | self::VALUE_NEGATABLE); - - private $name; - private $shortcut; - private $mode; - private $default; - private $description; - - /** - * @param string $name The option name - * @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts - * @param int $mode The option mode: One of the VALUE_* constants - * @param string $description A description text - * @param mixed $default The default value (must be null for self::VALUE_NONE) - * - * @throws InvalidArgumentException If option mode is invalid or incompatible - */ - public function __construct(InputOption $primaryOption) - { - $this->primaryOption = $primaryOption; - - /* string $name, $shortcut = null, int $mode = null, string $description = '', $default = null */ - $name = 'no-' . $primaryOption->getName(); - $shortcut = null; - $mode = self::VALUE_HIDDEN; - $description = $primaryOption->getDescription(); - $default = $this->negate($primaryOption->getDefault()); - - parent::__construct($name, $shortcut, $mode, $description, $default); - } - - public function effectiveName() - { - return $this->primaryOption->getName(); - } - - /** - * Sets the default value. - * - * @param mixed $default The default value - * - * @throws LogicException When incorrect default value is given - */ - public function setDefault($default = null) - { - $this->primaryOption->setDefault($this->negate($default)); - } - - /** - * Returns the default value. - * - * @return mixed The default value - */ - public function getDefault() - { - return $this->negate($this->primaryOption->getDefault()); - } - - /** - * @inheritdoc - */ - public function checkValue($value) - { - return false; - } - - /** - * Negate a value if it is provided. - * - * @param mixed $value - * - * @return mixed - */ - private function negate($value) - { - if ($value === null) { - return $value; - } - return !$value; - } -} diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 4141920965..f115f140ec 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -1257,7 +1257,8 @@ class ApplicationTest extends TestCase $this->assertTrue($inputDefinition->hasOption('verbose')); $this->assertTrue($inputDefinition->hasOption('version')); $this->assertTrue($inputDefinition->hasOption('ansi')); - $this->assertTrue($inputDefinition->hasOption('no-ansi')); + $this->assertTrue($inputDefinition->hasNegation('no-ansi')); + $this->assertFalse($inputDefinition->hasOption('no-ansi')); $this->assertTrue($inputDefinition->hasOption('no-interaction')); } @@ -1277,7 +1278,7 @@ class ApplicationTest extends TestCase $this->assertFalse($inputDefinition->hasOption('verbose')); $this->assertFalse($inputDefinition->hasOption('version')); $this->assertFalse($inputDefinition->hasOption('ansi')); - $this->assertFalse($inputDefinition->hasOption('no-ansi')); + $this->assertFalse($inputDefinition->hasNegation('no-ansi')); $this->assertFalse($inputDefinition->hasOption('no-interaction')); $this->assertTrue($inputDefinition->hasOption('custom')); @@ -1301,7 +1302,7 @@ class ApplicationTest extends TestCase $this->assertFalse($inputDefinition->hasOption('verbose')); $this->assertFalse($inputDefinition->hasOption('version')); $this->assertFalse($inputDefinition->hasOption('ansi')); - $this->assertFalse($inputDefinition->hasOption('no-ansi')); + $this->assertFalse($inputDefinition->hasNegation('no-ansi')); $this->assertFalse($inputDefinition->hasOption('no-interaction')); $this->assertTrue($inputDefinition->hasOption('custom')); diff --git a/src/Symfony/Component/Console/Tests/Command/ListCommandTest.php b/src/Symfony/Component/Console/Tests/Command/ListCommandTest.php index a5d6653ad8..a7c113565e 100644 --- a/src/Symfony/Component/Console/Tests/Command/ListCommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/ListCommandTest.php @@ -80,8 +80,7 @@ Options: -h, --help Display help for the given command. When no command is given display help for the list command -q, --quiet Do not output any message -V, --version Display this application version - --ansi Force ANSI output - --no-ansi Disable ANSI output + --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question -v|vv|vvv, --verbose 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/Tests/Fixtures/application_1.json b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json index bb1eab28ed..9e9cf1b52c 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json @@ -79,7 +79,7 @@ "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Force ANSI output", + "description": "Force (or disable --no-ansi) ANSI output", "default": false }, "no-ansi": { @@ -88,7 +88,7 @@ "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Disable ANSI output", + "description": "Negate the \"--ansi\" option", "default": false }, "no-interaction": { @@ -182,7 +182,7 @@ "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Force ANSI output", + "description": "Force (or disable --no-ansi) ANSI output", "default": false }, "no-ansi": { @@ -191,7 +191,7 @@ "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Disable ANSI output", + "description": "Negate the \"--ansi\" option", "default": false }, "no-interaction": { diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.md b/src/Symfony/Component/Console/Tests/Fixtures/application_1.md index 38c84e4e23..990f750f5b 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.md @@ -42,6 +42,7 @@ The output format (txt, xml, json, or md) * Accept value: yes * Is value required: yes * Is multiple: no +* Is negatable: no * Default: `'txt'` #### `--raw` @@ -51,6 +52,7 @@ To output raw command help * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--help|-h` @@ -60,6 +62,7 @@ Display help for the given command. When no command is given display help for th * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--quiet|-q` @@ -69,6 +72,7 @@ Do not output any message * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--verbose|-v|-vv|-vvv` @@ -78,6 +82,7 @@ Increase the verbosity of messages: 1 for normal output, 2 for more verbose outp * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--version|-V` @@ -87,24 +92,17 @@ Display this application version * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` -#### `--ansi` +#### `--ansi|--no-ansi` -Force ANSI output - -* Accept value: no -* Is value required: no -* Is multiple: no -* Default: `false` - -#### `--no-ansi` - -Disable ANSI output +Force (or disable --no-ansi) ANSI output * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: yes * Default: `false` #### `--no-interaction|-n` @@ -114,6 +112,7 @@ Do not ask any interactive question * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` `list` @@ -160,6 +159,7 @@ To output raw command list * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--format` @@ -169,6 +169,7 @@ The output format (txt, xml, json, or md) * Accept value: yes * Is value required: yes * Is multiple: no +* Is negatable: no * Default: `'txt'` #### `--help|-h` @@ -178,6 +179,7 @@ Display help for the given command. When no command is given display help for th * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--quiet|-q` @@ -187,6 +189,7 @@ Do not output any message * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--verbose|-v|-vv|-vvv` @@ -196,6 +199,7 @@ Increase the verbosity of messages: 1 for normal output, 2 for more verbose outp * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` #### `--version|-V` @@ -205,24 +209,17 @@ Display this application version * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` -#### `--ansi` +#### `--ansi|--no-ansi` -Force ANSI output - -* Accept value: no -* Is value required: no -* Is multiple: no -* Default: `false` - -#### `--no-ansi` - -Disable ANSI output +Force (or disable --no-ansi) ANSI output * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: yes * Default: `false` #### `--no-interaction|-n` @@ -232,4 +229,5 @@ Do not ask any interactive question * Accept value: no * Is value required: no * Is multiple: no +* Is negatable: no * Default: `false` diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_1.txt index cc55447241..47b6524904 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.txt @@ -7,8 +7,7 @@ Console Tool -h, --help Display help for the given command. When no command is given display help for the list command -q, --quiet Do not output any message -V, --version Display this application version - --ansi Force ANSI output - --no-ansi Disable ANSI output + --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question -v|vv|vvv, --verbose 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/Tests/Fixtures/application_1.xml b/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml index 5b6a906c5a..313b0d1cc3 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.xml @@ -46,10 +46,10 @@ Display this application version