Как определить классы с платформой API для запроса на вложенных объектах, используя пользовательский поставщик данных без доктрины - PullRequest
0 голосов
/ 02 июня 2019

Я использую Symfony 4 с платформой API 2.4.Я не использую Доктрину и поэтому ни Сущностей.У меня есть два класса (не сущности) Facet и Option.Между ними существует связь, поэтому я определяю параметры атрибута в классе Facet, который является коллекцией Option (например, OneToMany в Doctrine).У меня есть свой пользовательский поставщик данных, потому что я получаю эти данные из внешнего API.Я создаю свою коллекцию фасетов с параметрами в этом пользовательском поставщике данных.

В Graphql Doc параметры являются итеративными, но это должен быть ConnectionOption

id: ID!
_id: Int!
name: String!
options: Iterable!

, поэтому я не могу выполнить graphqlзапрос на вложенный объект, у меня ошибка en: поле "options" не должно иметь выбор, так как тип повторяется!не имеет подполей

{
  facets {
    edges {
      node {
        id
        name
        options {
          edges {
            node {
              id
              value
              count
            }
          }
        }
      }
    }
  }
}

Для информации я попытался использовать аннотацию ORM доктрины, чтобы обойти эту проблему и иметь ConnectionOption вместо итерируемого, и это работает, но когда я выполняю этот запрос graphql, у меня всегда есть пустой массивдля параметров (кажется, что они не сериализованы или даже не существуют)

{
  "data": {
    "facets": {
      "edges": [
        {
          "node": {
            "id": "/api/facets/1",
            "name": "facet [1]",
            "options": []
          }
        }
      ]
    }
  }
}

Вы можете найти мои классы и мой пользовательский провайдер данных

<?php

namespace App\Model;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use \Doctrine\Common\Collections\Collection;

/**
 * @ApiResource()
 * Class Facet
 *
 * @package App\Model
 */
class Facet
{
    /**
     * @ApiProperty(identifier=true)
     * @var int
     */
    private $id;

    /**
     * @var string
     */
    private $name;

    /**
     * @var \App\Model\Option[]
     */
    private $options;

    public function __construct()
    {
        $this->options = new ArrayCollection();
    }

    /**
     * @return int
     */
    public function getId(): int
    {
        return $this->id;
    }

    /**
     * @param int $id
     *
     * @return Facet
     */
    public function setId(int $id): self
    {
        $this->id = $id;

        return $this;
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param string $name
     *
     * @return Facet
     */
    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }


    /**
     * @return Collection|Option[]
     */
    public function getOptions(): Collection
    {
        return $this->options;
    }

    public function addOption(Option $option): self
    {
        if (!$this->options->contains($option)) {
            $this->options[] = $option;
            $option->setFacet($this);
        }

        return $this;
    }

    public function removeOption(Option $option): self
    {
        if ($this->options->contains($option)) {
            $this->options->removeElement($option);
            // set the owning side to null (unless already changed)
            if ($option->getFacet() === $this) {
                $option->setFacet(null);
            }
        }

        return $this;
    }
}

<?php

namespace App\Model;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;

/**
 * Class Option
 *
 * @ApiResource()
 * @package App\Model
 */
class Option
{
    /**
     * @ApiProperty(identifier=true)
     * @var int
     */
    private $id;

    /**
     * @var string
     */
    private $value;

    /**
     * @var int
     */
    private $count;

    /**
     * @var Facet
     */
    private $facet;

    /**
     * @return int
     */
    public function getId(): int
    {
        return $this->id;
    }

    /**
     * @param int $id
     *
     * @return Option
     */
    public function setId(int $id): self
    {
        $this->id = $id;

        return $this;
    }

    /**
     * @return string
     */
    public function getValue(): string
    {
        return $this->value;
    }

    /**
     * @param string $value
     *
     * @return Option
     */
    public function setValue(string $value): self
    {
        $this->value = $value;

        return $this;
    }

    /**
     * @return int
     */
    public function getCount(): int
    {
        return $this->count;
    }

    /**
     * @param int $count
     *
     * @return Option
     */
    public function setCount(int $count): self
    {
        $this->count = $count;

        return $this;
    }

    /**
     * @return Facet
     */
    public function getFacet(): Facet
    {
        return $this->facet;
    }

    /**
     * @param Facet $facet
     *
     * @return Option
     */
    public function setFacet(Facet $facet = null): self
    {
        $this->facet = $facet;

        return $this;
    }
}

and my custom data provider (just and example)
<?php

namespace App\DataProvider;

use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Model\Facet;
use App\Model\Option;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Class FacetDataProvider
 *
 * @package App\DataProvider
 */
final class FacetDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{
    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Facet::class === $resourceClass;
    }

    public function getCollection(string $resourceClass, string $operationName = null)
    {
        $k = 0;
        $collection = new ArrayCollection();
        for ($i = 0; $i < 2; $i++) {
            $facet = new Facet();
            $facet
                ->setId(++$i)
                ->setName("facet [$i]");
            for ($j = 0; $j < 2; $j++) {
                $option = new Option();
                $option
                    ->setId($k++)
                    ->setValue("option [$i] [$j]")
                    ->setCount(rand(0, 10))
                ;
                $facet->addOption($option);
            }

            $collection->add($facet);
        }

        return $collection;
    }
}

Я создаю эти классы как Entity toпоказать ожидаемые результаты для Graphql Doc

id: ID!
_id: Int!
name: String!
options(first: Int after: String): OptionConnection

и при выполнении запроса graphql

{
  facets {
    edges {
      node {
        id
        name
        options {
          edges {
            node {
              id
              count
              value
            }
          }
        }
      }
    }
  }
}

у меня должен быть такой результат, как

{
  "data": {
    "facets": {
      "edges": [
        {
          "node": {
            "id": "/api/facets/1",
            "name": "facet [1]",
            "options": {
              "edges": [
                {
                  "node": {
                    "id": "/api/options/1",
                    "count": 0,
                    "value": "option [1] [0]"
                  }
                },
                {
                  "node": {
                    "id": "/api/options/2",
                    "count": 0,
                    "value": "option [1] [1]"
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Спасибо

...