Description
Description
Currently, RequestPayloadValueResolver
only deserializes $request->request->all()
into the target class. This behavior requires uploaded files to be mapped separately using another argument with the #[MapUploadedFile]
attribute:
public function __invoke(
#[MapRequestPayload] MyRequest $myRequest,
#[MapUploadedFile] UploadedFile $myFile
) {
}
This separation forces developers to manually split file handling from the main request payload, even when the uploaded files conceptually belong to the same data structure.
It would be much more ergonomic and intuitive if the uploaded file could be included directly within the request DTO. For example:
class MyRequest {
public ?string $foo = null;
public ?UploadedFile $file = null;
}
This would allow the controller signature to be simplified to:
public function __invoke(#[MapRequestPayload] MyRequest $myRequest) {
}
While it might be possible to work around this with custom denormalizers (not yet tested), I believe this use case is common enough to warrant native support in Symfony core.
Proposal
Extend RequestPayloadValueResolver
(and possibly the serializer) to support injecting UploadedFile
instances into DTOs during deserialization, allowing them to be mapped directly as properties.
Proposal requirements
- It should allow to add validation constraints to files as well.
- It should handle multi-level data like Symfony Form does.
Benefits
- Cleaner controller method signatures
- Better encapsulation of request data
- Less boilerplate and manual mapping
- More aligned with how form handling works
Looking forward to hearing your thoughts and if this could be a candidate for inclusion in a future Symfony release.
Something to consider
Allowing UploadedFile
to be included in MapRequestPayload
could set a precedent for supporting other request sources, such as query strings and headers. If that happens, we might need to define a clear priority order for how data from different parts of the request (body, query, headers, files) should be merged.