API-платформа: фильтрация пользовательских данных - PullRequest
0 голосов
/ 25 сентября 2018

В настоящее время у меня возникают проблемы при попытке отфильтровать результаты при использовании внешнего источника API (Stripe) в API-платформе.

Что мне нужно сделать, так это вернуть список подписокдля указанного клиента.Таким образом, переход к http://localhost/api/subscriptions?customer=123foo вернет все записи, соответствующие этому клиенту.

Теперь приведенный ниже код вызывает ошибку из-за ORM \ Filter и будет работать без нее, как фактическая фильтрация.выполняется на Stripes API, а не мной, НО, я действительно хочу, чтобы графический интерфейс Swagger-API имел поле фильтра.

Короче говоря, как получить аннотации в моей сущности для отображения полей с возможностью поиска в интерфейсе Swagger при использовании внешнего источника данных.

То, что у меня есть, - это сущность, как показано ниже (упрощеннодля примера):

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use Symfony\Component\Serializer\Annotation\Groups;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Annotation\ApiFilter;

/**
 * Subscriptions allow you to charge a customer on a recurring basis. A subscription ties a customer to a particular plan you've created.
 * @ApiResource()
 * @ApiFilter(SearchFilter::class, properties={"customer": "exact"})
 * @package App\Entity
 */
class Subscription
{
     /**
     * Unique identifier for the object.
     * @ApiProperty(identifier=true)
     * @var string | null
     */
    protected $id; 

    /**
     * ID of the customer who owns the subscription.
     * @var string | null
     */
    protected $customer;

    // Plus a bunch more properties and their Getters & Setters
}

И SubscriptionCollectionDataProvider:

<?php

namespace App\DataProvider;

use App\Entity\Subscription;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Controller\BaseController;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Class SubscriptionCollectionDataProvider
 * @package App\DataProvider
 * @author dhayward
 */
final class SubscriptionCollectionDataProvider extends BaseController implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{

    protected $requestStack;

    /**
     * SubscriptionCollectionDataProvider constructor.
     * @param RequestStack $requestStack
     */
    public function __construct(RequestStack $requestStack)
    {
        $this->request = $requestStack->getCurrentRequest();
    }

    /**
     * @param string $resourceClass
     * @param string|null $operationName
     * @param array $context
     * @return bool
     */
    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Subscription::class === $resourceClass;
    }

    /**
     * @param string $resourceClass
     * @param string|null $operationName
     * @return \Generator
     * @throws \Stripe\Error\Api
     */
    public function getCollection(string $resourceClass, string $operationName = null): \Generator
    {
        $customer = $this->request->get("customer");

        $data = \Stripe\Subscription::all(["customer" => $customer]);

        foreach($data['data'] as $subscriptionObject){
            $this->serializer()->deserialize(json_encode($subscriptionObject), Subscription::class, 'json', array('object_to_populate' => $subscription = new Subscription()));
            yield $subscription;
        }
    }

}

Результат ошибки, предположительно потому, что я использую ORM / Filter без какой-либо настройки ORM:

Вызов функции-члена getClassMetadata () со значением NULL

Будем весьма благодарны за любые указатели.

1 Ответ

0 голосов
/ 25 сентября 2018

Так что мне наконец удалось это решить.Это было так же просто, как создание собственной версии SearchFilter, реализация ApiPlatform\Core\Api\FilterInterface.

<?php

namespace App\Filter;

use ApiPlatform\Core\Api\FilterInterface;

/**
 * Class SearchFilter
 * @package App\Filter
 */
class SearchFilter implements FilterInterface
{
    /**
     * @var string Exact matching
     */
    const STRATEGY_EXACT = 'exact';

    /**
     * @var string The value must be contained in the field
     */
    const STRATEGY_PARTIAL = 'partial';

    /**
     * @var string Finds fields that are starting with the value
     */
    const STRATEGY_START = 'start';

    /**
     * @var string Finds fields that are ending with the value
     */
    const STRATEGY_END = 'end';

    /**
     * @var string Finds fields that are starting with the word
     */
    const STRATEGY_WORD_START = 'word_start';

    protected $properties;

    /**
     * SearchFilter constructor.
     * @param array|null $properties
     */
    public function __construct(array $properties = null)
    {
        $this->properties = $properties;
    }

    /**
     * {@inheritdoc}
     */
    public function getDescription(string $resourceClass): array
    {
        $description = [];

        $properties = $this->properties;

        foreach ($properties as $property => $strategy) {

                $filterParameterNames = [
                    $property,
                    $property.'[]',
                ];

                foreach ($filterParameterNames as $filterParameterName) {
                    $description[$filterParameterName] = [
                        'property' => $property,
                        'type' => 'string',
                        'required' => false,
                        'strategy' => self::STRATEGY_EXACT,
                        'is_collection' => '[]' === substr($filterParameterName, -2),
                    ];
                }
            }

        return $description;
    }

}
...