Skip to content

Commit

Permalink
Allowed Constraint to be used on the requirements option on QueryPara…
Browse files Browse the repository at this point in the history
…ms and RequestParams
  • Loading branch information
ClementGautier committed Mar 10, 2014
1 parent 3345659 commit 7031f40
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 47 deletions.
4 changes: 2 additions & 2 deletions Controller/Annotations/Param.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ abstract class Param
public $name;
/** @var string */
public $key = null;
/** @var string */
public $requirements = '';
/** @var mixed */
public $requirements = null;
/** @var mixed */
public $default = null;
/** @var string */
Expand Down
68 changes: 46 additions & 22 deletions Request/ParamFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use Doctrine\Common\Util\ClassUtils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Validator\ValidatorInterface;

/**
* Helper to validate parameters of the active request.
Expand Down Expand Up @@ -48,16 +50,23 @@ class ParamFetcher implements ParamFetcherInterface
*/
private $controller;

/**
* @var ValidatorInterface
*/
private $validator;

/**
* Initializes fetcher.
*
* @param ParamReader $paramReader Query param reader
* @param Request $request Active request
* @param ParamReader $paramReader Query param reader
* @param Request $request Active request
* @param ValidatorInterface $validator The validator service
*/
public function __construct(ParamReader $paramReader, Request $request)
public function __construct(ParamReader $paramReader, Request $request, ValidatorInterface $validator)
{
$this->paramReader = $paramReader;
$this->request = $request;
$this->request = $request;
$this->validator = $validator;
}

/**
Expand Down Expand Up @@ -103,17 +112,9 @@ public function get($name, $strict = null)
}

if ($config->array) {
$failMessage = null;

if (!is_array($param)) {
$failMessage = sprintf("Query parameter value of '%s' is not an array", $name);
} elseif (count($param) !== count($param, COUNT_RECURSIVE)) {
$failMessage = sprintf("Query parameter value of '%s' must not have a depth of more than one", $name);
}

if (null !== $failMessage) {
if ($strict) {
throw new BadRequestHttpException($failMessage);
throw new BadRequestHttpException(sprintf("Query parameter value of '%s' is not an array", $name));
}

return $default;
Expand Down Expand Up @@ -159,16 +160,39 @@ public function cleanParamWithRequirements(Param $config, $param, $strict)
{
$default = $config->default;

if ('' !== $config->requirements
&& ($param !== $default || null === $default)
&& !preg_match('#^'.$config->requirements.'$#xsu', $param)
) {
if ($strict) {
$paramType = $config instanceof QueryParam ? 'Query' : 'Request';
if (null === $config->requirements || ($param === $default && null !== $default)) {

return $param;
}

$constraint = $config->requirements;

throw new BadRequestHttpException(
$paramType . " parameter value '$param', does not match requirements '{$config->requirements}'"
);
if (is_scalar($constraint)) {
if (is_array($param)) {
if ($strict) {
throw new BadRequestHttpException("Query parameter is an array");
}

return $default;
}

$constraint = new Regex(array(

This comment has been minimized.

Copy link
@blex18

blex18 Mar 11, 2014

preg_quote turns \d+ annotations from examples to \\d\+

'pattern' => '#^'.preg_quote($config->requirements).'$#xsu',
'message' => sprintf(
"%s parameter value '%s', does not match requirements '%s'",
$config instanceof QueryParam ? 'Query' : 'Request',
$param,
$config->requirements
)
));
}

$errors = $this->validator->validateValue($param, $constraint);

if (0 !== count($errors)) {

if ($strict) {
throw new BadRequestHttpException((string) $errors);
}

return null === $default ? '' : $default;
Expand Down
1 change: 1 addition & 0 deletions Resources/config/request.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<service id="fos_rest.request.param_fetcher" class="%fos_rest.request.param_fetcher.class%" scope="request">
<argument type="service" id="fos_rest.request.param_fetcher.reader"/>
<argument type="service" id="request"/>
<argument type="service" id="validator"/>
</service>

<service id="fos_rest.request.param_fetcher.reader" class="%fos_rest.request.param_fetcher.reader.class%">
Expand Down
9 changes: 8 additions & 1 deletion Resources/doc/3-listener-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ fos_rest:
use FOS\RestBundle\Request\ParamFetcher;
use FOS\RestBundle\Controller\Annotations\RequestParam;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use Acme\FooBundle\Validation\Constraints\MyComplexConstraint

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

1 comment on commit 7031f40

@Gnucki
Copy link

@Gnucki Gnucki commented on 7031f40 Mar 11, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

This seems to produce a bug for me:
"Request parameter value 'test', does not match requirements ''".

Here is my annotation line:
* @RequestParam(name="source", strict=true, description="The source name.")

This was woking with the last commit of the 7th of march.

I'm sorry if this is not the real cause but i didn't had much time to investigate.

Please sign in to comment.