如何解决DocQrine Embedded无法与GraphQLApi平台一起显示
我在教义和Api平台之间有问题
我希望对序列化嵌入/可嵌入的学说有所帮助。
从现在开始,我们将Api平台与REST方法一起使用,但是我们希望使用GraphQL创建一个项目,但是某些字段没有显示。
我在https://github.com/tattali/apip-graphql
处建立了测试库当我查询
{
__type(name: "User") {
name
fields {
name
}
}
}
我只得到未嵌入的字段
{
"data": {
"__type": {
"name": "User","fields": [
{
"name": "id"
},{
"name": "_id"
},{
"name": "firstname"
},{
"name": "lastname"
}
]
}
}
}
这是我的实体
<?PHP
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation as Api;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @Api\ApiResource
* @ORM\Entity(repositoryClass=UserRepository::class)
*/
class User
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string",length=255)
*/
private $firstname;
/**
* @ORM\Column(type="string",length=255)
*/
private $lastname;
/**
* @ORM\Embedded(class="App\Entity\Remuneration")
*/
private $actualRemuneration;
/**
* @ORM\Embedded(class="App\Entity\Remuneration")
*/
private $expectedRemuneration;
public function __construct()
{
$this->actualRemuneration = new Remuneration();
$this->expectedRemuneration = new Remuneration();
}
public function getId(): ?int
{
return $this->id;
}
public function getFirstname(): ?string
{
return $this->firstname;
}
public function setFirstname(string $firstname): self
{
$this->firstname = $firstname;
return $this;
}
public function getLastname(): ?string
{
return $this->lastname;
}
public function setLastname(string $lastname): self
{
$this->lastname = $lastname;
return $this;
}
public function getActualRemuneration(): ?Remuneration
{
return $this->actualRemuneration;
}
public function setActualRemuneration(Remuneration $actualRemuneration): self
{
$this->actualRemuneration = $actualRemuneration;
return $this;
}
public function getExpectedRemuneration(): ?Remuneration
{
return $this->expectedRemuneration;
}
public function setExpectedRemuneration(Remuneration $expectedRemuneration): self
{
$this->expectedRemuneration = $expectedRemuneration;
return $this;
}
}
<?PHP
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Embeddable
*/
class Remuneration
{
/**
* @ORM\Column(type="integer",nullable=true)
*/
private $fixedSalary;
/**
* @ORM\Column(type="integer",nullable=true)
*/
private $fullPackage;
public function getFixedSalary(): ?int
{
return $this->fixedSalary;
}
public function setFixedSalary(?int $fixedSalary): self
{
$this->fixedSalary = $fixedSalary;
return $this;
}
public function getFullPackage(): ?int
{
return $this->fullPackage;
}
public function setFullPackage(?int $fullPackage): self
{
$this->fullPackage = $fullPackage;
return $this;
}
}
解决方法
我通过创建自定义GraphQL类型和规范化器找到了一个黑客解决方案
这并不完美,但可以满足基本需求
# config/services.yaml
services:
# ...
App\GraphQL\Type\EmbeddedObjectType:
tags:
- { name: api_platform.graphql.type }
App\GraphQL\Type\TypeConverter:
decorates: api_platform.graphql.type_converter
// src/GraphQL/Type/EmbeddedObjectType.php
<?php
declare(strict_types=1);
namespace App\GraphQL\Type;
use ApiPlatform\Core\GraphQl\Type\Definition\TypeInterface;
use GraphQL\Error\Error;
use GraphQL\Language\AST\ObjectValueNode;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Utils\AST;
use GraphQL\Utils\Utils;
final class EmbeddedObjectType extends ScalarType implements TypeInterface
{
const NAME = 'EmbeddedObject';
public function __construct()
{
$this->name = 'EmbeddedObject';
$this->description = 'The `EmbeddedObject` scalar type represents file metadata data.';
parent::__construct();
}
public function getName(): string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function serialize($value)
{
if (\is_array($value)) {
return $value;
}
if (!\is_object($value)) {
throw new Error(sprintf('Value must be an instance of %s to be represented by `EmbeddedObject`: %s','object',Utils::printSafe($value)));
}
}
/**
* {@inheritdoc}
*/
public function parseValue($value): object
{
if (!\is_object($value)) {
throw new Error(sprintf('`EmbeddedObject` could not parse: %s',Utils::printSafe($value)));
}
return $value;
}
/**
* {@inheritdoc}
*/
public function parseLiteral($valueNode,array $variables = null)
{
if ($valueNode instanceof ObjectValueNode) {
return AST::valueFromASTUntyped($valueNode,$variables);
}
// Intentionally without message,as all information already in wrapped Exception
throw new \Exception();
}
}
// src/GraphQL/Type/TypeConverter.php
<?php
declare(strict_types=1);
namespace App\GraphQL\Type;
use ApiPlatform\Core\GraphQl\Type\TypeConverterInterface;
use Doctrine\ORM\EntityManagerInterface;
use GraphQL\Type\Definition\Type as GraphQLType;
use Symfony\Component\PropertyInfo\Type;
final class TypeConverter implements TypeConverterInterface
{
private $typeConverter;
private $entityManager;
public function __construct(
TypeConverterInterface $typeConverter,EntityManagerInterface $entityManager
) {
$this->typeConverter = $typeConverter;
$this->entityManager = $entityManager;
}
/**
* {@inheritdoc}
*/
public function convertType(Type $type,bool $input,?string $queryName,?string $mutationName,string $resourceClass,string $rootResource,?string $property,int $depth)
{
if (false !== strpos((string) $resourceClass,'App\\Entity\\')) {
$metadata = $this->entityManager->getClassMetadata($resourceClass);
if ($metadata->isEmbeddedClass) {
return EmbeddedObjectType::NAME;
}
}
return $this->typeConverter->convertType($type,$input,$queryName,$mutationName,$resourceClass,$rootResource,$property,$depth);
}
public function resolveType(string $type): ?GraphQLType
{
return $this->typeConverter->resolveType($type);
}
}
// src/Serializer/Normalizer/EmbeddedNormalizer.php
<?php
declare(strict_types=1);
namespace App\Serializer\Normalizer;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
class EmbeddedNormalizer implements ContextAwareNormalizerInterface,NormalizerAwareInterface
{
use NormalizerAwareTrait;
const FORMAT = 'graphql';
private $entityManager;
private $propertyAccessor;
private $metadata;
public function __construct(
EntityManagerInterface $entityManager
) {
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
$this->entityManager = $entityManager;
}
public function normalize($data,$format = null,array $context = [])
{
$array = [];
foreach ($this->metadata->fieldNames as $name) {
$this->propertyAccessor->setValue(
$array,"[{$name}]",$this->normalizer->normalize($this->propertyAccessor->getValue($data,$name),$format,$context)
);
}
return $array;
}
public function supportsNormalization($data,array $context = [])
{
if (
self::FORMAT === $format && \is_object($data) && false !== strpos(\get_class($data),'App\\Entity\\')
) {
$this->metadata = $this->entityManager->getClassMetadata(\get_class($data));
if ($this->metadata->isEmbeddedClass) {
return true;
}
}
return false;
}
}
就像我查询时一样
{
user (id: "/api/users/1") {
lastname
actualRemuneration
}
}
它呈现
{
"data": {
"user": {
"lastname": "lastname 0","actualRemuneration": {
"fixedSalary": 190,"fullPackage": 198
}
}
}
}
,
您在哪里定义类型?
App\GraphQL\Type\EmbeddedObjectType:
tags:
- { name: api_platform.graphql.type }
App\GraphQL\Type\TypeConverter:
decorates: api_platform.graphql.type_converter
,
对于那些有困难的人,我需要进行这些更改和设置。
// src/GraphQL/Type/EmbeddedObjectType.php
...
#50 if (\is_array($value)) {
#51 $value = (object) $value;
#52 }
#55 throw new Error(sprintf('`EmbeddedObject` could not parse: %s',Utils::printSafeJson($value)));
...
并添加服务:
// config/services.yaml
...
App\Serializer\Normalizer\EmbeddedNormalizer:
decorates: "api_platform.serializer.normalizer.item"
arguments: ["@doctrine.orm.entity_manager"]
...
如果您使用其他路径/命名空间(不是 App \ Entity ),例如: App \ Embeddable :
// src/GraphQL/Type/TypeConverter.php
...
#30 if (false !== strpos((string) $resourceClass,'App\\Entity\\') || false !== strpos((string) $resourceClass,'App\\Embeddable\\')) {
...
// src/Serializer/Normalizer/EmbeddedNormalizer.php
...
#48 self::FORMAT === $format && \is_object($data) && (false !== strpos(\get_class($data),'App\\Entity\\') || false !== strpos(\get_class($data),'App\\Embeddable\\'))
...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。