Skip to content

Commit 2be23e6

Browse files
Merge branch '4.3' into 4.4
* 4.3: Fix an error message to be more accurate
2 parents 69a6276 + f46c7fc commit 2be23e6

File tree

2 files changed

+30
-23
lines changed

2 files changed

+30
-23
lines changed

OptionsResolver.php

+16-14
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/)
921921

922922
// Validate the type of the resolved option
923923
if (isset($this->allowedTypes[$option])) {
924-
$valid = false;
924+
$valid = true;
925925
$invalidTypes = [];
926926

927927
foreach ($this->allowedTypes[$option] as $type) {
@@ -933,13 +933,18 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/)
933933
}
934934

935935
if (!$valid) {
936-
$keys = array_keys($invalidTypes);
937-
938-
if (1 === \count($keys) && '[]' === substr($keys[0], -2)) {
939-
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]));
936+
$fmtActualValue = $this->formatValue($value);
937+
$fmtAllowedTypes = implode('" or "', $this->allowedTypes[$option]);
938+
$fmtProvidedTypes = implode('|', array_keys($invalidTypes));
939+
$allowedContainsArrayType = \count(array_filter($this->allowedTypes[$option], static function ($item) {
940+
return '[]' === substr(self::$typeAliases[$item] ?? $item, -2);
941+
})) > 0;
942+
943+
if (\is_array($value) && $allowedContainsArrayType) {
944+
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]), $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
940945
}
941946

942-
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))));
947+
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]), $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
943948
}
944949
}
945950

@@ -1044,26 +1049,23 @@ private function verifyTypes(string $type, $value, array &$invalidTypes, int $le
10441049
{
10451050
if (\is_array($value) && '[]' === substr($type, -2)) {
10461051
$type = substr($type, 0, -2);
1052+
$valid = true;
10471053

10481054
foreach ($value as $val) {
10491055
if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) {
1050-
return false;
1056+
$valid = false;
10511057
}
10521058
}
10531059

1054-
return true;
1060+
return $valid;
10551061
}
10561062

10571063
if (('null' === $type && null === $value) || (\function_exists($func = 'is_'.$type) && $func($value)) || $value instanceof $type) {
10581064
return true;
10591065
}
10601066

1061-
if (!$invalidTypes) {
1062-
$suffix = '';
1063-
while (\strlen($suffix) < $level * 2) {
1064-
$suffix .= '[]';
1065-
}
1066-
$invalidTypes[$this->formatTypeOf($value).$suffix] = true;
1067+
if (!$invalidTypes || $level > 0) {
1068+
$invalidTypes[$this->formatTypeOf($value)] = true;
10671069
}
10681070

10691071
return false;

Tests/OptionsResolverTest.php

+14-9
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ public function testFailIfSetAllowedTypesFromLazyOption()
776776
public function testResolveFailsIfInvalidTypedArray()
777777
{
778778
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
779-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime[]".');
779+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime".');
780780
$this->resolver->setDefined('foo');
781781
$this->resolver->setAllowedTypes('foo', 'int[]');
782782

@@ -796,7 +796,7 @@ public function testResolveFailsWithNonArray()
796796
public function testResolveFailsIfTypedArrayContainsInvalidTypes()
797797
{
798798
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
799-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass[]".');
799+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass|array|DateTime".');
800800
$this->resolver->setDefined('foo');
801801
$this->resolver->setAllowedTypes('foo', 'int[]');
802802
$values = range(1, 5);
@@ -811,7 +811,7 @@ public function testResolveFailsIfTypedArrayContainsInvalidTypes()
811811
public function testResolveFailsWithCorrectLevelsButWrongScalar()
812812
{
813813
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
814-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double[][]".');
814+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double".');
815815
$this->resolver->setDefined('foo');
816816
$this->resolver->setAllowedTypes('foo', 'int[][]');
817817

@@ -847,6 +847,11 @@ public function provideInvalidTypes()
847847
[42, 'string', 'The option "option" with value 42 is expected to be of type "string", but is of type "integer".'],
848848
[null, 'string', 'The option "option" with value null is expected to be of type "string", but is of type "NULL".'],
849849
['bar', '\stdClass', 'The option "option" with value "bar" is expected to be of type "\stdClass", but is of type "string".'],
850+
[['foo', 12], 'string[]', 'The option "option" with value array is expected to be of type "string[]", but one of the elements is of type "integer".'],
851+
[123, ['string[]', 'string'], 'The option "option" with value 123 is expected to be of type "string[]" or "string", but is of type "integer".'],
852+
[[null], ['string[]', 'string'], 'The option "option" with value array is expected to be of type "string[]" or "string", but one of the elements is of type "NULL".'],
853+
[['string', null], ['string[]', 'string'], 'The option "option" with value array is expected to be of type "string[]" or "string", but one of the elements is of type "NULL".'],
854+
[[\stdClass::class], ['string'], 'The option "option" with value array is expected to be of type "string", but is of type "array".'],
850855
];
851856
}
852857

@@ -1898,7 +1903,7 @@ public function testNested2Arrays()
18981903
public function testNestedArraysException()
18991904
{
19001905
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1901-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer[][][][]".');
1906+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer".');
19021907
$this->resolver->setDefined('foo');
19031908
$this->resolver->setAllowedTypes('foo', 'float[][][][]');
19041909

@@ -1916,7 +1921,7 @@ public function testNestedArraysException()
19161921
public function testNestedArrayException1()
19171922
{
19181923
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1919-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".');
1924+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean|string|array".');
19201925
$this->resolver->setDefined('foo');
19211926
$this->resolver->setAllowedTypes('foo', 'int[][]');
19221927
$this->resolver->resolve([
@@ -1929,7 +1934,7 @@ public function testNestedArrayException1()
19291934
public function testNestedArrayException2()
19301935
{
19311936
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1932-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".');
1937+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean|string|array".');
19331938
$this->resolver->setDefined('foo');
19341939
$this->resolver->setAllowedTypes('foo', 'int[][]');
19351940
$this->resolver->resolve([
@@ -1942,7 +1947,7 @@ public function testNestedArrayException2()
19421947
public function testNestedArrayException3()
19431948
{
19441949
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1945-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string[][]".');
1950+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string|integer".');
19461951
$this->resolver->setDefined('foo');
19471952
$this->resolver->setAllowedTypes('foo', 'string[][][]');
19481953
$this->resolver->resolve([
@@ -1955,7 +1960,7 @@ public function testNestedArrayException3()
19551960
public function testNestedArrayException4()
19561961
{
19571962
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1958-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer[][][]".');
1963+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer".');
19591964
$this->resolver->setDefined('foo');
19601965
$this->resolver->setAllowedTypes('foo', 'string[][][]');
19611966
$this->resolver->resolve([
@@ -1969,7 +1974,7 @@ public function testNestedArrayException4()
19691974
public function testNestedArrayException5()
19701975
{
19711976
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1972-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array[]".');
1977+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array".');
19731978
$this->resolver->setDefined('foo');
19741979
$this->resolver->setAllowedTypes('foo', 'string[]');
19751980
$this->resolver->resolve([

0 commit comments

Comments
 (0)