Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f366d35

Browse filesBrowse files
author
Rene
committed
add support to multiple files
1 parent ea50c48 commit f366d35
Copy full SHA for f366d35

File tree

3 files changed

+46
-16
lines changed
Filter options

3 files changed

+46
-16
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ApiAttributesTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ApiAttributesTest.php
+31-2Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
2020
use Symfony\Component\HttpKernel\Attribute\MapUploadedFile;
2121
use Symfony\Component\Validator\Constraints as Assert;
22-
use Symfony\Component\Validator\Constraints\File;
2322

2423
class ApiAttributesTest extends AbstractWebTestCase
2524
{
@@ -460,6 +459,31 @@ public function testMapUploadedFileWithConstraints()
460459
self::assertSame(400, $response->getStatusCode());
461460
self::assertJsonStringEqualsJsonString($content, $response->getContent());
462461
}
462+
463+
public function testMapUploadedFileWithMultipleFiles()
464+
{
465+
$client = self::createClient(['test_case' => 'ApiAttributesTest']);
466+
467+
$client->request(
468+
'POST',
469+
'/map-uploaded-file-with-multiple',
470+
[],
471+
[
472+
'files' => [
473+
new UploadedFile(__DIR__.'/Fixtures/file-small.txt', 'file-small.txt', 'text/plain'),
474+
new UploadedFile(__DIR__.'/Fixtures/file-big.txt', 'file-small.txt', 'text/plain'),
475+
],
476+
],
477+
['HTTP_CONTENT_TYPE' => 'multipart/form-data'],
478+
);
479+
$response = $client->getResponse();
480+
481+
self::assertTrue($response->isSuccessful());
482+
self::assertJsonStringEqualsJsonString(
483+
json_encode([2, UploadedFile::class, UploadedFile::class], \JSON_THROW_ON_ERROR),
484+
$response->getContent()
485+
);
486+
}
463487
}
464488

465489
class WithMapQueryStringController
@@ -516,10 +540,15 @@ public function nullable(#[MapUploadedFile] ?UploadedFile $file): Response
516540
return new Response($file?->getContent());
517541
}
518542

519-
public function withConstraints(#[MapUploadedFile(constraints: new File(maxSize: 50))] ?UploadedFile $file): Response
543+
public function withConstraints(#[MapUploadedFile(constraints: new Assert\File(maxSize: 50))] ?UploadedFile $file): Response
520544
{
521545
return new Response($file->getContent());
522546
}
547+
548+
public function withMultipleFiles(#[MapUploadedFile(constraints: new Assert\All([new Assert\File(maxSize: 100)]))] ?array $files): JsonResponse
549+
{
550+
return new JsonResponse([\count($files), \get_class($files[0]), \get_class($files[1])]);
551+
}
523552
}
524553

525554
class QueryString

‎src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ApiAttributesTest/routing.yml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ApiAttributesTest/routing.yml
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ map_uploaded_file_nullable:
2121
map_uploaded_file_constraints:
2222
path: /map-uploaded-file-with-constraints
2323
controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\WithMapUploadedFileController::withConstraints
24+
25+
map_uploaded_file_multiple:
26+
path: /map-uploaded-file-with-multiple
27+
controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\WithMapUploadedFileController::withMultipleFiles

‎src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php
+11-14Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable
6666
continue;
6767
}
6868

69-
if (!$type = $argument->getType()) {
69+
if (!$argument->getType()) {
7070
throw new \LogicException(sprintf('Could not resolve the "$%s" controller argument: argument should be typed.', $argument->getName()));
7171
}
7272

7373
try {
74-
$payload = $this->$payloadMapper($request, $type, $attributes[0], $argument);
74+
$payload = $this->$payloadMapper($request, $argument, $attributes[0]);
7575
} catch (PartialDenormalizationException $e) {
7676
throw new HttpException($validationFailedCode, implode("\n", array_map(static fn (NotNormalizableValueException $e) => $e->getMessage(), $e->getErrors())), $e);
7777
}
@@ -89,19 +89,19 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable
8989
return [];
9090
}
9191

92-
private function mapQueryString(Request $request, string $type, MapQueryString $attribute): ?object
92+
private function mapQueryString(Request $request, ArgumentMetadata $argument, MapQueryString $attribute): ?object
9393
{
9494
if (!$data = $request->query->all()) {
9595
return null;
9696
}
9797

98-
return $this->serializer->denormalize($data, $type, self::DEFAULT_FORMAT, self::CONTEXT_DENORMALIZE + $attribute->context);
98+
return $this->serializer->denormalize($data, $argument->getType(), self::DEFAULT_FORMAT, self::CONTEXT_DENORMALIZE + $attribute->context);
9999
}
100100

101-
private function mapRequestPayload(Request $request, string $type, MapRequestPayload $attribute): ?object
101+
private function mapRequestPayload(Request $request, ArgumentMetadata $argument, MapRequestPayload $attribute): ?object
102102
{
103103
if ($data = $request->request->all()) {
104-
return $this->serializer->denormalize($data, $type, self::DEFAULT_FORMAT, self::CONTEXT_DENORMALIZE + $attribute->context);
104+
return $this->serializer->denormalize($data, $argument->getType(), self::DEFAULT_FORMAT, self::CONTEXT_DENORMALIZE + $attribute->context);
105105
}
106106

107107
if ('' === $data = $request->getContent()) {
@@ -111,24 +111,21 @@ private function mapRequestPayload(Request $request, string $type, MapRequestPay
111111
$format = $request->getRequestFormat(self::DEFAULT_FORMAT);
112112

113113
try {
114-
return $this->serializer->deserialize($data, $type, $format, self::CONTEXT_DESERIALIZE + $attribute->context);
114+
return $this->serializer->deserialize($data, $argument->getType(), $format, self::CONTEXT_DESERIALIZE + $attribute->context);
115115
} catch (UnsupportedFormatException $e) {
116116
throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, sprintf('Unsupported format: "%s".', $format), $e);
117117
} catch (NotEncodableValueException $e) {
118118
throw new HttpException(Response::HTTP_BAD_REQUEST, sprintf('Request payload contains not valid "%s".', $format), $e);
119119
}
120120
}
121121

122-
private function mapUploadedFile(Request $request, string $type, MapUploadedFile $attribute, ArgumentMetadata $argument): ?UploadedFile
122+
private function mapUploadedFile(Request $request, ArgumentMetadata $argument, MapUploadedFile $attribute): UploadedFile|array|null
123123
{
124-
if (UploadedFile::class !== $type) {
125-
throw new \InvalidArgumentException(sprintf('Unexpected type "%s". Expected "%s".', $type, UploadedFile::class));
126-
}
127-
128124
$name = $attribute->name ?? $argument->getName();
129125
$file = $request->files->get($name);
130-
if (!$file instanceof UploadedFile) {
131-
return null;
126+
$type = get_debug_type($file);
127+
if ($type !== $argument->getType() && !('null' === $type && $argument->isNullable())) {
128+
throw new \InvalidArgumentException(sprintf('Unexpected type "%s". Expected "%s".', $type, $argument->getType()));
132129
}
133130

134131
return $file;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.