Skip to content

Commit

Permalink
feature #53209 [HttpKernel] Add support for custom HTTP status code f…
Browse files Browse the repository at this point in the history
…or the `#[MapQueryParameter]` attribute (ovidiuenache)

This PR was merged into the 7.1 branch.

Discussion
----------

[HttpKernel] Add support for custom HTTP status code for the `#[MapQueryParameter]` attribute

| Q             | A
| ------------- | ---
| Branch?       | 7.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | #52782
| License       | MIT

Issue #52782 was created where the need to have a custom HTTP status code for the MapQueryParameter attribute was stated. As part of the discussion, `@nicolas`-grekas suggested an approach similar to the implementation of the MapQueryString attribute where such a status code can be provided in the attribute's constructor.

I believe having the possibility to control the status code returned for an invalid and non-nullable parameter with no default value would be a great addition so I took the liberty to create this PR.

This change is backward compatible.

Commits
-------

c9f33bb [HttpKernel] Add support for custom HTTP status code for the MapQueryParameter attribute
  • Loading branch information
nicolas-grekas committed Jan 2, 2024
2 parents 862c6fb + c9f33bb commit 0766167
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 111 deletions.
Expand Up @@ -11,12 +11,14 @@

namespace Symfony\Component\HttpKernel\Attribute;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\QueryParameterValueResolver;

/**
* Can be used to pass a query parameter to a controller argument.
*
* @author Ruud Kamphuis <ruud@ticketswap.com>
* @author Ionut Enache <i.ovidiuenache@yahoo.com>
*/
#[\Attribute(\Attribute::TARGET_PARAMETER)]
final class MapQueryParameter extends ValueResolver
Expand All @@ -32,6 +34,7 @@ public function __construct(
public int $flags = 0,
public array $options = [],
string $resolver = QueryParameterValueResolver::class,
public int $validationFailedStatusCode = Response::HTTP_NOT_FOUND,
) {
parent::__construct($resolver);
}
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/HttpKernel/CHANGELOG.md
Expand Up @@ -6,6 +6,7 @@ CHANGELOG

* Add method `isKernelTerminating()` to `ExceptionEvent` that allows to check if an exception was thrown while the kernel is being terminated
* Add `HttpException::fromStatusCode()`
* Add `$validationFailedStatusCode` argument to `#[MapQueryParameter]` that allows setting a custom HTTP status code when validation fails

7.0
---
Expand Down
Expand Up @@ -15,14 +15,15 @@
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
* Resolve arguments of type: array, string, int, float, bool, \BackedEnum from query parameters.
*
* @author Ruud Kamphuis <ruud@ticketswap.com>
* @author Nicolas Grekas <p@tchwork.com>
* @author Mateusz Anders <anders_mateusz@outlook.com>
* @author Ionut Enache <i.ovidiuenache@yahoo.com>
*/
final class QueryParameterValueResolver implements ValueResolverInterface
{
Expand All @@ -33,12 +34,14 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
}

$name = $attribute->name ?? $argument->getName();
$validationFailedCode = $attribute->validationFailedStatusCode;

if (!$request->query->has($name)) {
if ($argument->isNullable() || $argument->hasDefaultValue()) {
return [];
}

throw new NotFoundHttpException(sprintf('Missing query parameter "%s".', $name));
throw HttpException::fromStatusCode($validationFailedCode, sprintf('Missing query parameter "%s".', $name));
}

$value = $request->query->all()[$name];
Expand All @@ -52,7 +55,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
$filtered = array_values(array_filter((array) $value, \is_array(...)));

if ($filtered !== $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) {
throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name));
throw HttpException::fromStatusCode($validationFailedCode, sprintf('Invalid query parameter "%s".', $name));
}

return $filtered;
Expand Down Expand Up @@ -103,7 +106,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
}

if (null === $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) {
throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name));
throw HttpException::fromStatusCode($validationFailedCode, sprintf('Invalid query parameter "%s".', $name));
}

if (!\is_array($value)) {
Expand All @@ -117,7 +120,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
}

if ($filtered !== $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) {
throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name));
throw HttpException::fromStatusCode($validationFailedCode, sprintf('Invalid query parameter "%s".', $name));
}

return $argument->isVariadic() ? $filtered : [$filtered];
Expand Down

0 comments on commit 0766167

Please sign in to comment.