I'm trying to insert a duplicate key to test the UniqueEntity
constraint. If a do it by the post
operation it works fine.
If i try to do it by the add_association
the UniqueEntity
constraint is skipped (even if it has the right validation group) while the @AssertValid
constraint on the $customer
property is executed has it has to... any idea?
/**
* @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>."
* }
* }
* })
* @ORMTable(name="security_utente_cliente",
* uniqueConstraints={@ORMUniqueConstraint(name="unique_association", columns={"utente_id", "cliente_id"})})
* @ORMEntity(repositoryClass=UserCustomerAssociationRepository::class)
* @ORMHasLifecycleCallbacks
* @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.
*
* @ORMId
* @ORMColumn(type="uuid", unique=true)
* @ORMGeneratedValue(strategy="CUSTOM")
* @ORMCustomIdGenerator(class=UuidGenerator::class)
* @Groups({"user-customer:read", "user:read"})
*/
private ?UuidInterface $id = null;
/**
* Utente a cui appartiene l'associazione.
*
* @ORMManyToOne(targetEntity=User::class, inversedBy="userCustomerAssociations")
* @ORMJoinColumn(name="utente_id", nullable=false, onDelete="CASCADE")
* @Groups({"user-customer:read", "user-customer:write"})
*/
private ?User $user;
/**
* Il cliente associato all'utente.
*
* @ORMManyToOne(targetEntity=Customer::class)
* @ORMJoinColumn(name="cliente_id", nullable=false, onDelete="CASCADE")
* @Groups({"user-customer:read", "user-customer:write", "user:read"})
* @AssertValid(groups={"UserCustomerAssociation:Add"})
*/
private ?Customer $customer;
}
The Dto validation is working fine in both cases.
namespace AppDtoSecurity;
use AppValidatorConstraints as AppAssert;
use SymfonyComponentSerializerAnnotationGroups;
class UserCustomerAssociationInputDto
{
/**
* Id dell'utente per creare l'associazione
*
* @var null|string
* @Groups({"user-customer:write"})
* @AppAssertUserExists
*/
public ?string $userId;
/**
* Codice cliente da associare
*
* @var null|string
* @Groups({"user-customer:write"})
* @AppAssertCustomerExists
*/
public ?string $customerCode;
}
And this is the transformer
use ApiPlatformCoreDataTransformerDataTransformerInterface;
use AppEntityDataCustomer;
use AppEntitySecurityUser;
use AppEntitySecurityUserCustomerAssociation;
use DoctrineORMEntityManagerInterface;
use ApiPlatformCoreValidatorValidatorInterface;
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);
}
}
question from:
https://stackoverflow.com/questions/66050015/api-platform-validation-group-not-working-in-uniqueentity-constraint