Skip to content

Commit 9f7c899

Browse files
authored
fix(File upload): correct steps order (#2177)
Correct configuration steps order to allow to make a request `POST /media_objects`. Resolves: api-platform/api-platform#2713
1 parent a29b178 commit 9f7c899

File tree

1 file changed

+79
-81
lines changed

1 file changed

+79
-81
lines changed

symfony/file-upload.md

Lines changed: 79 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,85 @@ class MediaObjectNormalizer implements NormalizerInterface
189189
190190
```
191191

192+
### Handling the Multipart Deserialization
193+
194+
By default, Symfony is not able to decode `multipart/form-data`-encoded data.
195+
We need to create our own decoder to do it:
196+
197+
```php
198+
<?php
199+
// api/src/Encoder/MultipartDecoder.php
200+
201+
namespace App\Encoder;
202+
203+
use Symfony\Component\HttpFoundation\RequestStack;
204+
use Symfony\Component\Serializer\Encoder\DecoderInterface;
205+
206+
final class MultipartDecoder implements DecoderInterface
207+
{
208+
public const FORMAT = 'multipart';
209+
210+
public function __construct(private readonly RequestStack $requestStack)
211+
{
212+
}
213+
214+
public function decode(string $data, string $format, array $context = []): ?array
215+
{
216+
$request = $this->requestStack->getCurrentRequest();
217+
218+
if (!$request) {
219+
return null;
220+
}
221+
222+
return array_map(static function (string $element) {
223+
// Multipart form values will be encoded in JSON.
224+
return json_decode($element, true, flags: \JSON_THROW_ON_ERROR);
225+
}, $request->request->all()) + $request->files->all();
226+
}
227+
228+
public function supportsDecoding(string $format): bool
229+
{
230+
return self::FORMAT === $format;
231+
}
232+
}
233+
```
234+
235+
If you're not using `autowiring` and `autoconfiguring`, don't forget to register the service and tag it as `serializer.encoder`.
236+
237+
We also need to make sure the field containing the uploaded file is not denormalized:
238+
239+
```php
240+
<?php
241+
// api/src/Serializer/UploadedFileDenormalizer.php
242+
243+
namespace App\Serializer;
244+
245+
use Symfony\Component\HttpFoundation\File\File;
246+
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
247+
248+
final class UploadedFileDenormalizer implements DenormalizerInterface
249+
{
250+
public function denormalize($data, string $type, string $format = null, array $context = []): File
251+
{
252+
return $data;
253+
}
254+
255+
public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
256+
{
257+
return $data instanceof File;
258+
}
259+
260+
public function getSupportedTypes(?string $format): array
261+
{
262+
return [
263+
File::class => true,
264+
];
265+
}
266+
}
267+
```
268+
269+
If you're not using `autowiring` and `autoconfiguring`, don't forget to register the service and tag it as `serializer.normalizer`.
270+
192271
### Making a Request to the `/media_objects` Endpoint
193272

194273
Your `/media_objects` endpoint is now ready to receive a `POST` request with a
@@ -409,84 +488,3 @@ class Book
409488
// ...
410489
}
411490
```
412-
413-
### Handling the Multipart Deserialization
414-
415-
By default, Symfony is not able to decode `multipart/form-data`-encoded data.
416-
We need to create our own decoder to do it:
417-
418-
```php
419-
<?php
420-
// api/src/Encoder/MultipartDecoder.php
421-
422-
namespace App\Encoder;
423-
424-
use Symfony\Component\HttpFoundation\RequestStack;
425-
use Symfony\Component\Serializer\Encoder\DecoderInterface;
426-
427-
final class MultipartDecoder implements DecoderInterface
428-
{
429-
public const FORMAT = 'multipart';
430-
431-
public function __construct(private readonly RequestStack $requestStack)
432-
{
433-
}
434-
435-
public function decode(string $data, string $format, array $context = []): ?array
436-
{
437-
$request = $this->requestStack->getCurrentRequest();
438-
439-
if (!$request) {
440-
return null;
441-
}
442-
443-
return array_map(static function (string $element) {
444-
// Multipart form values will be encoded in JSON.
445-
return json_decode($element, true, flags: \JSON_THROW_ON_ERROR);
446-
}, $request->request->all()) + $request->files->all();
447-
}
448-
449-
public function supportsDecoding(string $format): bool
450-
{
451-
return self::FORMAT === $format;
452-
}
453-
}
454-
```
455-
456-
If you're not using `autowiring` and `autoconfiguring`, don't forget to register the service and tag it as `serializer.encoder`.
457-
458-
We also need to make sure the field containing the uploaded file is not denormalized:
459-
460-
```php
461-
<?php
462-
// api/src/Serializer/UploadedFileDenormalizer.php
463-
464-
namespace App\Serializer;
465-
466-
use Symfony\Component\HttpFoundation\File\File;
467-
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
468-
469-
final class UploadedFileDenormalizer implements DenormalizerInterface
470-
{
471-
public function denormalize($data, string $type, string $format = null, array $context = []): File
472-
{
473-
return $data;
474-
}
475-
476-
public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
477-
{
478-
return $data instanceof File;
479-
}
480-
481-
public function getSupportedTypes(?string $format): array
482-
{
483-
return [
484-
File::class => true,
485-
];
486-
}
487-
}
488-
```
489-
490-
If you're not using `autowiring` and `autoconfiguring`, don't forget to register the service and tag it as `serializer.normalizer`.
491-
492-
For resolving the file URL, you can use a custom normalizer, like shown in [the previous example](#resolving-the-file-url).

0 commit comments

Comments
 (0)