walidtlili
walidtlili

Reputation: 1100

How to inject api-plaform's pagination filter on my custom dataprovider

I'm developing an application with symfony4, in which I'm using api-platform. I've created a custom dataprovider for a specific entity (Car for example). CarCollectionDataProvider returns all blue cars.

<?php

namespace App\DataProvider;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\PaginationExtension;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Entity\Car;
use Doctrine\Common\Persistence\ManagerRegistry;
use Generator;

final class CarCollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{
    private $managerRegistry;
    private $paginationExtenstion;

    public function __construct(ManagerRegistry $managerRegistry, PaginationExtension $paginationExtension)
    {
        $this->managerRegistry = $managerRegistry;
        $this->paginationExtenstion = $paginationExtension;
    }

    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Car::class === $resourceClass;
    }

    public function getCollection(string $resourceClass, string $operationName = null): Generator
    {
        $queryBuilder = $this->managerRegistry
            ->getManagerForClass($resourceClass)
            ->getRepository($resourceClass)->createQueryBuilder('car')
            ->where('car.color = :color')
            ->setParameter('color', 'blue');

        $this->paginationExtenstion->applyToCollection($queryBuilder, new QueryNameGenerator(), $resourceClass, $operationName, []);

        yield $this->paginationExtenstion->getResult($queryBuilder, $resourceClass, $operationName, []);
    }
}

How can I inject api-platform's pagination extension on my custom dataprovider (CarCollectionDataProvider)?

Upvotes: 2

Views: 3988

Answers (2)

MetaClass
MetaClass

Reputation: 1428

If all you want is allways add a criterium like ->where('car.color = :color') to the queries of all collection operations of some resouce, a custom Extension is more appropriate and will work with the default pagination (and filters):

// api/src/Doctrine/CarCollectionExtension.php

namespace App\Doctrine;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Car;
use Doctrine\ORM\QueryBuilder;

final class CarCollectionExtension implements QueryCollectionExtensionInterface
{
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
    {
        if ($resourceClass != Car::class) return;

         $rootAlias = $queryBuilder->getRootAliases()[0];
         $queryBuilder->andWhere($rootAlias. '.color = :color');
         $queryBuilder->setParameter('color', 'blue');
    }
}

You can make this Extension specific to an operation by adding to the if statement something like:

|| $operationName == 'get_blue'

(from the docs) If you're not using the autoconfiguration, you have to register the custom extension:

# api/config/services.yaml
services:

    # ...

    'App\Doctrine\CarCollectionExtension':
        tags:
            - { name: api_platform.doctrine.orm.query_extension.collection }

If you also want to add a criterium for item operations, see the docs on Extensions

Upvotes: 1

walidtlili
walidtlili

Reputation: 1100

this works fine for me :

<?php

namespace App\DataProvider;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\PaginationExtension;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Entity\Car;
use Doctrine\Common\Persistence\ManagerRegistry;

final class CarCollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{
    private $managerRegistry;
    private $paginationExtension;
    private $context;

    public function __construct(ManagerRegistry $managerRegistry, PaginationExtension $paginationExtension)
    {
        $this->managerRegistry = $managerRegistry;
        $this->paginationExtension = $paginationExtension;
    }

    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        $this->context = $context;
        return Car::class === $resourceClass;
    }

    public function getCollection(string $resourceClass, string $operationName = null)
    {

        $queryBuilder = $this->managerRegistry
            ->getManagerForClass($resourceClass)
            ->getRepository($resourceClass)->createQueryBuilder('car')
            ->where('car.color = :color')
            ->setParameter('color', 'blue');

        $this->paginationExtension->applyToCollection($queryBuilder, new QueryNameGenerator(), $resourceClass, $operationName, $this->context);

        if ($this->paginationExtension instanceof QueryResultCollectionExtensionInterface
            && $this->paginationExtension->supportsResult($resourceClass, $operationName, $this->context)) {

            return $this->paginationExtension->getResult($queryBuilder, $resourceClass, $operationName, $this->context);
        }

        return $queryBuilder->getQuery()->getResult();

    }
}

Upvotes: 3

Related Questions