vendor/api-platform/core/src/Filter/QueryParameterValidateListener.php line 41

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace ApiPlatform\Core\Filter;
  12. use ApiPlatform\Core\Api\FilterLocatorTrait;
  13. use ApiPlatform\Core\Exception\FilterValidationException;
  14. use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
  15. use ApiPlatform\Core\Util\RequestAttributesExtractor;
  16. use Psr\Container\ContainerInterface;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  19. /**
  20.  * Validates query parameters depending on filter description.
  21.  *
  22.  * @author Julien Deniau <julien.deniau@gmail.com>
  23.  */
  24. final class QueryParameterValidateListener
  25. {
  26.     use FilterLocatorTrait;
  27.     private $resourceMetadataFactory;
  28.     public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactoryContainerInterface $filterLocator)
  29.     {
  30.         $this->resourceMetadataFactory $resourceMetadataFactory;
  31.         $this->setFilterLocator($filterLocator);
  32.     }
  33.     public function onKernelRequest(GetResponseEvent $event): void
  34.     {
  35.         $request $event->getRequest();
  36.         if (
  37.             !$request->isMethodSafe(false)
  38.             || !($attributes RequestAttributesExtractor::extractAttributes($request))
  39.             || !isset($attributes['collection_operation_name'])
  40.             || 'get' !== ($operationName $attributes['collection_operation_name'])
  41.         ) {
  42.             return;
  43.         }
  44.         $resourceMetadata $this->resourceMetadataFactory->create($attributes['resource_class']);
  45.         $resourceFilters $resourceMetadata->getCollectionOperationAttribute($operationName'filters', [], true);
  46.         $errorList = [];
  47.         foreach ($resourceFilters as $filterId) {
  48.             if (!$filter $this->getFilter($filterId)) {
  49.                 continue;
  50.             }
  51.             foreach ($filter->getDescription($attributes['resource_class']) as $name => $data) {
  52.                 if (!($data['required'] ?? false)) { // property is not required
  53.                     continue;
  54.                 }
  55.                 if (!$this->isRequiredFilterValid($name$request)) {
  56.                     $errorList[] = sprintf('Query parameter "%s" is required'$name);
  57.                 }
  58.             }
  59.         }
  60.         if ($errorList) {
  61.             throw new FilterValidationException($errorList);
  62.         }
  63.     }
  64.     /**
  65.      * Test if required filter is valid. It validates array notation too like "required[bar]".
  66.      */
  67.     private function isRequiredFilterValid(string $nameRequest $request): bool
  68.     {
  69.         $matches = [];
  70.         parse_str($name$matches);
  71.         if (!$matches) {
  72.             return false;
  73.         }
  74.         $rootName = (string) (array_keys($matches)[0] ?? null);
  75.         if (!$rootName) {
  76.             return false;
  77.         }
  78.         if (\is_array($matches[$rootName])) {
  79.             $keyName array_keys($matches[$rootName])[0];
  80.             $queryParameter $request->query->get($rootName);
  81.             return \is_array($queryParameter) && isset($queryParameter[$keyName]);
  82.         }
  83.         return null !== $request->query->get($rootName);
  84.     }
  85. }