diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index f47aef128451a..837f7536f01a2 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -103,6 +103,8 @@ class OptionsResolver implements Options */ private $locked = false; + private $parentsOptions = []; + private static $typeAliases = [ 'boolean' => 'bool', 'integer' => 'int', @@ -423,7 +425,7 @@ public function setDeprecated(string $option, $deprecationMessage = 'The option } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist, defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist, defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } if (!\is_string($deprecationMessage) && !$deprecationMessage instanceof \Closure) { @@ -481,7 +483,7 @@ public function setNormalizer($option, \Closure $normalizer) } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } $this->normalizers[$option] = [$normalizer]; @@ -526,7 +528,7 @@ public function addNormalizer(string $option, \Closure $normalizer, bool $forceP } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } if ($forcePrepend) { @@ -569,7 +571,7 @@ public function setAllowedValues($option, $allowedValues) } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } $this->allowedValues[$option] = \is_array($allowedValues) ? $allowedValues : [$allowedValues]; @@ -610,7 +612,7 @@ public function addAllowedValues($option, $allowedValues) } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } if (!\is_array($allowedValues)) { @@ -651,7 +653,7 @@ public function setAllowedTypes($option, $allowedTypes) } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } $this->allowedTypes[$option] = (array) $allowedTypes; @@ -686,7 +688,7 @@ public function addAllowedTypes($option, $allowedTypes) } if (!isset($this->defined[$option])) { - throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } if (!isset($this->allowedTypes[$option])) { @@ -793,7 +795,7 @@ public function resolve(array $options = []) ksort($clone->defined); ksort($diff); - throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', implode('", "', array_keys($diff)), implode('", "', array_keys($clone->defined)))); + throw new UndefinedOptionsException(sprintf((\count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Defined options are: "%s".', $this->formatOptions(array_keys($diff)), implode('", "', array_keys($clone->defined)))); } // Override options set by the user @@ -809,7 +811,7 @@ public function resolve(array $options = []) if (\count($diff) > 0) { ksort($diff); - throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', implode('", "', array_keys($diff)))); + throw new MissingOptionsException(sprintf(\count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.', $this->formatOptions(array_keys($diff)))); } // Lock the container @@ -860,10 +862,10 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) // Check whether the option is set at all if (!isset($this->defaults[$option]) && !\array_key_exists($option, $this->defaults)) { if (!isset($this->defined[$option])) { - throw new NoSuchOptionException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + throw new NoSuchOptionException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $this->formatOptions([$option]), implode('", "', array_keys($this->defined)))); } - throw new NoSuchOptionException(sprintf('The optional option "%s" has no value set. You should make sure it is set with "isset" before reading it.', $option)); + throw new NoSuchOptionException(sprintf('The optional option "%s" has no value set. You should make sure it is set with "isset" before reading it.', $this->formatOptions([$option]))); } $value = $this->defaults[$option]; @@ -872,17 +874,19 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) if (isset($this->nested[$option])) { // If the closure is already being called, we have a cyclic dependency if (isset($this->calling[$option])) { - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); } if (!\is_array($value)) { - throw new InvalidOptionsException(sprintf('The nested option "%s" with value %s is expected to be of type array, but is of type "%s".', $option, $this->formatValue($value), $this->formatTypeOf($value))); + throw new InvalidOptionsException(sprintf('The nested option "%s" with value %s is expected to be of type array, but is of type "%s".', $this->formatOptions([$option]), $this->formatValue($value), $this->formatTypeOf($value))); } // The following section must be protected from cyclic calls. $this->calling[$option] = true; try { $resolver = new self(); + $resolver->parentsOptions = $this->parentsOptions; + $resolver->parentsOptions[] = $option; foreach ($this->nested[$option] as $closure) { $closure($resolver, $this); } @@ -897,7 +901,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) // If the closure is already being called, we have a cyclic // dependency if (isset($this->calling[$option])) { - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); } // The following section must be protected from cyclic @@ -932,10 +936,10 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) $keys = array_keys($invalidTypes); if (1 === \count($keys) && '[]' === substr($keys[0], -2)) { - throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), $keys[0])); + throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $this->formatOptions([$option]), $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), $keys[0])); } - throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), implode('|', array_keys($invalidTypes)))); + throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $this->formatOptions([$option]), $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), implode('|', array_keys($invalidTypes)))); } } @@ -989,7 +993,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) if ($deprecationMessage instanceof \Closure) { // If the closure is already being called, we have a cyclic dependency if (isset($this->calling[$option])) { - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); } $this->calling[$option] = true; @@ -1012,7 +1016,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) // If the closure is already being called, we have a cyclic // dependency if (isset($this->calling[$option])) { - throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); + throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', $this->formatOptions(array_keys($this->calling)))); } // The following section must be protected from cyclic @@ -1195,4 +1199,20 @@ private function formatValues(array $values): string return implode(', ', $values); } + + private function formatOptions(array $options): string + { + if ($this->parentsOptions) { + $prefix = array_shift($this->parentsOptions); + if ($this->parentsOptions) { + $prefix .= sprintf('[%s]', implode('][', $this->parentsOptions)); + } + + $options = array_map(static function (string $option) use ($prefix): string { + return sprintf('%s[%s]', $prefix, $option); + }, $options); + } + + return implode('", "', $options); + } } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index 43ebf408e90b0..dc2aba7424677 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -1993,7 +1993,7 @@ public function testIsNestedOption() public function testFailsIfUndefinedNestedOption() { $this->expectException('Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException'); - $this->expectExceptionMessage('The option "foo" does not exist. Defined options are: "host", "port".'); + $this->expectExceptionMessage('The option "database[foo]" does not exist. Defined options are: "host", "port".'); $this->resolver->setDefaults([ 'name' => 'default', 'database' => function (OptionsResolver $resolver) { @@ -2008,7 +2008,7 @@ public function testFailsIfUndefinedNestedOption() public function testFailsIfMissingRequiredNestedOption() { $this->expectException('Symfony\Component\OptionsResolver\Exception\MissingOptionsException'); - $this->expectExceptionMessage('The required option "host" is missing.'); + $this->expectExceptionMessage('The required option "database[host]" is missing.'); $this->resolver->setDefaults([ 'name' => 'default', 'database' => function (OptionsResolver $resolver) { @@ -2023,7 +2023,7 @@ public function testFailsIfMissingRequiredNestedOption() public function testFailsIfInvalidTypeNestedOption() { $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); - $this->expectExceptionMessage('The option "logging" with value null is expected to be of type "bool", but is of type "NULL".'); + $this->expectExceptionMessage('The option "database[logging]" with value null is expected to be of type "bool", but is of type "NULL".'); $this->resolver->setDefaults([ 'name' => 'default', 'database' => function (OptionsResolver $resolver) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy