Skip to content

Commit

Permalink
Merge ecc55af into a9bc507
Browse files Browse the repository at this point in the history
  • Loading branch information
jdeniau committed Jan 25, 2019
2 parents a9bc507 + ecc55af commit 298acf7
Show file tree
Hide file tree
Showing 32 changed files with 2,095 additions and 157 deletions.
136 changes: 132 additions & 4 deletions features/filter/filter_validation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ Feature: Validate filters based upon filter description

@createSchema
Scenario: Required filter should not throw an error if set
When I am on "/filter_validators?required=foo"
When I am on "/filter_validators?required=foo&required-allow-empty=&arrayRequired[foo]="
Then the response status code should be 200

When I am on "/filter_validators?required="
Then the response status code should be 200
Scenario: Required filter that does not allow empty value should throw an error if empty
When I am on "/filter_validators?required=&required-allow-empty=&arrayRequired[foo]="
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "required" does not allow empty value'

Scenario: Required filter should throw an error if not set
When I am on "/filter_validators"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "required" is required'
Then the JSON node "detail" should match '/^Query parameter "required" is required\nQuery parameter "required-allow-empty" is required$/'

Scenario: Required filter should not throw an error if set
When I am on "/array_filter_validators?arrayRequired[]=foo&indexedArrayRequired[foo]=foo"
Expand All @@ -37,3 +39,129 @@ Feature: Validate filters based upon filter description
When I am on "/array_filter_validators?arrayRequired[]=foo&indexedArrayRequired[bar]=bar"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "indexedArrayRequired[foo]" is required'

Scenario: Test filter bounds: maximum
When I am on "/filter_validators?required=foo&required-allow-empty&maximum=10"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&maximum=11"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "maximum" must be less than or equal to 10'

Scenario: Test filter bounds: exclusiveMaximum
When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMaximum=9"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMaximum=10"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "exclusiveMaximum" must be less than 10'

Scenario: Test filter bounds: minimum
When I am on "/filter_validators?required=foo&required-allow-empty&minimum=5"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&minimum=0"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "minimum" must be greater than or equal to 5'

Scenario: Test filter bounds: exclusiveMinimum
When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMinimum=6"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMinimum=5"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "exclusiveMinimum" must be greater than 5'

Scenario: Test filter bounds: max length
When I am on "/filter_validators?required=foo&required-allow-empty&max-length-3=123"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&max-length-3=1234"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "max-length-3" length must be lower than or equal to 3'

Scenario: Do not throw an error if value is not an array
When I am on "/filter_validators?required=foo&required-allow-empty&max-length-3[]=12345"
Then the response status code should be 200

Scenario: Test filter bounds: min length
When I am on "/filter_validators?required=foo&required-allow-empty&min-length-3=123"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&min-length-3=12"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "min-length-3" length must be greater than or equal to 3'

Scenario: Test filter pattern
When I am on "/filter_validators?required=foo&required-allow-empty&pattern=pattern"
When I am on "/filter_validators?required=foo&required-allow-empty&pattern=nrettap"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&pattern=not-pattern"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "pattern" must match pattern /^(pattern|nrettap)$/'

Scenario: Test filter enum
When I am on "/filter_validators?required=foo&required-allow-empty&enum=in-enum"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&enum=not-in-enum"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "enum" must be one of "in-enum, mune-ni"'

Scenario: Test filter multipleOf
When I am on "/filter_validators?required=foo&required-allow-empty&multiple-of=4"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&multiple-of=3"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "multiple-of" must multiple of 2'

Scenario: Test filter array items csv format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&csv-min-2=a,b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&csv-min-2=a"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "csv-min-2" must contain more than 2 values'

Scenario: Test filter array items csv format maxItems
When I am on "/filter_validators?required=foo&required-allow-empty&csv-max-3=a,b,c"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&csv-max-3=a,b,c,d"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "csv-max-3" must contain less than 3 values'

Scenario: Test filter array items tsv format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&tsv-min-2=a\tb"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&tsv-min-2=a,b"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "tsv-min-2" must contain more than 2 values'

Scenario: Test filter array items pipes format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&pipes-min-2=a|b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&pipes-min-2=a,b"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "pipes-min-2" must contain more than 2 values'

Scenario: Test filter array items ssv format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&ssv-min-2=a b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&ssv-min-2=a,b"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "ssv-min-2" must contain more than 2 values'

@dropSchema
Scenario: Test filter array items unique items
When I am on "/filter_validators?required=foo&required-allow-empty&csv-uniques=a,b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&csv-uniques=a,a"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "csv-uniques" must contain unique values'
8 changes: 6 additions & 2 deletions src/Bridge/Symfony/Bundle/Resources/config/validator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@
<tag name="kernel.event_listener" event="kernel.view" method="onKernelView" priority="64" />
</service>

<service id="api_platform.listener.view.validate_query_parameters" class="ApiPlatform\Core\Filter\QueryParameterValidateListener" public="false">
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<service id="api_platform.validator.query_parameter_validator" class="ApiPlatform\Core\Filter\QueryParameterValidator" public="false">
<argument type="service" id="api_platform.filter_locator" />
</service>

<service id="api_platform.listener.view.validate_query_parameters" class="ApiPlatform\Core\EventListener\QueryParameterValidateListener" public="false">
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<argument type="service" id="api_platform.validator.query_parameter_validator" />

<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="16" />
</service>
Expand Down
55 changes: 55 additions & 0 deletions src/EventListener/QueryParameterValidateListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\EventListener;

use ApiPlatform\Core\Filter\QueryParameterValidator;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Util\RequestAttributesExtractor;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;

/**
* Validates query parameters depending on filter description.
*
* @author Julien Deniau <julien.deniau@mapado.com>
*/
final class QueryParameterValidateListener
{
private $resourceMetadataFactory;

private $queryParameterValidator;

public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, QueryParameterValidator $queryParameterValidator)
{
$this->resourceMetadataFactory = $resourceMetadataFactory;
$this->queryParameterValidator = $queryParameterValidator;
}

public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if (
!$request->isMethodSafe(false)
|| !($attributes = RequestAttributesExtractor::extractAttributes($request))
|| !isset($attributes['collection_operation_name'])
|| 'get' !== ($operationName = $attributes['collection_operation_name'])
) {
return;
}

$resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']);
$resourceFilters = $resourceMetadata->getCollectionOperationAttribute($operationName, 'filters', [], true);

$this->queryParameterValidator->validateFilters($attributes['resource_class'], $resourceFilters, $request);
}
}
104 changes: 0 additions & 104 deletions src/Filter/QueryParameterValidateListener.php

This file was deleted.

66 changes: 66 additions & 0 deletions src/Filter/QueryParameterValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\Filter;

use ApiPlatform\Core\Api\FilterLocatorTrait;
use ApiPlatform\Core\Exception\FilterValidationException;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;

/**
* Validates query parameters depending on filter description.
*
* @author Julien Deniau <julien.deniau@gmail.com>
*/
class QueryParameterValidator
{
use FilterLocatorTrait;

private $validators;

public function __construct(ContainerInterface $filterLocator)
{
$this->setFilterLocator($filterLocator);

$this->validators = [
new Validator\ArrayItems(),
new Validator\Bounds(),
new Validator\Enum(),
new Validator\Length(),
new Validator\MultipleOf(),
new Validator\Pattern(),
new Validator\Required(),
];
}

public function validateFilters(string $resourceClass, array $resourceFilters, Request $request)
{
$errorList = [];
foreach ($resourceFilters as $filterId) {
if (!$filter = $this->getFilter($filterId)) {
continue;
}

foreach ($filter->getDescription($resourceClass) as $name => $data) {
foreach ($this->validators as $validator) {
$errorList = \array_merge($errorList, $validator->validate($name, $data, $request));
}
}
}

if ($errorList) {
throw new FilterValidationException($errorList);
}
}
}

0 comments on commit 298acf7

Please sign in to comment.