Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6556c8d

Browse files
bug #63052 [Serializer] Fix NameConverter not detecting wrong input format with allow_extra_attributes=false (xersion22)
This PR was merged into the 6.4 branch. Discussion ---------- [Serializer] Fix NameConverter not detecting wrong input format with `allow_extra_attributes=false` | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #62725 | License | MIT When using a `NameConverter` with `allow_extra_attributes=false`, wrongly formatted input (e.g., `someCamelCaseProperty` instead of `some_camel_case_property`) was silently accepted because the unconverted attribute name happened to match the property name. This fix detects when the `NameConverter` didn't transform the input and checks if the property requires a different serialized format. If so, it flags the input as an extra attribute and throws `ExtraAttributesException`. Commits ------- 55b5388eb53 [Serializer] Fix NameConverter not detecting wrong input format with allow_extra_attributes=false
2 parents 43a730a + ff43530 commit 6556c8d

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

Normalizer/AbstractObjectNormalizer.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,16 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
358358
if (isset($nestedData[$notConverted]) && !isset($originalNestedData[$attribute])) {
359359
throw new LogicException(\sprintf('Duplicate values for key "%s" found. One value is set via the SerializedPath attribute: "%s", the other one is set via the SerializedName attribute: "%s".', $notConverted, implode('->', $nestedAttributes[$notConverted]->getElements()), $attribute));
360360
}
361+
362+
if ($attribute === $notConverted
363+
&& !($context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES])
364+
&& (false === $allowedAttributes || \in_array($attribute, $allowedAttributes, true))
365+
&& $this->nameConverter->normalize($attribute, $resolvedClass, $format, $context) !== $attribute
366+
) {
367+
// Input was in wrong format (e.g., camelCase when snake_case expected)
368+
$extraAttributes[] = $notConverted;
369+
continue;
370+
}
361371
}
362372

363373
$attributeContext = $this->getAttributeDenormalizationContext($resolvedClass, $attribute, $context);

Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
2121
use Symfony\Component\Serializer\Attribute\Groups;
2222
use Symfony\Component\Serializer\Attribute\Ignore;
23+
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
2324
use Symfony\Component\Serializer\Exception\LogicException;
2425
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
2526
use Symfony\Component\Serializer\Exception\RuntimeException;
@@ -1202,6 +1203,51 @@ public function testDiscriminatorWithAllowExtraAttributesFalse()
12021203
$this->assertInstanceOf(DiscriminatorDummyTypeA::class, $obj);
12031204
}
12041205

1206+
public function testNameConverterWithWrongCaseAndAllowExtraAttributesFalse()
1207+
{
1208+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1209+
$normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
1210+
1211+
$result = $normalizer->denormalize(
1212+
['some_camel_case_property' => 1],
1213+
NameConverterTestDummy::class,
1214+
null,
1215+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false]
1216+
);
1217+
$this->assertSame(1, $result->someCamelCaseProperty);
1218+
1219+
$this->expectException(ExtraAttributesException::class);
1220+
$this->expectExceptionMessage('someCamelCaseProperty');
1221+
$normalizer->denormalize(
1222+
['someCamelCaseProperty' => 1],
1223+
NameConverterTestDummy::class,
1224+
null,
1225+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false]
1226+
);
1227+
}
1228+
1229+
public function testNameConverterWithWrongCaseAndAllowExtraAttributesTrue()
1230+
{
1231+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1232+
$normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
1233+
1234+
$result = $normalizer->denormalize(
1235+
['someCamelCaseProperty' => 999],
1236+
NameConverterTestDummy::class,
1237+
null,
1238+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => true]
1239+
);
1240+
$this->assertSame(0, $result->someCamelCaseProperty);
1241+
1242+
$result = $normalizer->denormalize(
1243+
['some_camel_case_property' => 42],
1244+
NameConverterTestDummy::class,
1245+
null,
1246+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => true]
1247+
);
1248+
$this->assertSame(42, $result->someCamelCaseProperty);
1249+
}
1250+
12051251
public function testNormalizeObjectWithGroupsAndIsPrefixedProperty()
12061252
{
12071253
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
@@ -1756,3 +1802,20 @@ public function visibleGroup()
17561802
return $this->visibleGroup;
17571803
}
17581804
}
1805+
1806+
class NameConverterTestDummy
1807+
{
1808+
public function __construct(
1809+
public readonly int $someCamelCaseProperty = 0,
1810+
) {
1811+
}
1812+
}
1813+
1814+
class NameConverterTestDummyMultiple
1815+
{
1816+
public function __construct(
1817+
public readonly int $someCamelCaseProperty = 0,
1818+
public readonly int $anotherProperty = 0,
1819+
) {
1820+
}
1821+
}

0 commit comments

Comments
 (0)