Skip to content

Commit d5ab738

Browse files
committed
feature #18336 [HttpKernel] Add #[MapQueryParameter], #[MapQueryString] and #[MapRequestPayload] (alexandre-daubois)
This PR was merged into the 6.3 branch. Discussion ---------- [HttpKernel] Add `#[MapQueryParameter]`, `#[MapQueryString]` and `#[MapRequestPayload]` Back at it to fulfill the `Attributes Overview` document 😄 Resolves #18216 Resolves #18206 Commits ------- cf9788c [HttpKernel] Add `#[MapQueryParameter]`, `#[MapQueryString]` and `#[MapRequestPayload]`
2 parents 4d2a0e4 + cf9788c commit d5ab738

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

controller.rst

+152
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,157 @@ object. To access it in your controller, add it as an argument and
336336
:ref:`Keep reading <request-object-info>` for more information about using the
337337
Request object.
338338

339+
.. _controller_map-request:
340+
341+
Automatic Mapping Of The Request
342+
--------------------------------
343+
344+
It is possible to automatically map request's payload and/or query parameters to
345+
your controller's action arguments with attributes.
346+
347+
Mapping Query Parameters Individually
348+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
349+
350+
Let's say a user sends you a request with the following query string:
351+
``https://example.com/dashboard?firstName=John&lastName=Smith&age=27``.
352+
Thanks to the :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter`
353+
attribute, arguments of your controller's action can be automatically fulfilled::
354+
355+
use Symfony\Component\HttpFoundation\Response;
356+
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
357+
358+
// ...
359+
360+
public function dashboard(
361+
#[MapQueryParameter] string $firstName,
362+
#[MapQueryParameter] string $lastName,
363+
#[MapQueryParameter] int $age,
364+
): Response
365+
{
366+
// ...
367+
}
368+
369+
``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the
370+
`Validate Filters`_ constants defined in PHP::
371+
372+
use Symfony\Component\HttpFoundation\Response;
373+
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
374+
375+
// ...
376+
377+
public function dashboard(
378+
#[MapQueryParameter(filter: \FILTER_VALIDATE_REGEXP, options: ['regexp' => '/^\w++$/'])] string $firstName,
379+
#[MapQueryParameter] string $lastName,
380+
#[MapQueryParameter(filter: \FILTER_VALIDATE_INT)] int $age,
381+
): Response
382+
{
383+
// ...
384+
}
385+
386+
.. versionadded:: 6.3
387+
388+
The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter` attribute
389+
was introduced in Symfony 6.3.
390+
391+
Mapping The Whole Query String
392+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
393+
394+
Another possibility is to map the entire query string into an object that will hold
395+
available query parameters. Let's say you declare the following DTO with its
396+
optional validation constraints::
397+
398+
namespace App\Model;
399+
400+
use Symfony\Component\Validator\Constraints as Assert;
401+
402+
class UserDTO
403+
{
404+
public function __construct(
405+
#[Assert\NotBlank]
406+
public string $firstName,
407+
408+
#[Assert\NotBlank]
409+
public string $lastName,
410+
411+
#[Assert\GreaterThan(18)]
412+
public int $age,
413+
) {
414+
}
415+
}
416+
417+
You can then use the :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString`
418+
attribute in your controller::
419+
420+
use App\Model\UserDto;
421+
use Symfony\Component\HttpFoundation\Response;
422+
use Symfony\Component\HttpKernel\Attribute\MapQueryString;
423+
424+
// ...
425+
426+
public function dashboard(
427+
#[MapQueryString] UserDTO $userDto
428+
): Response
429+
{
430+
// ...
431+
}
432+
433+
.. versionadded:: 6.3
434+
435+
The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString` attribute
436+
was introduced in Symfony 6.3.
437+
438+
Mapping Request Payload
439+
~~~~~~~~~~~~~~~~~~~~~~~
440+
441+
When creating an API and dealing with other HTTP methods than ``GET`` (like
442+
``POST`` or ``PUT``), user's data are not stored in the query string
443+
but directly in the request payload, like this:
444+
445+
.. code-block:: json
446+
447+
{
448+
"firstName": "John",
449+
"lastName": "Smith",
450+
"age": 28
451+
}
452+
453+
In this case, it is also possible to directly map this payload to your DTO by
454+
using the :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload`
455+
attribute::
456+
457+
use App\Model\UserDto;
458+
use Symfony\Component\HttpFoundation\Response;
459+
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
460+
461+
// ...
462+
463+
public function dashboard(
464+
#[MapRequestPayload] UserDTO $userDto
465+
): Response
466+
{
467+
// ...
468+
}
469+
470+
This attribute allows you to customize the serialization context as well
471+
as the class responsible of doing the mapping between the request and
472+
your DTO::
473+
474+
public function dashboard(
475+
#[MapRequestPayload(
476+
serializationContext: ['...'],
477+
resolver: App\Resolver\UserDtoResolver
478+
)]
479+
UserDTO $userDto
480+
): Response
481+
{
482+
// ...
483+
}
484+
485+
.. versionadded:: 6.3
486+
487+
The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload` attribute
488+
was introduced in Symfony 6.3.
489+
339490
Managing the Session
340491
--------------------
341492

@@ -604,3 +755,4 @@ Learn more about Controllers
604755
.. _`Early hints`: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103
605756
.. _`SAPI`: https://www.php.net/manual/en/function.php-sapi-name.php
606757
.. _`FrankenPHP`: https://frankenphp.dev
758+
.. _`Validate Filters`: https://www.php.net/manual/en/filter.filters.validate.php

reference/attributes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ HttpKernel
5757
* :class:`Symfony\\Component\\HttpKernel\\Attribute\\AsPinnedValueResolver`
5858
* :ref:`Cache <http-cache-expiration-intro>`
5959
* :ref:`MapDateTime <functionality-shipped-with-the-httpkernel>`
60+
* :ref:`MapQueryParameter <controller_map-request>`
61+
* :ref:`MapQueryString <controller_map-request>`
62+
* :ref:`MapRequestPayload <controller_map-request>`
6063
* :class:`Symfony\\Component\\HttpKernel\\Attribute\\ValueResolver`
6164
* :ref:`WithHttpStatus <framework_exceptions>`
6265
* :ref:`WithLogLevel <framework_exceptions>`

0 commit comments

Comments
 (0)