8000 minor #30442 [OptionsResolver] Fix an error message to be more accura… · symfony/symfony@fb70e0a · GitHub
[go: up one dir, main page]

Skip to content

Commit fb70e0a

Browse files
committed
minor #30442 [OptionsResolver] Fix an error message to be more accurate (dimabory)
This PR was merged into the 3.4 branch. Discussion ---------- [OptionsResolver] Fix an error message to be more accurate | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #30432 | License | MIT | Doc PR | See #30432 for more details: > **Symfony version(s) affected**: 3.4, maybe other versions too (not tested) > > **Description** > Error message when allowedTypes is an array contains `[]` but should not: > `The option "testme" with value array is expected to be of type "string[]", but one of the elements is of type "integer[]".` > It should be: > `The option "testme" with value array is expected to be of type "string[]", but one of the elements is of type "integer".` > > **How to reproduce** > > ``` > $resolver = (new OptionsResolver()) > ->setDefault('testme', []) > ->setAllowedTypes('testme', ['string[]']) > ->resolve(['testme' => ['test', 12]]); > ``` In addition I changed an error message to be more accurate if provided more than one incorrect value: > [...] is expected to be of type "integer[][]", but is of type "integer|boolean|string". Commits ------- 7fa2fc2 #30432 fix an error message
2 parents 2a5c755 + 7fa2fc2 commit fb70e0a

File tree

2 files changed

+38
-27
lines changed

2 files changed

+38
-27
lines changed

src/Symfony/Component/OptionsResolver/OptionsResolver.php

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ public function offsetGet($option)
734734

735735
// Validate the type of the resolved option
736736
if (isset($this->allowedTypes[$option])) {
737-
$valid = false;
737+
$valid = true;
738738
$invalidTypes = [];
739739

740740
foreach ($this->allowedTypes[$option] as $type) {
@@ -746,13 +746,22 @@ public function offsetGet($option)
746746
}
747747

748748
if (!$valid) {
749-
$keys = array_keys($invalidTypes);
749+
$fmtActualValue = $this->formatValue($value);
750+
$fmtAllowedTypes = implode('" or "', $this->allowedTypes[$option]);
751+
$fmtProvidedTypes = implode('|', array_keys($invalidTypes));
752+
753+
$allowedContainsArrayType = \count(array_filter(
754+
$this->allowedTypes[$option],
755+
function ($item) {
756+
return '[]' === substr(isset(self::$typeAliases[$item]) ? self::$typeAliases[$item] : $item, -2);
757+
}
758+
)) > 0;
750759

751-
if (1 === \count($keys) && '[]' === substr($keys[0], -2)) {
752-
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]));
760+
if (\is_array($value) && $allowedContainsArrayType) {
761+
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, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
753762
}
754763

755-
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))));
764+
throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
756765
}
757766
}
758767

@@ -858,37 +867,32 @@ private function verifyArrayType($type, array $value, array &$invalidTypes, $lev
858867
{
859868
$type = substr($type, 0, -2);
860869

861-
$suffix = '[]';
862-
while (\strlen($suffix) <= $level * 2) {
863-
$suffix .= '[]';
864-
}
865-
866870
if ('[]' === substr($type, -2)) {
867871
$success = true;
868872
foreach ($value as $item) {
869873
if (!\is_array($item)) {
870-
$invalidTypes[$this->formatTypeOf($item, null).$suffix] = true;
874+
$invalidTypes[$this->formatTypeOf($item, null)] = true;
871875

872-
return false;
873-
}
874-
875-
if (!$this->verifyArrayType($type, $item, $invalidTypes, $level + 1)) {
876+
$success = false;
877+
} elseif (!$this->verifyArrayType($type, $item, $invalidTypes, $level + 1)) {
876878
$success = false;
877879
}
878880
}
879881

880882
return $success;
881883
}
882884

885+
$valid = true;
886+
883887
foreach ($value as $item) {
884888
if (!self::isValueValidType($type, $item)) {
885-
$invalidTypes[$this->formatTypeOf($item, $type).$suffix] = $value;
889+
$invalidTypes[$this->formatTypeOf($item, $type)] = $value;
886890

887-
return false;
891+
$valid = false;
888892
}
889893
}
890894

891-
return true;
895+
return $valid;
892896
}
893897

894898
/**

src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ public function testFailIfSetAllowedTypesFromLazyOption()
466466
public function testResolveFailsIfInvalidTypedArray()
467467
{
468468
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
469-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime[]".');
469+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime".');
470470
$this->resolver->setDefined('foo');
471471
$this->resolver->setAllowedTypes('foo', 'int[]');
472472

@@ -486,9 +486,10 @@ public function testResolveFailsWithNonArray()
486486
public function testResolveFailsIfTypedArrayContainsInvalidTypes()
487487
{
488488
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
489-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass[]".');
489+
$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".');
490490
$this->resolver->setDefined('foo');
491491
$this->resolver->setAllowedTypes('foo', 'int[]');
492+
492493
$values = range(1, 5);
493494
$values[] = new \stdClass();
494495
$values[] = [];
@@ -501,7 +502,7 @@ public function testResolveFailsIfTypedArrayContainsInvalidTypes()
501502
public function testResolveFailsWithCorrectLevelsButWrongScalar()
502503
{
503504
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
504-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double[][]".');
505+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double".');
505506
$this->resolver->setDefined('foo');
506507
$this->resolver->setAllowedTypes('foo', 'int[][]');
507508

@@ -537,6 +538,11 @@ public function provideInvalidTypes()
537538
[42, 'string', 'The option "option" with value 42 is expected to be of type "string", but is of type "integer".'],
538539
[null, 'string', 'The option "option" with value null is expected to be of type "string", but is of type "NULL".'],
539540
['bar', '\stdClass', 'The option "option" with value "bar" is expected to be of type "\stdClass", but is of type "string".'],
541+
[['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".'],
542+
[123, ['string[]', 'string'], 'The option "option" with value 123 is expected to be of type "string[]" or "string", but is of type "integer".'],
543+
[[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".'],
544+
[['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".'],
545+
[[\stdClass::class], ['string'], 'The option "option" with value array is expected to be of type "string", but is of type "array".'],
540546
];
541547
}
542548

@@ -585,6 +591,7 @@ public function testResolveSucceedsIfTypedArray()
585591
new \DateTime(),
586592
],
587593
];
594+
588595
$result = $this->resolver->resolve($data);
589596
$this->assertEquals($data, $result);
590597
}
@@ -1535,7 +1542,7 @@ public function testNested2Arrays()
15351542
public function testNestedArraysException()
15361543
{
15371544
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1538-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer[][][][]".');
1545+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer".');
15391546
$this->resolver->setDefined('foo');
15401547
$this->resolver->setAllowedTypes('foo', 'float[][][][]');
15411548

@@ -1553,7 +1560,7 @@ public function testNestedArraysException()
15531560
public function testNestedArrayException1()
15541561
{
15551562
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1556-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of th 10000 e elements is of type "boolean[][]".');
1563+
$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".');
15571564
$this->resolver->setDefined('foo');
15581565
$this->resolver->setAllowedTypes('foo', 'int[][]');
15591566
$this->resolver->resolve([
@@ -1566,7 +1573,7 @@ public function testNestedArrayException1()
15661573
public function testNestedArrayException2()
15671574
{
15681575
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1569-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".');
1576+
$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".');
15701577
$this->resolver->setDefined('foo');
15711578
$this->resolver->setAllowedTypes('foo', 'int[][]');
15721579
$this->resolver->resolve([
@@ -1579,7 +1586,7 @@ public function testNestedArrayException2()
15791586
public function testNestedArrayException3()
15801587
{
15811588
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1582-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string[][]".');
1589+
$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".');
15831590
$this->resolver->setDefined('foo');
15841591
$this->resolver->setAllowedTypes('foo', 'string[][][]');
15851592
$this->resolver->resolve([
@@ -1592,7 +1599,7 @@ public function testNestedArrayException3()
15921599
public function testNestedArrayException4()
15931600
{
15941601
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1595-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer[][][]".');
1602+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer".');
15961603
$this->resolver->setDefined('foo');
15971604
$this->resolver->setAllowedTypes('foo', 'string[][][]');
15981605
$this->resolver->resolve([
@@ -1606,7 +1613,7 @@ public function testNestedArrayException4()
16061613
public function testNestedArrayException5()
16071614
{
16081615
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
1609-
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array[]".');
1616+
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array".');
16101617
$this->resolver->setDefined('foo');
16111618
$this->resolver->setAllowedTypes('foo', 'string[]');
16121619
$this->resolver->resolve([

0 commit comments

Comments
 (0)
0