我有这个用户实体
#[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()] ,它就会起作用,因为验证在解析器之前运行。
解决这个问题的最好方法是什么?自定义反规范化器或使用事件系统或其他东西?
我做出了这个决定。自定义反规范化器:
<?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 [];
}
}