Filters
Restify provides few powerful ways to filter and search your data.
Global search
Restify provides a global endpoint that searches over all repositories searchable fields.
To define which repository fields are searchable, you may assign an array of database columns in the search
property of your repository class. This includes id column by default, but you may override it to your needs:
class PostRepository extends Repository
{
public static array $search = ['id', 'title'];
The endpoint to search is:
GET: /api/restify/search?search="Test title"
It will search over all repositories that are authorized (has allowRestify
policy on true).
Disabling global search
There are 2 ways to disable the global search: for a repository, either return false from the allowRestify
model policy method or
So to disable the Posts
from the global search using the repository property we do:
// PostRepository.php
public static bool $globallySearchable = false;
Paginate global search
You can limit the number of results that are returned in the global search by overriding the globalSearchResults
property on the resource:
// PostRepository.php
public static int $globalSearchResults = 5;
Restify has built in support for laravel scout, so it will initialize the query using scout if you have setup it for the model.
Customize global search
The default global search response looks like this:
{
"data": [
{
"repositoryName": "users",
"repositoryTitle": "Users",
"title": "Mrs. Lucie Parker Jr.",
"subTitle": null,
"repositoryId": 1,
"link": "/api/restify/users/1"
}
]
}
Where the title
is the repository column defined by the $title
property. So you can customize it:
// UserRepository.php
public static string $title = 'email';
The subTitle
could be customized by overriding the subtitle
method. The returned value will be displayed here:
// UserRepository.php
public function subtitle(): ?string
{
return 'User email: ' . $this->model()->email;
}
Repository Search
The repository search works in a similar way as global search, however in this case the endpoint refers to the repository and the search will be applied for a certain repository.
Say we want to search users by their email
and name
:
class UserRepository extends Repository
{
public static array $search = ['name', 'email'];
So the endpoint will scope the the users
repository now:
GET: /api/restify/users?search="John Doe"
Case-sensitive search
By default, Restify search is case-sensitive. You can change this behavior by changing the configuration:
// restify.php
'search' => [
/*
| Specify either the search should be case-sensitive or not.
*/
'case_sensitive' => false,
],
Custom search filter
The search could be customized by creating a class that extends the \Binaryk\LaravelRestify\Filters\SearchableFilter
:
use Binaryk\LaravelRestify\Filters\SearchableFilter;
class CustomTitleSearchFilter extends SearchableFilter
{
public function filter(RestifyRequest $request, $query, $value)
{
return $query->orWhere('name', 'like', "%$value%");
}
}
In the filter
method you can define your own filtering over the $query
builder and then attach the class instance to a column:
public static function searchables(): array
{
return [
'title' => CustomTitleSearchFilter::make(),
];
}
As soon as you define the searchables
method into the repository, the $search
array is not taken into consideration anymore. So make sure you return all available search fields from this method.
Match
Matching by specific attributes may be useful if you want an exact matching.
Repository configuration:
class PostRepository extends Repository
{
public static array $match = [
'id' => 'int',
'title' => 'string',
];
}
As we may notice the match configuration is an associative array, defining the attribute name and type mapping.
Available types:
When performing the request you may pass the match field and value as query params:
GET: /api/restify/posts?id=1
or by title:
GET: /api/restify/posts?title="Some title"
Match string
Definition:
class PostRepository extends Repository
{
public static array $match = [
'title' => 'string',
];
}
Request:
GET: /api/restify/posts?title="Title"
Match bool
Definition:
class PostRepository extends Repository
{
public static array $match = [
'active' => 'bool',
];
}
Request:
GET: /api/restify/posts?active=true
Match int
Definition:
class PostRepository extends Repository
{
public static array $match = [
'id' => 'int',
];
}
Request:
GET: /api/restify/posts?id=1
Match datetime
The datetime
filter add behind the scene an whereDate
query.
class PostRepository extends Repository
{
public static array $match = [
'published_at' => 'datetime',
];
}
Request:
GET: /api/restify/posts?published_at=2020-12-01
If the request contains two dates instead of one, it will perform a whereBetween
query:
GET: /api/restify/posts?published_at=2020-12-01,2021-01-01
Eloquent will do:
$query->whereBetween('published_at', ['2020-12-01', '2021-01-01']);
Match between
The between
match works similarly as the whereBetween
Eloquent method:
class PostRepository extends Repository
{
public static array $match = [
'id' => 'between',
'published_at' => 'between',
];
}
Request:
GET: /api/restify/posts?published_at=2021-09-16,2021-11-16
So it will return all posts published between the first and the second dates. It works with integer
as well:
GET: /api/restify/posts?id=1,20
Match all available ids
between 1
and 20
.
Match array
Match also accept a list of elements in the query param:
class PostRepository extends Repository
{
public static $match = [
'id' => 'array'
];
}
Request:
GET: /api/restify/posts?id=1,2,3
This will be converted to:
->whereIn('id', [1, 2, 3])
Match null
All match types accept null
as a value, and check add whereNull
to the query:
GET: /api/restify/posts?published_at=null
Match negation
All match types accept a negation, so you can negate the column match by simply adding the -
(minus) sign before the field:
GET: /api/restify/posts?-id=1,2,3
This will return all posts where doesn't have the id
in the [1,2,3]
list.
You can apply -
(negation) for every match:
GET: /api/restify/posts?-title="Some title"
This will return all posts that doesn't contain Some title
substring.
Custom match filter
Sometimes you may have a large logic into a match. To allow this, Restify
provides a declarative way to define matchers
. For this purpose you should define a class, that extends the Binaryk\LaravelRestify\Filters\MatchFilter
:
use Binaryk\LaravelRestify\Filters\MatchFilter;
class ActivePostMatchFiler extends MatchFilter
{
public function filter(RestifyRequest $request, Builder | Relation $query, $value)
{
// your logic here
}
}
The next step is to return this class instance from the matchers
method:
// PostRepository.php
public static function matches(): array
{
return [
'active' => ActivePostMatchFiler::make(),
];
}
As soon as you define the matches
method into the repository, the $match
array is not taken into consideration anymore. So make sure you return all available matches from this method.
Partial match
The match filters 1:1 match, however, when you're looking for a substring into a text, you might need to partially match it.
This could be done using the Binaryk\LaravelRestify\Filters\MatchFilter
class:
public static function matches(): array
{
return [
'title' => MatchFilter::make()->setType('text')->partial()
];
}
Get available matches
You can use the following request to get all repository matches:
/api/restify/posts/filters?only=matches