【问题标题】:Api Platform validation group not working in UniqueEntity constraintApi 平台验证组在 UniqueEntity 约束中不起作用
【发布时间】:2021-05-09 00:18:04
【问题描述】:

我正在尝试插入重复键来测试UniqueEntity 约束。如果通过post 操作执行它,它工作正常。

如果我尝试通过add_association 执行此操作,则在执行$customer 属性上的@Assert\Valid 约束时,将跳过UniqueEntity 约束(即使它具有正确的验证组),它必须这样做。 ..有什么想法吗?

/**
 * @ApiResource(normalizationContext={"groups"={"user-customer:read"}, "skip_null_values"=false},
 *              denormalizationContext={"groups"={"user-customer:write"}},
 *              collectionOperations={
 *                  "get"={
 *                      "openapi_context"={
 *                          "summary"="Recupera la lista di associazioni.",
 *                          "description"="Recupera la lista delle associazioni.<br>
                               Se l'operazione è eseguita <b>dagli operatori del backoffice (ROLE_BACKOFFICE)</b> non ha
                               restrizioni.<br>
                               Per un utente (ROLE_USER) recupera solo le proprie associazioni attualmente verificate."
 *                      }
 *                  },
 *                  "post"={
 *                      "security"="is_granted('ROLE_BACKOFFICE')",
 *                      "validation_groups"={"Insert"},
 *                      "denormalization_context"={"groups"={"user-customer:write"}},
 *                      "input"=UserCustomerAssociationInputDto::class,
 *                      "openapi_context"={
 *                          "summary"="Crea un'associazione.",
 *                          "description"="Permette la creazione di un'associazione User/Customer e la rende attiva
                                <b>agli operatori del backoffice (ROLE_BACKOFFICE)</b>.<br>
                                Questo metodo non invia alcun sms con il codice di verifica all'utente, in quanto
                                deve venire utilizzato direttamente dagli operatori."
 *                      }
 *                  },
 *                  "add_association"={
 *                      "method"="POST",
 *                      "controller"=AddUserCustomerAssociation::class,
 *                      "path"="/user_customer_associations/add_association",
 *                      "validation_groups"={"UserCustomerAssociation:Add"},
 *                      "denormalization_context"={"groups"={"user-customer:write"}},
 *                      "input"=UserCustomerAssociationInputDto::class,
 *                      "openapi_context"={
 *                          "summary"="Aggiunge un'associazione.",
 *                          "description"="Aggiunge un'associazione User/Customer e invia un codice di attivazione
                                ad uno dei contatti di Customer (Cliente).<br>
                                L'associazione viene bloccata se Customer non ha nessun contatto (email o telefono)
                                impostato come <em>main</em>."
 *                      }
 *                  }
 *              })
 * @ORM\Table(name="security_utente_cliente",
 *     uniqueConstraints={@ORM\UniqueConstraint(name="unique_association", columns={"utente_id", "cliente_id"})})
 * @ORM\Entity(repositoryClass=UserCustomerAssociationRepository::class)
 * @ORM\HasLifecycleCallbacks
 * @ActiveEntityAware(activeFieldName="verificato", rolesToExclude={"ROLE_BACKOFFICE"})
 * @UniqueEntity(fields={"user", "customer"},
 *     errorPath="customer",
 *     message="Questo codice cliente è già associato all'utente",
 *     groups={"Insert","UserCustomerAssociation:Add"})
 */
class UserCustomerAssociation
{
    /**
     * Identificativo univoco dell'utente (Uuid) di 36 caratteri.
     *
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class=UuidGenerator::class)
     * @Groups({"user-customer:read", "user:read"})
     */
    private ?UuidInterface $id = null;
    /**
     * Utente a cui appartiene l'associazione.
     *
     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="userCustomerAssociations")
     * @ORM\JoinColumn(name="utente_id", nullable=false, onDelete="CASCADE")
     * @Groups({"user-customer:read", "user-customer:write"})
     */
    private ?User $user;
    /**
     * Il cliente associato all'utente.
     *
     * @ORM\ManyToOne(targetEntity=Customer::class)
     * @ORM\JoinColumn(name="cliente_id", nullable=false, onDelete="CASCADE")
     * @Groups({"user-customer:read", "user-customer:write", "user:read"})
     * @Assert\Valid(groups={"UserCustomerAssociation:Add"})
     */
    private ?Customer $customer;
}

Dto 验证在这两种情况下都可以正常工作。

namespace App\Dto\Security;

use App\Validator\Constraints as AppAssert;
use Symfony\Component\Serializer\Annotation\Groups;


class UserCustomerAssociationInputDto
{
    /**
     * Id dell'utente per creare l'associazione
     *
     * @var null|string
     * @Groups({"user-customer:write"})
     * @AppAssert\UserExists
     */
    public ?string $userId;

    /**
     * Codice cliente da associare
     *
     * @var null|string
     * @Groups({"user-customer:write"})
     * @AppAssert\CustomerExists
     */
    public ?string $customerCode;
}

这是变压器

use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\Entity\Data\Customer;
use App\Entity\Security\User;
use App\Entity\Security\UserCustomerAssociation;
use Doctrine\ORM\EntityManagerInterface;
use ApiPlatform\Core\Validator\ValidatorInterface;

class UserCustomerAssociationInputDataTransformer implements DataTransformerInterface
{
    private EntityManagerInterface $entityManager;
    private ValidatorInterface $validator;

    public function __construct(EntityManagerInterface $entityManager,
                                ValidatorInterface $validator)
    {
        $this->entityManager = $entityManager;
        $this->validator = $validator;
    }

    /**
     * @inheritDoc
     */
    public function transform($object, string $to, array $context = [])
    {
        $this->validator->validate($object);

        $userCustomerAssociation = new UserCustomerAssociation();

        $user = $this->entityManager
            ->getRepository(User::class)
            ->find($object->userId);

        $customer = $this->entityManager
            ->getRepository(Customer::class)
            ->findOneBy(['code' => $object->customerCode]);

        $userCustomerAssociation->setUser($user);
        $userCustomerAssociation->setCustomer($customer);

        return $userCustomerAssociation;
    }

    /**
     * @inheritDoc
     */
    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        // in the case of an input, the value given here is an array (the JSON decoded).
        // if it's a book we transformed the data already
        if ($data instanceof UserCustomerAssociation) {
            return false;
        }

        return UserCustomerAssociation::class === $to && null !== ($context['input']['class'] ?? null);
    }
}

【问题讨论】:

    标签: php symfony validation api-platform.com


    【解决方案1】:

    那是因为您需要通过正确的验证组 - 与核心验证器一样:

    https://github.com/api-platform/core/blob/359baae7871d7ba7a6869f8fdae5cf771133c308/src/Validator/EventListener/ValidateListener.php#L65-L68

    您的 DTO 转换应如下所示:

    <?php declare(strict_types=1);
    
    use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
    use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
    use App\Entity\Data\Customer;
    use App\Entity\Security\User;
    use App\Entity\Security\UserCustomerAssociation;
    use Doctrine\ORM\EntityManagerInterface;
    use ApiPlatform\Core\Validator\ValidatorInterface;
    
    class UserCustomerAssociationInputDataTransformer implements DataTransformerInterface
    {
        private EntityManagerInterface $entityManager;
        private ValidatorInterface $validator;
        private ResourceMetadataFactoryInterface $resourceMetadataFactory;
    
        public function __construct(
            EntityManagerInterface $entityManager,
            ValidatorInterface $validator,
            ResourceMetadataFactoryInterface $resourceMetadataFactory
        ) {
            $this->entityManager = $entityManager;
            $this->validator = $validator;
            $this->resourceMetadataFactory = $resourceMetadataFactory;
        }
    
        public function transform($object, string $to, array $context = []): UserCustomerAssociation
        {
            $resourceMetadata = $this->resourceMetadataFactory->create($context['resource_class']);
            $validationGroups = $resourceMetadata->getOperationAttribute($context, 'validation_groups', null, true);
    
            $this->validator->validate($object, ['groups' => $validationGroups]);
    
            $userCustomerAssociation = new UserCustomerAssociation();
    
            $user = $this->entityManager
                ->getRepository(User::class)
                ->find($object->userId);
    
            $customer = $this->entityManager
                ->getRepository(Customer::class)
                ->findOneBy(['code' => $object->customerCode]);
    
            $userCustomerAssociation->setUser($user);
            $userCustomerAssociation->setCustomer($customer);
    
            return $userCustomerAssociation;
        }
    
        public function supportsTransformation($data, string $to, array $context = []): bool
        {
            // in the case of an input, the value given here is an array (the JSON decoded).
            // if it's a book we transformed the data already
            if ($data instanceof UserCustomerAssociation) {
                return false;
            }
    
            return UserCustomerAssociation::class === $to && null !== ($context['input']['class'] ?? null);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-11
      • 2021-01-25
      相关资源
      最近更新 更多