ApiPlatform 转换为突变 graphql 上现有实体的最佳方式

问题描述 投票:0回答:1

我有这个用户实体

#[UniqueEntity(fields: ['email'], message: 'email is exists')]
#[ORM\Entity]
#[ORM\Table(name: 'user')]
#[ApiPlatform\ApiResource(
    operations: [],
    graphQlOperations: [
        new ApiPlatform\GraphQl\Query(),
        new ApiPlatform\GraphQl\Mutation(
            name: 'create',
            denormalizationContext: ['groups' => ['request:create', 'shopping:create']],
        ),
    ]
)]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'AUTO')]
    #[ORM\Column(type: 'integer')]
    #[Serializer\Expose]
    protected $id;

    #[Assert\Email(message: 'email not valid')]
    #[ORM\Column(type: 'string', unique: true, length: 150, nullable: true)]
    #[Groups(['request:create', 'shopping:create'])]
    protected $email;
}

这个用于购物

#[ORM\Entity]
#[ApiPlatform\ApiResource(
    operations: [],
    graphQlOperations: [
        new ApiPlatform\GraphQl\Query(),
        new ApiPlatform\GraphQl\Mutation(
            name: 'create',
            denormalizationContext: ['groups' => ['shopping:create']],
        ),
    ]
)]
class Shopping
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private int $id;

    #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'shoppings')]
    #[Groups(['shopping:create'])]
    #[Assert\Valid()]
    private User $user;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    #[Groups(['shopping:create'])]
    private string $name;
}

并像这样执行graphql查询

mutation {
  createShopping(
    input: {
      user: {
        email: "[email protected]"
      }, 
      name: "foo"
    }
  ) {
    shopping {
      id
    }
  }
}

我收到错误“电子邮件已存在”

我尝试编写自定义 reslover 来转换用户实体,以存在这样的实体

final class UserResolver implements MutationResolverInterface
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
    ) {
    }

    public function __invoke($item, array $context): object
    {
        if ($item->getEmail()) {
            $existUser = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $item->getEmail()]);
            if ($existUser) {
                return $existUser;
            }
        }



        return $item;
    }
}

以及购物的自定义解析器,因为解析器不调用级联

final class ShoppingResolver implements MutationResolverInterface
{
    public function __construct(
        private readonly UserResolver $userResolver,
    ) {
    }

    public function __invoke($item, array $context): ?object
    {
        $item->setUser($this->userResolver->__invoke($item->getUser(), $context));

        return $item;
    }
}

如果我从 Shopping 实体中删除 #[Assert\Valid()] ,它就会起作用,因为验证在解析器之前运行。

解决这个问题的最好方法是什么?自定义反规范化器或使用事件系统或其他东西?

symfony graphql api-platform.com
1个回答
0
投票

我做出了这个决定。自定义反规范化器:

<?php

namespace App\Serializer\Denormalizer;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

class UserDenormalizer implements DenormalizerAwareInterface, DenormalizerInterface
{
    use DenormalizerAwareTrait;

    public function __construct(
        private EntityManagerInterface $entityManager,
    ) {
    }

    private const ALREADY_CALLED = 'USER_DENORMALIZER_ALREADY_CALLED';

    public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool
    {
        if (isset($context[self::ALREADY_CALLED])) {
            return false;
        }

        return $type === User::class;
    }

    public function denormalize($data, string $type, string $format = null, array $context = []): mixed
    {
        $context[self::ALREADY_CALLED] = true;

        /** @var User $user */
        $user = $this->denormalizer->denormalize($data, $type, $format, $context);

        $existUser = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $user->getEmail()]);
        if ($existUser) {
            return $existUser;
        }

        return $user;
    }

    public function getSupportedTypes(?string $format): array
    {
        return [];
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.