Skip to content

Commit ff3255c

Browse files
authored
fix(serializer): check which instance of NameConverterInstance is used (#5398)
1 parent bad7bc9 commit ff3255c

File tree

3 files changed

+109
-24
lines changed

3 files changed

+109
-24
lines changed

src/Serializer/AbstractConstraintViolationListNormalizer.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Serializer;
1515

16+
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
1617
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
1718
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
1819
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
@@ -56,8 +57,17 @@ protected function getMessagesAndViolations(ConstraintViolationListInterface $co
5657

5758
foreach ($constraintViolationList as $violation) {
5859
$class = \is_object($root = $violation->getRoot()) ? $root::class : null;
60+
61+
if ($this->nameConverter instanceof AdvancedNameConverterInterface) {
62+
$propertyPath = $this->nameConverter->normalize($violation->getPropertyPath(), $class, static::FORMAT);
63+
} elseif ($this->nameConverter instanceof NameConverterInterface) {
64+
$propertyPath = $this->nameConverter->normalize($violation->getPropertyPath());
65+
} else {
66+
$propertyPath = $violation->getPropertyPath();
67+
}
68+
5969
$violationData = [
60-
'propertyPath' => $this->nameConverter ? $this->nameConverter->normalize($violation->getPropertyPath(), $class, static::FORMAT) : $violation->getPropertyPath(),
70+
'propertyPath' => $propertyPath,
6171
'message' => $violation->getMessage(),
6272
'code' => $violation->getCode(),
6373
];

tests/Hydra/Serializer/ConstraintViolationNormalizerTest.php

+57-17
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPUnit\Framework\TestCase;
1919
use Prophecy\Argument;
2020
use Prophecy\PhpUnit\ProphecyTrait;
21+
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
2122
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2223
use Symfony\Component\Validator\Constraints\NotNull;
2324
use Symfony\Component\Validator\ConstraintViolation;
@@ -44,17 +45,14 @@ public function testSupportNormalization(): void
4445
}
4546

4647
/**
47-
* @dataProvider payloadFieldsProvider
48+
* @dataProvider nameConverterAndPayloadFieldsProvider
4849
*/
49-
public function testNormalize(?array $fields, array $result): void
50+
public function testNormalize(?object $nameConverter, ?array $fields, array $expected): void
5051
{
5152
$urlGeneratorProphecy = $this->prophesize(UrlGeneratorInterface::class);
52-
$nameConverterProphecy = $this->prophesize(NameConverterInterface::class);
53-
5453
$urlGeneratorProphecy->generate('api_jsonld_context', ['shortName' => 'ConstraintViolationList'])->willReturn('/context/foo')->shouldBeCalled();
55-
$nameConverterProphecy->normalize(Argument::type('string'), null, Argument::type('string'))->will(fn ($args): string => '_'.$args[0]);
5654

57-
$normalizer = new ConstraintViolationListNormalizer($urlGeneratorProphecy->reveal(), $fields, $nameConverterProphecy->reveal());
55+
$normalizer = new ConstraintViolationListNormalizer($urlGeneratorProphecy->reveal(), $fields, $nameConverter);
5856

5957
// Note : we use NotNull constraint and not Constraint class because Constraint is abstract
6058
$constraint = new NotNull();
@@ -64,7 +62,31 @@ public function testNormalize(?array $fields, array $result): void
6462
new ConstraintViolation('1', '2', [], '3', '4', '5'),
6563
]);
6664

67-
$expected = [
65+
$this->assertSame($expected, $normalizer->normalize($list));
66+
}
67+
68+
public function nameConverterAndPayloadFieldsProvider(): iterable
69+
{
70+
$basicExpectation = [
71+
'@context' => '/context/foo',
72+
'@type' => 'ConstraintViolationList',
73+
'hydra:title' => 'An error occurred',
74+
'hydra:description' => "d: a\n4: 1",
75+
'violations' => [
76+
[
77+
'propertyPath' => 'd',
78+
'message' => 'a',
79+
'code' => 'f24bdbad0becef97a6887238aa58221c',
80+
],
81+
[
82+
'propertyPath' => '4',
83+
'message' => '1',
84+
'code' => null,
85+
],
86+
],
87+
];
88+
89+
$nameConverterBasedExpectation = [
6890
'@context' => '/context/foo',
6991
'@type' => 'ConstraintViolationList',
7092
'hydra:title' => 'An error occurred',
@@ -82,17 +104,35 @@ public function testNormalize(?array $fields, array $result): void
82104
],
83105
],
84106
];
85-
if ([] !== $result) {
86-
$expected['violations'][0]['payload'] = $result;
87-
}
88107

89-
$this->assertSame($expected, $normalizer->normalize($list));
90-
}
108+
$advancedNameConverterProphecy = $this->prophesize(AdvancedNameConverterInterface::class);
109+
$advancedNameConverterProphecy->normalize(Argument::type('string'), null, Argument::type('string'))->will(fn ($args): string => '_'.$args[0]);
110+
$advancedNameConverter = $advancedNameConverterProphecy->reveal();
91111

92-
public function payloadFieldsProvider(): iterable
93-
{
94-
yield [['severity', 'anotherField1'], ['severity' => 'warning']];
95-
yield [null, ['severity' => 'warning', 'anotherField2' => 'aValue']];
96-
yield [[], []];
112+
$nameConverterProphecy = $this->prophesize(NameConverterInterface::class);
113+
$nameConverterProphecy->normalize(Argument::type('string'))->will(fn ($args): string => '_'.$args[0]);
114+
$nameConverter = $nameConverterProphecy->reveal();
115+
116+
$nullNameConverter = null;
117+
118+
$expected = $nameConverterBasedExpectation;
119+
$expected['violations'][0]['payload'] = ['severity' => 'warning'];
120+
yield [$advancedNameConverter, ['severity', 'anotherField1'], $expected];
121+
yield [$nameConverter, ['severity', 'anotherField1'], $expected];
122+
$expected = $basicExpectation;
123+
$expected['violations'][0]['payload'] = ['severity' => 'warning'];
124+
yield [$nullNameConverter, ['severity', 'anotherField1'], $expected];
125+
126+
$expected = $nameConverterBasedExpectation;
127+
$expected['violations'][0]['payload'] = ['severity' => 'warning', 'anotherField2' => 'aValue'];
128+
yield [$advancedNameConverter, null, $expected];
129+
yield [$nameConverter, null, $expected];
130+
$expected = $basicExpectation;
131+
$expected['violations'][0]['payload'] = ['severity' => 'warning', 'anotherField2' => 'aValue'];
132+
yield [$nullNameConverter, null, $expected];
133+
134+
yield [$advancedNameConverter, [], $nameConverterBasedExpectation];
135+
yield [$nameConverter, [], $nameConverterBasedExpectation];
136+
yield [$nullNameConverter, [], $basicExpectation];
97137
}
98138
}

tests/Problem/Serializer/ConstraintViolationNormalizerTest.php

+41-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use PHPUnit\Framework\TestCase;
1818
use Prophecy\Argument;
1919
use Prophecy\PhpUnit\ProphecyTrait;
20+
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
2021
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
2122
use Symfony\Component\Validator\Constraints\NotNull;
2223
use Symfony\Component\Validator\ConstraintViolation;
@@ -40,12 +41,12 @@ public function testSupportNormalization(): void
4041
$this->assertTrue($normalizer->hasCacheableSupportsMethod());
4142
}
4243

43-
public function testNormalize(): void
44+
/**
45+
* @dataProvider nameConverterProvider
46+
*/
47+
public function testNormalize(object|null $nameConverter, array $expected): void
4448
{
45-
$nameConverterProphecy = $this->prophesize(NameConverterInterface::class);
46-
$normalizer = new ConstraintViolationListNormalizer(['severity', 'anotherField1'], $nameConverterProphecy->reveal());
47-
48-
$nameConverterProphecy->normalize(Argument::type('string'), null, Argument::type('string'))->will(fn ($args) => '_'.$args[0]);
49+
$normalizer = new ConstraintViolationListNormalizer(['severity', 'anotherField1'], $nameConverter);
4950

5051
// Note : we use NotNull constraint and not Constraint class because Constraint is abstract
5152
$constraint = new NotNull();
@@ -55,6 +56,11 @@ public function testNormalize(): void
5556
new ConstraintViolation('1', '2', [], '3', '4', '5'),
5657
]);
5758

59+
$this->assertSame($expected, $normalizer->normalize($list));
60+
}
61+
62+
public function nameConverterProvider(): iterable
63+
{
5864
$expected = [
5965
'type' => 'https://tools.ietf.org/html/rfc2616#section-10',
6066
'title' => 'An error occurred',
@@ -75,6 +81,35 @@ public function testNormalize(): void
7581
],
7682
],
7783
];
78-
$this->assertSame($expected, $normalizer->normalize($list));
84+
85+
$nameConverterProphecy = $this->prophesize(NameConverterInterface::class);
86+
$nameConverterProphecy->normalize(Argument::type('string'))->will(fn ($args) => '_'.$args[0]);
87+
yield [$nameConverterProphecy->reveal(), $expected];
88+
89+
$nameConverterProphecy = $this->prophesize(AdvancedNameConverterInterface::class);
90+
$nameConverterProphecy->normalize(Argument::type('string'), null, Argument::type('string'))->will(fn ($args) => '_'.$args[0]);
91+
yield [$nameConverterProphecy->reveal(), $expected];
92+
93+
$expected = [
94+
'type' => 'https://tools.ietf.org/html/rfc2616#section-10',
95+
'title' => 'An error occurred',
96+
'detail' => "d: a\n4: 1",
97+
'violations' => [
98+
[
99+
'propertyPath' => 'd',
100+
'message' => 'a',
101+
'code' => 'f24bdbad0becef97a6887238aa58221c',
102+
'payload' => [
103+
'severity' => 'warning',
104+
],
105+
],
106+
[
107+
'propertyPath' => '4',
108+
'message' => '1',
109+
'code' => null,
110+
],
111+
],
112+
];
113+
yield [null, $expected];
79114
}
80115
}

0 commit comments

Comments
 (0)