Filtering data
One of the most important actions in development is getting the right set of data by given criteria. The graphql-base module gives some most common filters you might need to use, out of the box:
- Bool filter
- equals
get rows where field is equal to the value given; example:
{equals: true}
- Date filter
- equals
get rows where field is equal to the value given; example:
{equals: '2020-01-30 12:37:21'}
- between
get rows where field value is between given values; example:
{between: ['2020-01-30 12:37:21', '2020-02-30 10:20:30']}
- Integer filter
- equals
get rows where field is equal to the value given; example:
{equals: 5}
- lessThan
get rows where field is less then the value given; example:
{lessThan: 5}
- greaterThan
get rows where field is greater then the value given; example:
{greaterThan: 5}
- between
get rows where field value is between given values; example:
{between: [1, 5]}
- Float filter
This filter takes the same configuration as Integer filter, but float values are used!
- String filter
- equals
get rows where field is equal to the string given; example:
{equals: 'some text'}
- contains
get rows where field contains string given; example:
{contains: 'me tex'}
- beginsWith
get rows where field begins with string given example:
{beginsWith: 'some'}
And several more specific ones:
- Pagination filter
- offset
set the row number to start listing from; example:
{offset: 10, limit: 10}
- limit
set the count of rows we would like to get; example:
{offset: 0, limit: 100}
- ID filter
- equals
get rows where field is equal to the string representation of the ID given; example:
{equals: 'some text'}
Main idea
Via the graphql query we provide arguments for filter constructor and later
on we apply created preconfigured filter on the current query builder object
instance by passing it to addToQuery
method of the filter and modifying the
builder by this selected specific filter configuration.
Simple direct filter usage example
In this example, we create a country query with possibility to filter countries by title and we will use our String filter for this:
/**
* @Query()
*
* @return string[][]
*/
public function exampleCountryQuery(?StringFilter $titleFilter = null): array
{
$queryBuilder = $this->queryBuilderFactory->create();
$queryBuilder->select('OXID,OXTITLE,OXISOALPHA2')
->from('oxcountry');
$titleFilter->addToQuery($queryBuilder, 'oxtitle');
$queryBuilder->getConnection()->setFetchMode(PDO::FETCH_ASSOC);
return $queryBuilder->execute()->fetchAll();
}
Later on, we can apply the “title” filter on the query via the GraphQL interface. As there are several variants possible for String filter (equals, contains, beginsWith), we could use any combination of those, but as example, simple “equals” usage is shown:
query {
exampleCountryQuery(
titleFilter: {
equals: "Deutschland"
}
)
}
Result of this query will be one country data with specific name:
{
"data": {
"exampleCountryQuery": [
[
"a7c40f631fc920687.20179984",
"Deutschland",
"DE"
]
]
}
}
Important
The example do not provide you best practices architecture for your application - this is just an example to understand the main idea.
Filtering by multiple fields
Often we need more then one field with more then one filter at the time. For this reason, we could wrap several filters in some filter list DataType:
final class CountryFilterList
{
/** @var ?StringFilter */
private $title;
/** @var ?StringFilter */
private $iso;
public function __construct(
?StringFilter $title = null,
?StringFilter $iso = null
) {
$this->title = $title;
$this->iso = $iso;
}
/**
* @return array{
* oxtitle: ?StringFilter
* oxisoalpha2: ?StringFilter
* }
*/
public function getFilters(): array
{
return [
'OXTITLE' => $this->title,
'OXISOALPHA2' => $this->iso
];
}
/**
* @Factory(name="CountryFilterList")
*/
public static function createCountryFilterList(
?StringFilter $title = null,
?StringFilter $iso = null
): self {
return new self(
$title,
$iso
);
}
}
While having this filter list, we will require this DataType in place of our single filter in controller query from simple filter example, and just apply multiple filters to our query builder instead of previously used one:
public function exampleCountryQuery(?CountryFilterList $filter = null): array
{
...
/** @var FilterInterface[] $filters */
$filters = $filterList->getFilters();
foreach ($filters as $field => $fieldFilter) {
$fieldFilter->addToQuery($queryBuilder, $field);
}
...
}
Now our filter list can be used in a query:
query{
exampleCountryQuery (
filter: {
title: {
beginsWith: "D"
}
iso: {
beginsWith: "DM"
}
}
)
}
Gives us a country that was filtered by our conditions:
{
"data": {
"exampleCountryQuery": [
[
"8f241f11095811ea5.84717844",
"Dominica",
"DM"
]
]
}
}
How to add your own filters
You can easily add your own filters by implementing your new filter class in your module DataType folder.
There are no hard requirements on implementing any interfaces or implementing those new filters by any rules - everything is up to you! But, you could go together with us, and try reusing our interfaces and structures for making some standards for us and everyone in the future!
Feel free to make some pull requests with your great filters that others could get benefit from!