Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to always filter a collection on specific field value in api-platform GET operations?

In the GET operations, I'd like to exclude from the returning collections my entities that have an " archive" field that equals " true ".

I'd like that to be the default for my endpoints like /users or /companies and i want to avoid to add an URL filter by hand like /users?filter[archive]=true

what would be the best way to do that ?

Thanks for any help :)

like image 449
eincandela Avatar asked Sep 02 '19 19:09

eincandela


1 Answers

I had to do something like that, and I solved it by applying a DoctrineExtension to a Collection that will add the WHERE clause to the QueryBuilder.

How?

  1. Define your Filter, I see you already have that.
  2. Add the Doctrine Extension to by applied only to Collections, or if you need, also to an Item: https://api-platform.com/docs/core/extensions/#custom-doctrine-orm-extension
services:
    App\Doctrine\Extension\ArchivedExtension:
        tags:
            - { name: api_platform.doctrine.orm.query_extension.collection }
  1. Code your Extension.

You could check if you are receiving a certain "filter" (your "filter[archive]=true" query parameter): if YES, dont apply the condition to the QueryBuilder, your Filter will be applied by the filtering mechanism of ApiPlatform.

Your extension class should looked something like this:

class ArchivedExtension implements QueryCollectionExtensionInterface
{
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null, array $context = [])
    {
        $this->addWhere($queryBuilder, $resourceClass, $context);
    }

    private function addWhere(QueryBuilder $queryBuilder, string $resourceClass, array $context = [])
    {
        if (MyResource::class !== $resourceClass) {
            return;
        }

        // Search if a "archive" Filter is being requested, if not, apply a restriction to the QueryBuilder
        if (array_key_exists('archive', $context['filters'])) {
            return;
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->andWhere(sprintf('%s.archive = :archive', $rootAlias));
        $queryBuilder->setParameter('archive', true);
    }
}
like image 116
Pada Avatar answered Oct 28 '22 23:10

Pada