Api platform aliasing filters for nested resources

Viewed 1617

I'm currently using API Platform and its default SearchFilter and it works as intended.
However, filtering on a deep relationship between resources can be heavy by its quite long query string in the url. (I have got multiple entities like this.)

For instance I want to search every books listed in the stores of a specific country :

{url}/books?department.store.city.country.name=italy

Is there any way to edit the @ApiFilter(SearchFilter::class, properties={}) in order to get simply at the end ?

{url}/books?country_filter=italy

Thanks !

2 Answers

Thank you for your advices,

After some (hours of) researches, I came to the conclusion to extend the SearchFilter when creating my personnal CountryFilter :

In my entity class :

/*
 * @ApiFilter(CountryFilter::class, properties={
 *   "country_filter": "department.store.city.country.name",
 * })
 */

In my App\Filter\CountryFilter.php :

<?php

namespace App\Filter;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;

final class CountryFilter extends SearchFilter
{
    protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        foreach($this->properties as $alias => $propertyName){
            if($alias == $property){
                $property = $propertyName;
                break;
            }
        }

        /*
        if (
            null === $value ||
            !$this->isPropertyEnabled($property, $resourceClass) ||
            !$this->isPropertyMapped($property, $resourceClass, true)
        ) {
            return;
        }
        */

        // The rest of the SearchFilter.php copy/pasted code ...
    }

    public function getDescription(string $resourceClass): array
    {
        // ....
    }
}

You can make your one custom api filter and add your own logic in it.Call it country_filter and pass one value only, after that a custom query will search in database and return the rows. To make one you have to extend the AbstractFilter class and after that you have to add this filter it in your entity. A good tutorial from official site is here and the next chapter here

Related