Skip to content

Commit c1daf3c

Browse files
Merge branch '6.4' into 7.4
* 6.4: [DependencyInjection] Update Container PHPDoc behaviors count when a service does not exist [Validator] Review translations for Portuguese (pt_BR) [HttpKernel] Handle invalid backed-enum values gracefully in RequestPayloadValueResolver
2 parents 93900fb + 714af62 commit c1daf3c

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

Controller/ArgumentResolver/RequestPayloadValueResolver.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\HttpKernel\Exception\NearMissValueResolverException;
2626
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
2727
use Symfony\Component\HttpKernel\KernelEvents;
28+
use Symfony\Component\Serializer\Exception\InvalidArgumentException as SerializerInvalidArgumentException;
2829
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
2930
use Symfony\Component\Serializer\Exception\PartialDenormalizationException;
3031
use Symfony\Component\Serializer\Exception\UnexpectedPropertyException;
@@ -140,6 +141,9 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo
140141
$violations->add(new ConstraintViolation($message, $template, $parameters, null, $error->getPath(), null));
141142
}
142143
$payload = $e->getData();
144+
} catch (SerializerInvalidArgumentException $e) {
145+
$violations->add(new ConstraintViolation($e->getMessage(), $e->getMessage(), [], null, '', null));
146+
$payload = null;
143147
}
144148

145149
if (null !== $payload && !\count($violations)) {
@@ -158,6 +162,8 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo
158162
$payload = $payloadMapper($request, $argument->metadata, $argument);
159163
} catch (PartialDenormalizationException $e) {
160164
throw HttpException::fromStatusCode($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), $e->getErrors())), $e);
165+
} catch (SerializerInvalidArgumentException $e) {
166+
throw HttpException::fromStatusCode($validationFailedCode, $e->getMessage(), $e);
161167
}
162168
}
163169

Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
3131
use Symfony\Component\Serializer\Exception\PartialDenormalizationException;
3232
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
33+
use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
3334
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
3435
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
3536
use Symfony\Component\Serializer\Serializer;
@@ -284,6 +285,37 @@ public function testValidationNotPassed()
284285
}
285286
}
286287

288+
public function testValidationFailedOnInvalidBackedEnum()
289+
{
290+
$content = '{"method": "INVALID"}';
291+
$serializer = new Serializer([new BackedEnumNormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()]);
292+
293+
$validator = $this->createMock(ValidatorInterface::class);
294+
$validator->expects($this->never())
295+
->method('validate');
296+
297+
$resolver = new RequestPayloadValueResolver($serializer, $validator);
298+
299+
$argument = new ArgumentMetadata('invalid', RequestPayloadWithBackedEnum::class, false, false, null, false, [
300+
MapRequestPayload::class => new MapRequestPayload(),
301+
]);
302+
$request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => 'application/json'], content: $content);
303+
304+
$kernel = $this->createStub(HttpKernelInterface::class);
305+
$arguments = $resolver->resolve($request, $argument);
306+
$event = new ControllerArgumentsEvent($kernel, function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);
307+
308+
try {
309+
$resolver->onKernelControllerArguments($event);
310+
$this->fail(\sprintf('Expected "%s" to be thrown.', HttpException::class));
311+
} catch (HttpException $e) {
312+
$validationFailedException = $e->getPrevious();
313+
$this->assertSame(422, $e->getStatusCode());
314+
$this->assertInstanceOf(ValidationFailedException::class, $validationFailedException);
315+
$this->assertSame('The data must belong to a backed enumeration of type Symfony\\Component\\HttpKernel\\Tests\\Controller\\ArgumentResolver\\RequestMethod', $validationFailedException->getViolations()[0]->getMessage());
316+
}
317+
}
318+
287319
public function testValidationNotPerformedWhenPartialDenormalizationReturnsViolation()
288320
{
289321
$content = '{"password": "abc"}';
@@ -1014,6 +1046,19 @@ public function getPassword(): string
10141046
}
10151047
}
10161048

1049+
class RequestPayloadWithBackedEnum
1050+
{
1051+
public function __construct(public readonly RequestMethod $method)
1052+
{
1053+
}
1054+
}
1055+
1056+
enum RequestMethod: string
1057+
{
1058+
case GET = 'GET';
1059+
case POST = 'POST';
1060+
}
1061+
10171062
class ObjectWithBoolArgument
10181063
{
10191064
public function __construct(public readonly ?bool $value = null)

0 commit comments

Comments
 (0)