Skip to content

Commit 7031f40

Browse files
Allowed Constraint to be used on the requirements option on QueryParams and RequestParams
1 parent 3345659 commit 7031f40

File tree

5 files changed

+308
-47
lines changed

5 files changed

+308
-47
lines changed

Controller/Annotations/Param.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ abstract class Param
2323
public $name;
2424
/** @var string */
2525
public $key = null;
26-
/** @var string */
27-
public $requirements = '';
26+
/** @var mixed */
27+
public $requirements = null;
2828
/** @var mixed */
2929
public $default = null;
3030
/** @var string */

Request/ParamFetcher.php

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Doctrine\Common\Util\ClassUtils;
1818
use Symfony\Component\HttpFoundation\Request;
1919
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
20+
use Symfony\Component\Validator\Constraints\Regex;
21+
use Symfony\Component\Validator\ValidatorInterface;
2022

2123
/**
2224
* Helper to validate parameters of the active request.
@@ -48,16 +50,23 @@ class ParamFetcher implements ParamFetcherInterface
4850
*/
4951
private $controller;
5052

53+
/**
54+
* @var ValidatorInterface
55+
*/
56+
private $validator;
57+
5158
/**
5259
* Initializes fetcher.
5360
*
54-
* @param ParamReader $paramReader Query param reader
55-
* @param Request $request Active request
61+
* @param ParamReader $paramReader Query param reader
62+
* @param Request $request Active request
63+
* @param ValidatorInterface $validator The validator service
5664
*/
57-
public function __construct(ParamReader $paramReader, Request $request)
65+
public function __construct(ParamReader $paramReader, Request $request, ValidatorInterface $validator)
5866
{
5967
$this->paramReader = $paramReader;
60-
$this->request = $request;
68+
$this->request = $request;
69+
$this->validator = $validator;
6170
}
6271

6372
/**
@@ -103,17 +112,9 @@ public function get($name, $strict = null)
103112
}
104113

105114
if ($config->array) {
106-
$failMessage = null;
107-
108115
if (!is_array($param)) {
109-
$failMessage = sprintf("Query parameter value of '%s' is not an array", $name);
110-
} elseif (count($param) !== count($param, COUNT_RECURSIVE)) {
111-
$failMessage = sprintf("Query parameter value of '%s' must not have a depth of more than one", $name);
112-
}
113-
114-
if (null !== $failMessage) {
115116
if ($strict) {
116-
throw new BadRequestHttpException($failMessage);
117+
throw new BadRequestHttpException(sprintf("Query parameter value of '%s' is not an array", $name));
117118
}
118119

119120
return $default;
@@ -159,16 +160,39 @@ public function cleanParamWithRequirements(Param $config, $param, $strict)
159160
{
160161
$default = $config->default;
161162

162-
if ('' !== $config->requirements
163-
&& ($param !== $default || null === $default)
164-
&& !preg_match('#^'.$config->requirements.'$#xsu', $param)
165-
) {
166-
if ($strict) {
167-
$paramType = $config instanceof QueryParam ? 'Query' : 'Request';
163+
if (null === $config->requirements || ($param === $default && null !== $default)) {
164+
165+
return $param;
166+
}
167+
168+
$constraint = $config->requirements;
168169

169-
throw new BadRequestHttpException(
170-
$paramType . " parameter value '$param', does not match requirements '{$config->requirements}'"
171-
);
170+
if (is_scalar($constraint)) {
171+
if (is_array($param)) {
172+
if ($strict) {
173+
throw new BadRequestHttpException("Query parameter is an array");
174+
}
175+
176+
return $default;
177+
}
178+
179+
$constraint = new Regex(array(
180+
'pattern' => '#^'.preg_quote($config->requirements).'$#xsu',
181+
'message' => sprintf(
182+
"%s parameter value '%s', does not match requirements '%s'",
183+
$config instanceof QueryParam ? 'Query' : 'Request',
184+
$param,
185+
$config->requirements
186+
)
187+
));
188+
}
189+
190+
$errors = $this->validator->validateValue($param, $constraint);
191+
192+
if (0 !== count($errors)) {
193+
194+
if ($strict) {
195+
throw new BadRequestHttpException((string) $errors);
172196
}
173197

174198
return null === $default ? '' : $default;

Resources/config/request.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<service id="fos_rest.request.param_fetcher" class="%fos_rest.request.param_fetcher.class%" scope="request">
1717
<argument type="service" id="fos_rest.request.param_fetcher.reader"/>
1818
<argument type="service" id="request"/>
19+
<argument type="service" id="validator"/>
1920
</service>
2021

2122
<service id="fos_rest.request.param_fetcher.reader" class="%fos_rest.request.param_fetcher.reader.class%">

Resources/doc/3-listener-support.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ fos_rest:
421421
use FOS\RestBundle\Request\ParamFetcher;
422422
use FOS\RestBundle\Controller\Annotations\RequestParam;
423423
use FOS\RestBundle\Controller\Annotations\QueryParam;
424+
use Acme\FooBundle\Validation\Constraints\MyComplexConstraint
424425

425426
class FooController extends Controller
426427
{
@@ -461,7 +462,13 @@ class FooController extends Controller
461462
* If ids is not defined, array(1) will be given
462463
*
463464
* Array must have a single depth or it will return default value. It's difficult to validate with
464-
* preg_match each deeps of array, if you want to deal with that, use another validation system.
465+
* preg_match each deeps of array, if you want to deal with that, you can use a constraint:
466+
*
467+
* @QueryParam(array=true, name="filters", requirements=@MyComplexConstraint, description="List of complex filters")
468+
*
469+
* In this example, the ParamFetcher will validate each value of the array with the constraint, returning the
470+
* default value if you are in safe mode or throw a BadRequestHttpResponse containing the constraint violation
471+
* messages in the message.
465472
*
466473
* @param ParamFetcher $paramFetcher
467474
*/

0 commit comments

Comments
 (0)