Skip to content

[HttpKernel] Add #[MapQueryParameter], #[MapQueryString] and #[MapRequestPayload] #18336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions controller.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,157 @@ object. To access it in your controller, add it as an argument and
:ref:`Keep reading <request-object-info>` for more information about using the
Request object.

.. _controller_map-request:

Automatic Mapping Of The Request
--------------------------------

It is possible to automatically map request's payload and/or query parameters to
your controller's action arguments with attributes.

Mapping Query Parameters Individually
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Let's say a user sends you a request with the following query string:
``https://example.com/dashboard?firstName=John&lastName=Smith&age=27``.
Thanks to the :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter`
attribute, arguments of your controller's action can be automatically fulfilled::

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;

// ...

public function dashboard(
#[MapQueryParameter] string $firstName,
#[MapQueryParameter] string $lastName,
#[MapQueryParameter] int $age,
): Response
{
// ...
}

``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the
`Validate Filters`_ constants defined in PHP::

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;

// ...

public function dashboard(
#[MapQueryParameter(filter: \FILTER_VALIDATE_REGEXP, options: ['regexp' => '/^\w++$/'])] string $firstName,
#[MapQueryParameter] string $lastName,
#[MapQueryParameter(filter: \FILTER_VALIDATE_INT)] int $age,
): Response
{
// ...
}

.. versionadded:: 6.3

The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter` attribute
was introduced in Symfony 6.3.

Mapping The Whole Query String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Another possibility is to map the entire query string into an object that will hold
available query parameters. Let's say you declare the following DTO with its
optional validation constraints::

namespace App\Model;

use Symfony\Component\Validator\Constraints as Assert;

class UserDTO
{
public function __construct(
#[Assert\NotBlank]
public string $firstName,

#[Assert\NotBlank]
public string $lastName,

#[Assert\GreaterThan(18)]
public int $age,
) {
}
}

You can then use the :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString`
attribute in your controller::

use App\Model\UserDto;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapQueryString;

// ...

public function dashboard(
#[MapQueryString] UserDTO $userDto
): Response
{
// ...
}

.. versionadded:: 6.3

The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString` attribute
was introduced in Symfony 6.3.

Mapping Request Payload
~~~~~~~~~~~~~~~~~~~~~~~

When creating an API and dealing with other HTTP methods than ``GET`` (like
``POST`` or ``PUT``), user's data are not stored in the query string
but directly in the request payload, like this:

.. code-block:: json

{
"firstName": "John",
"lastName": "Smith",
"age": 28
}

In this case, it is also possible to directly map this payload to your DTO by
using the :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload`
attribute::

use App\Model\UserDto;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;

// ...

public function dashboard(
#[MapRequestPayload] UserDTO $userDto
): Response
{
// ...
}

This attribute allows you to customize the serialization context as well
as the class responsible of doing the mapping between the request and
your DTO::

public function dashboard(
#[MapRequestPayload(
serializationContext: ['...'],
resolver: App\Resolver\UserDtoResolver
)]
UserDTO $userDto
): Response
{
// ...
}

.. versionadded:: 6.3

The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload` attribute
was introduced in Symfony 6.3.

Managing the Session
--------------------

Expand Down Expand Up @@ -604,3 +755,4 @@ Learn more about Controllers
.. _`Early hints`: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103
.. _`SAPI`: https://www.php.net/manual/en/function.php-sapi-name.php
.. _`FrankenPHP`: https://frankenphp.dev
.. _`Validate Filters`: https://www.php.net/manual/en/filter.filters.validate.php
3 changes: 3 additions & 0 deletions reference/attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ HttpKernel
* :class:`Symfony\\Component\\HttpKernel\\Attribute\\AsPinnedValueResolver`
* :ref:`Cache <http-cache-expiration-intro>`
* :ref:`MapDateTime <functionality-shipped-with-the-httpkernel>`
* :ref:`MapQueryParameter <controller_map-request>`
* :ref:`MapQueryString <controller_map-request>`
* :ref:`MapRequestPayload <controller_map-request>`
* :class:`Symfony\\Component\\HttpKernel\\Attribute\\ValueResolver`
* :ref:`WithHttpStatus <framework_exceptions>`
* :ref:`WithLogLevel <framework_exceptions>`
Expand Down