The spiral/filters
is a powerful component for filtering and validating input data. It allows you to define a set of
rules for each input field, and then use those rules to ensure that the input data is in the correct format and meets
any other requirements you have set. You can use filters to validate data from HTTP requests, gRPC requests, console
commands, and other sources.
One of the benefits of using filters is that it helps to centralize your input validation logic in a single place. This can make it easier to maintain your code, as you don't need to duplicate validation logic in multiple places throughout your application.
Additionally, filters can be reused across different parts of your application, which can help to reduce code duplication and make it easier to manage your validation logic.
Illustration of the process of filtering and validating input data in an HTTP layer
See more
Read more about how to use filters for console commands in the Cookbook — Console command input validation section.
Note
The component relies on Validation component, make sure to read it first.
The component does not require any configuration and can be activated using the
bootloader Spiral\Bootloader\Security\FiltersBootloader
:
protected const LOAD = [
// ...
\Spiral\Bootloader\Security\FiltersBootloader::class,
// ...
];
The filter components operate using the Spiral\Filter\InputInterface
as a primary data source:
interface InputInterface
{
public function withPrefix(string $prefix, bool $add = true): InputInterface;
public function getValue(string $source, string $name = null);
}
By default, this interface is bound to InputManager and allows to access any request's attribute using a source and origin pair with dot-notation support.
For example:
namespace App\Controller;
use Spiral\Filters\InputInterface;
class HomeController
{
public function index(InputInterface $input): void
{
dump($input->getValue('query', 'abc')); // ?abc=1
// dot notation
dump($input->getValue('query', 'a.b.c')); // ?a[b][c]=2
// same as above
dump($input->withPrefix('a')->getValue('query', 'b.c')); // ?a[b][c]=2
}
}
Input binding is the primary way of delivering data from request into the filter object.
The implementation of the filter object might vary from package to package. The default implementation is provided via
the abstract class Spiral\Filters\Model\Filter
. To create a custom filter to validate a simple query value with
key username
:
namespace App\Filter;
use Spiral\Filters\Attribute\Input\Query;
use Spiral\Filters\Model\Filter;
final class UserFilter extends Filter
{
#[Query]
public string $username;
}
You can request the Filter as a method injection (it will be automatically bound to the current HTTP request input):
namespace App\Controller;
use App\Filter\UserFilter;
class UserController
{
public function show(UserFilter $filter): void
{
dump($filter->username);
}
}
By default, filters do not perform validation. However, if you want to validate a filter, you can implement the
HasFilterDefinition
interface and define a set of validation rules for the filter properties using
the FilterDefinition
class with Spiral\Filters\Model\ShouldBeValidated
interface implementation:
namespace App\Filter;
use Spiral\Filters\Model\FilterDefinitionInterface;
use Spiral\Filters\Model\ShouldBeValidated;
final class MyFilterDefinition implements FilterDefinitionInterface, ShouldBeValidated
{
public function __construct(
private readonly array $validationRules = [],
private readonly array $mappingSchema = []
) {
}
public function validationRules(): array
{
return $this->validationRules;
}
public function mappingSchema(): array
{
return $this->mappingSchema;
}
}
Here is an example of registering a filter definition and binding with a validator that will be used to validate filters
with the MyFilterDefinition
definition:
namespace App\Bootloader;
use App\Validation;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Validation\Bootloader\ValidationBootloader;
use Spiral\Validation\ValidationInterface;
use Spiral\Validation\ValidationProvider;
final class ValidatorBootloader extends Bootloader
{
public function boot(ValidationProvider $provider): void
{
$provider->register(
\App\Filter\MyFilterDefinition::class,
static fn(Validation $validation): ValidationInterface => new MyValidation()
);
}
}
Note
Red more about Validation component here .
And now you can use the filter definition in your filter:
namespace App\Filter;
use Spiral\Filters\Attribute\Input\Query;
use Spiral\Filters\Model\Filter;
use Spiral\Filters\Model\FilterDefinitionInterface;
use Spiral\Filters\Model\HasFilterDefinition;
use App\Filter\MyFilterDefinition;
final class UserFilter extends Filter implements HasFilterDefinition
{
#[Query]
public string $username;
public function filterDefinition(): FilterDefinitionInterface
{
return new MyFilterDefinition([
'username' => ['string', 'required']
]);
}
}
Note
Try URL with?username=john
. TheUserFilter
will automatically pre-validate your request before delivering it to the controller.