Skip to content

Commit 2aba779

Browse files
Merge branch '7.4' into 8.0
* 7.4: [TwigBridge] Fix Bootstrap 4 horizontal layout broken by form errors moved outside label [HttpKernel] Fix denormalization format detection for pre-parsed request data
2 parents ad50170 + 15e0982 commit 2aba779

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

Controller/ArgumentResolver/RequestPayloadValueResolver.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ private function mapRequestPayload(Request $request, ArgumentMetadata $argument,
223223
}
224224

225225
if (\is_array($data)) {
226-
return $this->serializer->denormalize($data, $type, 'form' === $format ? 'csv' : $format, $attribute->serializationContext + self::CONTEXT_DENORMALIZE + ('form' === $format ? ['filter_bool' => true] : []));
226+
return $this->serializer->denormalize($data, $type, self::hasNonStringScalar($data) ? $format : 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE + ('form' === $format ? ['filter_bool' => true] : []));
227227
}
228228

229229
if ('form' === $format) {
@@ -253,4 +253,21 @@ private function mapUploadedFile(Request $request, ArgumentMetadata $argument, M
253253

254254
return 'array' === $argument->getType() ? [] : null;
255255
}
256+
257+
private static function hasNonStringScalar(array $data): bool
258+
{
259+
$stack = [$data];
260+
261+
while ($stack) {
262+
foreach (array_pop($stack) as $v) {
263+
if (\is_array($v)) {
264+
$stack[] = $v;
265+
} elseif (!\is_string($v)) {
266+
return true;
267+
}
268+
}
269+
}
270+
271+
return false;
272+
}
256273
}

Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,32 @@ public function testMapRequestPayloadWithFormDataCoercesStringToBool()
10571057
$this->assertInstanceOf(FormPayloadWithBool::class, $payload);
10581058
$this->assertFalse($payload->active);
10591059
}
1060+
1061+
public function testMapRequestPayloadWithJsonContentTypeStringValuesCoercesToBool()
1062+
{
1063+
$serializer = new Serializer(
1064+
[new ObjectNormalizer(null, null, null, new ReflectionExtractor())],
1065+
[]
1066+
);
1067+
1068+
$resolver = new RequestPayloadValueResolver($serializer);
1069+
1070+
$argument = new ArgumentMetadata('payload', FormPayloadWithBool::class, false, false, null, false, [
1071+
MapRequestPayload::class => new MapRequestPayload(),
1072+
]);
1073+
$request = new Request([], ['active' => '0'], [], [], [], ['CONTENT_TYPE' => 'application/json']);
1074+
1075+
$kernel = $this->createStub(HttpKernelInterface::class);
1076+
$arguments = $resolver->resolve($request, $argument);
1077+
$event = new ControllerArgumentsEvent($kernel, static fn () => null, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);
1078+
1079+
$resolver->onKernelControllerArguments($event);
1080+
1081+
/** @var FormPayloadWithBool $payload */
1082+
[$payload] = $event->getArguments();
1083+
$this->assertInstanceOf(FormPayloadWithBool::class, $payload);
1084+
$this->assertFalse($payload->active);
1085+
}
10601086
}
10611087

10621088
class RequestPayload

0 commit comments

Comments
 (0)