mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
feat(graphql): add strict validation to filters (#1041)
This commit is contained in:
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Filter;
|
||||
|
||||
use App\Rules\Api\IsValidBoolean;
|
||||
use GraphQL\Type\Definition\Type;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
@@ -24,4 +25,15 @@ class BooleanFilter extends Filter
|
||||
fn (string $filterValue): ?bool => filter_var($filterValue, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
new IsValidBoolean(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,4 +35,18 @@ class DateTimeTzFilter extends Filter
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
$allowedDateFormats = array_column(AllowedDateFormat::cases(), 'value');
|
||||
$dateFormats = implode(',', $allowedDateFormats);
|
||||
|
||||
return [
|
||||
'required',
|
||||
"date_format:$dateFormats",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Filter;
|
||||
|
||||
use App\Exceptions\GraphQL\ClientValidationException;
|
||||
use BackedEnum;
|
||||
use Closure;
|
||||
use GraphQL\Type\Definition\Type;
|
||||
use Illuminate\Support\Arr;
|
||||
use Rebing\GraphQL\Support\Facades\GraphQL;
|
||||
@@ -42,10 +42,6 @@ class EnumFilter extends Filter
|
||||
$this->enumClass::cases(),
|
||||
fn (UnitEnum $enum): bool => $enum->name === $filterValue
|
||||
);
|
||||
|
||||
if (! $enum instanceof BackedEnum) {
|
||||
throw new ClientValidationException("'{$filterValue}' does not exist in the ".class_basename($this->enumClass).' enum.');
|
||||
}
|
||||
}
|
||||
|
||||
$values[] = $enum ?? $filterValue;
|
||||
@@ -53,4 +49,23 @@ class EnumFilter extends Filter
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
function ($attribute, mixed $value, Closure $fail): void {
|
||||
if (
|
||||
! is_string($value)
|
||||
|| ! enum_exists($this->enumClass)
|
||||
|| Arr::first($this->enumClass::cases(), fn (UnitEnum $enum): bool => $enum->name === $value) === null
|
||||
) {
|
||||
$fail("'{$value}' does not exist in the ".class_basename($this->enumClass).' enum.');
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ declare(strict_types=1);
|
||||
namespace App\GraphQL\Filter;
|
||||
|
||||
use App\Enums\Http\Api\Filter\ComparisonOperator;
|
||||
use App\Exceptions\GraphQL\ClientValidationException;
|
||||
use App\GraphQL\Argument\Argument;
|
||||
use App\GraphQL\Argument\FilterArgument;
|
||||
use GraphQL\Type\Definition\Type;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
abstract class Filter
|
||||
{
|
||||
@@ -21,9 +24,14 @@ abstract class Filter
|
||||
protected readonly ?string $column = null,
|
||||
) {}
|
||||
|
||||
public function getFieldName(): string
|
||||
{
|
||||
return $this->fieldName;
|
||||
}
|
||||
|
||||
public function getColumn(): string
|
||||
{
|
||||
return $this->column ?? $this->fieldName;
|
||||
return $this->column ?? $this->getFieldName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,6 +47,8 @@ abstract class Filter
|
||||
*/
|
||||
public function getFilterValues(array $attemptedFilterValues): array
|
||||
{
|
||||
$this->validateFilterValues($attemptedFilterValues);
|
||||
|
||||
return $this->convertFilterValues($attemptedFilterValues);
|
||||
}
|
||||
|
||||
@@ -47,6 +57,31 @@ abstract class Filter
|
||||
*/
|
||||
abstract protected function convertFilterValues(array $filterValues): array;
|
||||
|
||||
/**
|
||||
* Validate the filter values against its rules based on types.
|
||||
*/
|
||||
protected function validateFilterValues(array $filterValues): void
|
||||
{
|
||||
foreach ($filterValues as $filterValue) {
|
||||
try {
|
||||
Validator::make(
|
||||
[$this->fieldName => $filterValue],
|
||||
[$this->fieldName => $this->getRules()],
|
||||
)->validate();
|
||||
} catch (ValidationException $e) {
|
||||
throw new ClientValidationException($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the Equal operator to the filter.
|
||||
*/
|
||||
|
||||
@@ -24,4 +24,15 @@ class FloatFilter extends Filter
|
||||
fn (string $filterValue): ?float => filter_var($filterValue, FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
'numeric',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,15 @@ class IntFilter extends Filter
|
||||
fn (string $filterValue): ?int => filter_var($filterValue, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
'integer',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,15 @@ class StringFilter extends Filter
|
||||
{
|
||||
return $filterValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for the filter.
|
||||
*/
|
||||
protected function getRules(): array
|
||||
{
|
||||
return [
|
||||
'required',
|
||||
'string',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user