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

Skip to content

Commit ddf7926

Browse files
xersion22nicolas-grekas
authored andcommitted
[Serializer] Fix NameConverter not detecting wrong input format with allow_extra_attributes=false (fixes #62725)
1 parent 9cbc471 commit ddf7926

2 files changed

Lines changed: 140 additions & 0 deletions

File tree

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,20 @@ 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 nameConverter didn't transform the input, check if the format was wrong
363+
if ($attribute === $notConverted
364+
&& !($context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES])
365+
&& (false === $allowedAttributes || \in_array($attribute, $allowedAttributes, true))
366+
) {
367+
// Property exists - check if it requires a different serialized format
368+
$normalizedVersion = $this->nameConverter->normalize($attribute, $resolvedClass, $format, $context);
369+
if ($normalizedVersion !== $attribute) {
370+
// Input was in wrong format (e.g., camelCase when snake_case expected)
371+
$extraAttributes[] = $notConverted;
372+
continue;
373+
}
374+
}
361375
}
362376

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

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,115 @@ public function testDiscriminatorWithAllowExtraAttributesFalse()
12021202
$this->assertInstanceOf(DiscriminatorDummyTypeA::class, $obj);
12031203
}
12041204

1205+
public function testNameConverterWithWrongCaseAndAllowExtraAttributesFalse()
1206+
{
1207+
// When using a name converter with allow_extra_attributes=false,
1208+
// wrongly cased properties should trigger an exception
1209+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1210+
$normalizer = new ObjectNormalizer(
1211+
$classMetadataFactory,
1212+
new CamelCaseToSnakeCaseNameConverter()
1213+
);
1214+
1215+
// This should work - correct snake_case format
1216+
$result = $normalizer->denormalize(
1217+
['some_camel_case_property' => 1],
1218+
NameConverterTestDummy::class,
1219+
null,
1220+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false]
1221+
);
1222+
$this->assertSame(1, $result->someCamelCaseProperty);
1223+
1224+
// This should throw an exception - wrong camelCase format when snake_case is expected
1225+
$this->expectException(\Symfony\Component\Serializer\Exception\ExtraAttributesException:: class);
1226+
$normalizer->denormalize(
1227+
['someCamelCaseProperty' => 1],
1228+
NameConverterTestDummy::class,
1229+
null,
1230+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false]
1231+
);
1232+
}
1233+
1234+
public function testNameConverterWithWrongCaseAndAllowExtraAttributesTrue()
1235+
{
1236+
// When allow_extra_attributes=true (default), wrong format should be silently ignored
1237+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1238+
$normalizer = new ObjectNormalizer(
1239+
$classMetadataFactory,
1240+
new CamelCaseToSnakeCaseNameConverter()
1241+
);
1242+
1243+
// Wrong format should be ignored, property uses default value
1244+
$result = $normalizer->denormalize(
1245+
['someCamelCaseProperty' => 999],
1246+
NameConverterTestDummy::class,
1247+
null,
1248+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => true]
1249+
);
1250+
// Property should have default value since 'someCamelCaseProperty' was ignored
1251+
$this->assertSame(0, $result->someCamelCaseProperty);
1252+
1253+
// Correct format should work normally
1254+
$result = $normalizer->denormalize(
1255+
['some_camel_case_property' => 42],
1256+
NameConverterTestDummy::class,
1257+
null,
1258+
[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => true]
1259+
);
1260+
$this->assertSame(42, $result->someCamelCaseProperty);
1261+
}
1262+
1263+
public function testNameConverterWithMixedCorrectAndIncorrectFormat()
1264+
{
1265+
// Test with multiple properties where some are correct, some are wrong
1266+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1267+
$normalizer = new ObjectNormalizer(
1268+
$classMetadataFactory,
1269+
new CamelCaseToSnakeCaseNameConverter()
1270+
);
1271+
1272+
// Mix of correct (snake_case) and incorrect (camelCase) should fail
1273+
$this->expectException(\Symfony\Component\Serializer\Exception\ExtraAttributesException::class);
1274+
$this->expectExceptionMessage('someCamelCaseProperty');
1275+
1276+
$normalizer->denormalize(
1277+
[
1278+
'some_camel_case_property' => 1, // Correct format
1279+
'someCamelCaseProperty' => 2, // Wrong format - should trigger exception
1280+
'another_property' => 3, // Correct format
1281+
],
1282+
NameConverterTestDummyMultiple::class,
1283+
null,
1284+
[AbstractNormalizer:: ALLOW_EXTRA_ATTRIBUTES => false]
1285+
);
1286+
}
1287+
1288+
public function testNameConverterWithoutStrictModeStillWorks()
1289+
{
1290+
// Ensure the default behavior (without allow_extra_attributes context) still works
1291+
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
1292+
$normalizer = new ObjectNormalizer(
1293+
$classMetadataFactory,
1294+
new CamelCaseToSnakeCaseNameConverter()
1295+
);
1296+
1297+
// Correct snake_case format should work
1298+
$result1 = $normalizer->denormalize(
1299+
['some_camel_case_property' => 1],
1300+
NameConverterTestDummy::class
1301+
);
1302+
$this->assertSame(1, $result1->someCamelCaseProperty);
1303+
1304+
// Wrong format (camelCase instead of snake_case) is silently ignored
1305+
// when allow_extra_attributes is not set (defaults to true)
1306+
$result2 = $normalizer->denormalize(
1307+
['someCamelCaseProperty' => 2],
1308+
NameConverterTestDummy::class
1309+
);
1310+
// Property keeps default value since wrong format was ignored
1311+
$this->assertSame(0, $result2->someCamelCaseProperty);
1312+
}
1313+
12051314
public function testNormalizeObjectWithGroupsAndIsPrefixedProperty()
12061315
{
12071316
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
@@ -1756,3 +1865,20 @@ public function visibleGroup()
17561865
return $this->visibleGroup;
17571866
}
17581867
}
1868+
1869+
class NameConverterTestDummy
1870+
{
1871+
public function __construct(
1872+
public readonly int $someCamelCaseProperty = 0,
1873+
) {
1874+
}
1875+
}
1876+
1877+
class NameConverterTestDummyMultiple
1878+
{
1879+
public function __construct(
1880+
public readonly int $someCamelCaseProperty = 0,
1881+
public readonly int $anotherProperty = 0,
1882+
) {
1883+
}
1884+
}

0 commit comments

Comments
 (0)