Skip to content

Commit 44e5cd2

Browse files
authored
file upload use processor instead of controller (#1947)
1 parent e5f07a0 commit 44e5cd2

File tree

1 file changed

+42
-17
lines changed

1 file changed

+42
-17
lines changed

core/file-upload.md

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ before proceeding. It will help you get a grasp on how the bundle works, and why
1111
**Note**: Uploading files won't work in `PUT` or `PATCH` requests, you must use `POST` method to upload files.
1212
See [the related issue on Symfony](https://github.com/symfony/symfony/issues/9226) and [the related bug in PHP](https://bugs.php.net/bug.php?id=55815) talking about this behavior.
1313

14+
Previously to API Platform 3.3, file upload was using controllers that needs:
15+
16+
```yaml
17+
api_platform:
18+
use_symfony_listeners: true
19+
```
20+
21+
Since 3.3, we recommend to use a Processor, note that you need to enable the multipart format globally:
22+
23+
```yaml
24+
api_platform:
25+
use_symfony_listeners: false
26+
formats:
27+
multipart: ['multipart/form-data']
28+
jsonld: ['application/ld+json']
29+
```
30+
1431
## Installing VichUploaderBundle
1532
1633
Install the bundle with the help of Composer:
@@ -63,7 +80,7 @@ use ApiPlatform\Metadata\Get;
6380
use ApiPlatform\Metadata\GetCollection;
6481
use ApiPlatform\Metadata\Post;
6582
use ApiPlatform\OpenApi\Model;
66-
use App\Controller\CreateMediaObjectAction;
83+
use App\State\SaveMediaObject;
6784
use Doctrine\ORM\Mapping as ORM;
6885
use Symfony\Component\HttpFoundation\File\File;
6986
use Symfony\Component\Serializer\Annotation\Groups;
@@ -75,12 +92,13 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich;
7592
#[ApiResource(
7693
normalizationContext: ['groups' => ['media_object:read']],
7794
types: ['https://schema.org/MediaObject'],
95+
outputFormats: ['jsonld' => ['application/ld+json']],
7896
operations: [
7997
new Get(),
8098
new GetCollection(),
8199
new Post(
82100
inputFormats: ['multipart' => ['multipart/form-data']],
83-
controller: CreateMediaObjectAction::class,
101+
processor: SaveMediaObject::class,
84102
deserialize: false,
85103
validationContext: ['groups' => ['Default', 'media_object_create']],
86104
openapi: new Model\Operation(
@@ -127,37 +145,41 @@ class MediaObject
127145
```
128146
Note: From V3.3 onwards, `'multipart/form-data'` must either be including in the global API-Platform config, either in `formats` or `defaults->inputFormats`, or defined as an `inputFormats` parameter on an operation by operation basis.
129147

130-
### Creating the Controller
148+
### Creating the Processor
131149

132-
At this point, the entity is configured, but we still need to write the action
150+
At this point, the entity is configured, but we still need to write the processor
133151
that handles the file upload.
134152

135153
```php
136154
<?php
137-
// api/src/Controller/CreateMediaObjectAction.php
155+
// api/src/State/SaveMediaObject.php
138156
139-
namespace App\Controller;
157+
namespace App\State;
140158
159+
use ApiPlatform\Metadata\Operation;
160+
use ApiPlatform\State\ProcessorInterface;
141161
use App\Entity\MediaObject;
142-
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
143-
use Symfony\Component\HttpFoundation\Request;
144-
use Symfony\Component\HttpKernel\Attribute\AsController;
162+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
145163
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
164+
use Vich\UploaderBundle\Storage\StorageInterface;
146165
147-
#[AsController]
148-
final class CreateMediaObjectAction extends AbstractController
166+
final class SaveMediaObject implements ProcessorInterface
149167
{
150-
public function __invoke(Request $request): MediaObject
168+
public function __construct(
169+
#[Autowire('@api_platform.doctrine.orm.state.persist_processor')] private readonly ProcessorInterface $processor,
170+
private readonly StorageInterface $storage
171+
) {}
172+
173+
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
151174
{
152-
$uploadedFile = $request->files->get('file');
175+
$uploadedFile = $context['request']->files->get('file');
153176
if (!$uploadedFile) {
154177
throw new BadRequestHttpException('"file" is required');
155178
}
156179
157180
$mediaObject = new MediaObject();
158181
$mediaObject->file = $uploadedFile;
159-
160-
return $mediaObject;
182+
return $this->processor->process($mediaObject, $operation, $uriVariables, $context);
161183
}
162184
}
163185
```
@@ -185,7 +207,7 @@ class MediaObjectNormalizer implements NormalizerInterface
185207
private const ALREADY_CALLED = 'MEDIA_OBJECT_NORMALIZER_ALREADY_CALLED';
186208
187209
public function __construct(
188-
#[Autowire(service: 'serializer.normalizer.object')]
210+
#[Autowire(service: 'api_platform.jsonld.normalizer.item')]
189211
private readonly NormalizerInterface $normalizer,
190212
private readonly StorageInterface $storage
191213
) {
@@ -385,7 +407,10 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich;
385407
types: ['https://schema.org/Book'],
386408
operations: [
387409
new GetCollection(),
388-
new Post(inputFormats: ['multipart' => ['multipart/form-data']])
410+
new Post(
411+
outputFormats: ['jsonld' => ['application/ld+json']],
412+
inputFormats: ['multipart' => ['multipart/form-data']]
413+
)
389414
]
390415
)]
391416
class Book

0 commit comments

Comments
 (0)