Skip to content

Commit

Permalink
fix(validation)!: validate parameters with multiple values
Browse files Browse the repository at this point in the history
Ref #4798
  • Loading branch information
aegypius committed Oct 27, 2023
1 parent 6606dd4 commit db1c5e5
Showing 1 changed file with 82 additions and 2 deletions.
84 changes: 82 additions & 2 deletions src/Api/QueryParameterValidator/QueryParameterValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,16 @@ public function validateFilters(string $resourceClass, array $resourceFilters, a
}

foreach ($filter->getDescription($resourceClass) as $name => $data) {
foreach ($this->validators as $validator) {
if ($errors = $validator->validate($name, $data, $queryParameters)) {
$collectionFormat = $this->getCollectionFormat($data);

// validate simple values
if ($errors = $this->validate($name, $data, $queryParameters)) {
$errorList[] = $errors;
}

// manipulate query data to validate each value
foreach ($this->iterateValue($name, $queryParameters, $collectionFormat) as $scalarQueryParameters) {
if ($errors = $this->validate($name, $data, $scalarQueryParameters)) {
$errorList[] = $errors;
}
}
Expand All @@ -72,4 +80,76 @@ public function validateFilters(string $resourceClass, array $resourceFilters, a
throw new FilterValidationException(array_merge(...$errorList));
}
}

/**
* @param array<string, array<string, mixed>> $filterDescription
*/
private static function getCollectionFormat(array $filterDescription): string
{
return $filterDescription['openapi']['collectionFormat'] ?? $filterDescription['swagger']['collectionFormat'] ?? 'csv';
}

/**
* @param array<string, mixed> $queryParameters
*
* @throws \InvalidArgumentException
*/
private static function iterateValue(string $name, array $queryParameters, string $collectionFormat = 'csv'): \Generator
{
$candidates = array_filter(
$queryParameters,
static fn (string $key) => $key === $name || "{$key}[]" === $name,
\ARRAY_FILTER_USE_KEY
);

foreach ($candidates as $key => $value) {
$values = self::getValue($value, $collectionFormat);
foreach ($values as $v) {
yield [$key => $v];
}
}
}

/**
* @param int|int[]|string|string[] $value
*
* @return int[]|string[]
*/
private static function getValue(int|string|array $value, string $collectionFormat = 'csv'): array
{
if (\is_array($value)) {
return $value;

Check warning on line 121 in src/Api/QueryParameterValidator/QueryParameterValidator.php

View check run for this annotation

Codecov / codecov/patch

src/Api/QueryParameterValidator/QueryParameterValidator.php#L121

Added line #L121 was not covered by tests
}

if (\is_string($value)) {
return explode(self::getSeparator($collectionFormat), $value);
}

return [$value];

Check warning on line 128 in src/Api/QueryParameterValidator/QueryParameterValidator.php

View check run for this annotation

Codecov / codecov/patch

src/Api/QueryParameterValidator/QueryParameterValidator.php#L128

Added line #L128 was not covered by tests
}

/** @return non-empty-string */
private static function getSeparator(string $collectionFormat): string
{
return match ($collectionFormat) {
'csv' => ',',
'ssv' => ' ',
'tsv' => '\t',
'pipes' => '|',
default => throw new \InvalidArgumentException(sprintf('Unknown collection format %s', $collectionFormat)),
};
}

private function validate(string $name, array $data, array $queryParameters): array
{
$errorList = [];

foreach ($this->validators as $validator) {
if ($errors = $validator->validate($name, $data, $queryParameters)) {
$errorList[] = $errors;
}
}

return array_merge(...$errorList);
}
}

0 comments on commit db1c5e5

Please sign in to comment.