8000 Move logic for PartialDenormalizationException back to Serializer · Nyholm/symfony@bbf3011 · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit bbf3011

Browse files
committed
Move logic for PartialDenormalizationException back to Serializer
See symfony#52992
1 parent 4977937 commit bbf3011

File tree

4 files changed

+104
-24
lines changed

4 files changed

+104
-24
lines changed

src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,33 @@ public function testQueryNullPayloadAndNotDefaultOrNullableArgument()
201201
}
202202
}
203203

204+
/**
205+
* @group legacy
206+
*/
207+
public function testWithoutValidatorAndCouldNotDenormalizeWithLegacySerializer()
208+
{
209+
$content = '{"price": 50, "title": ["not a string"]}';
210+
$serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);
211+
212+
$resolver = new RequestPayloadValueResolver($serializer);
213+
214+
$argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [
215+
MapRequestPayload::class => new MapRequestPayload(),
216+
]);
217+
$request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);
218+
219+
$kernel = $this->createMock(HttpKernelInterface::class);
220+
$arguments = $resolver->resolve($request, $argument);
221+
$event = new ControllerArgumentsEvent($kernel, function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);
222+
223+
try {
224+
$resolver->onKernelControllerArguments($event);
225+
$this->fail(sprintf('Expected "%s" to be thrown.', HttpException::class));
226+
} catch (HttpException $e) {
227+
$this->assertInstanceOf(PartialDenormalizationException::class, $e->getPrevious());
228+
}
229+
}
230+
204231
public function testWithoutValidatorAndCouldNotDenormalize()
205232
{
206233
$content = '{"price": 50, "title": ["not a string"]}';

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

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -105,30 +105,6 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
105105
throw new NotNormalizableValueException(sprintf('Could not denormalize object of type "%s", no supporting normalizer found.', $type));
106106
}
107107

108-
if (isset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])) {
109-
unset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]);
110-
$context['not_normalizable_value_exceptions'] = [];
111-
$errors = &$context['not_normalizable_value_exceptions'];
112-
$denormalized = $denormalizer->denormalize($data, $type, $format, $context);
113-
114-
if ($errors) {
115-
// merge errors so that one path has only one error
116-
$uniqueErrors = [];
117-
foreach ($errors as $error) {
118-
if (null === $error->getPath()) {
119-
$uniqueErrors[] = $error;
120-
continue;
121-
}
122-
123-
$uniqueErrors[$error->getPath()] = $uniqueErrors[$error->getPath()] ?? $error;
124-
}
125-
126-
throw new PartialDenormalizationException($denormalized, array_values($uniqueErrors));
127-
}
128-
129-
return $denormalized;
130-
}
131-
132108
return $denormalizer->denormalize($data, $type, $format, $context);
133109
}
134110

src/Symfony/Component/Serializer/Serializer.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Serializer\Encoder\EncoderInterface;
2020
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
2121
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
22+
use Symfony\Component\Serializer\Exception\PartialDenormalizationException;
2223
use Symfony\Component\Serializer\Exception\UnsupportedFormatException;
2324
use Symfony\Component\Serializer\Normalizer\ChainDenormalizer;
2425
use Symfony\Component\Serializer\Normalizer\ChainNormalizer;
@@ -167,9 +168,34 @@ public function normalize(mixed $data, string $format = null, array $context = [
167168

168169
/**
169170
* @throws NotNormalizableValueException
171+
* @throws PartialDenormalizationException Occurs when one or more properties of $type fails to denormalize
170172
*/
171173
public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed
172174
{
175+
if (isset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS])) {
176+
unset($context[DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS]);
177+
$context['not_normalizable_value_exceptions'] = [];
178+
$errors = &$context['not_normalizable_value_exceptions'];
179+
$denormalized = $this->denormalizer->denormalize($data, $type, $format, $context);
180+
181+
if ($errors) {
182+
// merge errors so that one path has only one error
183+
$uniqueErrors = [];
184+
foreach ($errors as $error) {
185+
if (null === $error->getPath()) {
186+
$uniqueErrors[] = $error;
187+
continue;
188+
}
189+
190+
$uniqueErrors[$error->getPath()] = $uniqueErrors[$error->getPath()] ?? $error;
191+
}
192+
193+
throw new PartialDenormalizationException($denormalized, array_values($uniqueErrors));
194+
}
195+
196+
return $denormalized;
197+
}
198+
173199
return $this->denormalizer->denormalize($data, $type, $format, $context);
174200
}
175201

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,57 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa
12661266
$this->assertSame($expected, $exceptionsAsArray);
12671267
}
12681268

1269+
/**
1270+
* @group legacy
1271+
* If we use the Symfony 7.0 way to create a Serializer, will we still get a PartialDenormalizationException?
1272+
*/
1273+
public function testDenormalizationCollectErrorsWithLegacy()
1274+
{
1275+
$json = '{"string": "some string", "bool": "bool", "int": true}';
1276+
1277+
$extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]);
1278+
$serializer = new Serializer(
1279+
[new ObjectNormalizer(null, null, null, $extractor)],
1280+
['json' => new JsonEncoder()],
1281+
);
1282+
1283+
try {
1284+
$serializer->deserialize($json, WithTypedConstructor::class, 'json', [
1285+
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
1286+
]);
1287+
1288+
$this->fail();
1289+
} catch (\Throwable $th) {
1290+
$this->assertInstanceOf(PartialDenormalizationException::class, $th);
1291+
}
1292+
}
1293+
1294+
/**
1295+
* Make sure throwing PartialDenormalizationException is a feature of the serializer, not the ChainNormalizer.
1296+
*/
1297+
public function testDenormalizationCollectErrorsNoChainDenormalizer()
1298+
{
1299+
$json = '{"string": "some string", "bool": "bool", "int": true}';
1300+
1301+
$extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]);
1302+
$serializer = new Serializer(
1303+
[],
1304+
['json' => new JsonEncoder()],
1305+
new ObjectNormalizer(null, null, null, $extractor),
1306+
new ObjectNormalizer(null, null, null, $extractor)
1307+
);
1308+
1309+
try {
1310+
$serializer->deserialize($json, WithTypedConstructor::class, 'json', [
1311+
DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true,
1312+
]);
1313+
1314+
$this->fail();
1315+
} catch (\Throwable $th) {
1316+
$this->assertInstanceOf(PartialDenormalizationException::class, $th);
1317+
}
1318+
}
1319+
12691320
public function testCollectDenormalizationErrorsWithInvalidConstructorTypes()
12701321
{
12711322
$json = '{"string": "some string", "bool": "bool", "int": true}';

0 commit comments

Comments
 (0)
0