I had to upgrade one of my projects from symfony 2.8 to symfony 3.4, and I noticed a huge change in the validation process.
To simplify let's say I have a User entity, with many Addresses entities. When I create / update my User I want to be able to add / remove / update any number of addresses. So in symfony 2.8 I had this kind of situation
User
I use annotation validators
src/AppBundle/Entity/User.php
//...
class User
{
//...
/**
* @Assert\Count(min=1, max=10)
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Address", mappedBy="user", cascade={"persist", "remove"})
*/
protected $addresses;
//...
}
UserForm
src/AppBundle/Form/UserForm.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('addresses', CollectionType::class, [
'type' => AddressType::class,
'cascade_validation' => true,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
])
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
'cascade_validation' => true,
'validation_groups' => // User's logic
]);
}
Address
src/AppBundle/Entity/Address.php
//...
class Address
{
//...
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="user")
*/
protected $user;
/**
* @Assert\NotBlank(groups={"zipRequired"})
* @ORM\Column(type="text", nullable="true")
*/
protected $zipCode;
//...
}
AddressForm
src/AppBundle/Form/AddressForm.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('zipCode', TextType::class)
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'data_class' => Address::class,
'cascade_validation' => true,
'validation_groups' => function(FormInterface $form) {
/** @var Address $data */
$data = $form->getData();
$validation_groups = [];
// Simplified here, it's a service call with heavy logic
if ($data->doesRequireZip()) {
$validation_groups[] = 'zipRequired';
}
return $validation_groups;
},
]);
}
In symfony 2.8
On 3 addresses added, two have to valid the zipRequired group, one not. I works !
In symfony 3.4
I added @Assert\Valid()
to User::$zipCode declaration and removed the 'cascade_validation' => true
(not in method configureOptions but it seems unused) as it's deprecated.
But now on 3 addresses added, two have should to valid the zipRequired group, and one not : Only User's class validator_groups are used, so I can valid a form with incoherent data !
I checked with xdebug and the validator_groups
callback in AddressForm
is called but validators are not.
I tested the solutions decribed here : Specify different validation groups for each item of a collection in Symfony 2? but it can't work anymore as in symfony 3.4 cascade_validation
on a property throws an error
In my situation the logic involved is too heavy to use a solution ad described here Specify different validation groups for each item of a collection in Symfony 3? as it is very inneficient to rewrite the whole validation_groups
callback in individual methods and it apply the groups on all child entities.
The Behaviour of @Assert\Valid
and cascade_validation
are different, is there a way to handle embed form individual entity validation_groups in symfony 3.4 or the feature is definitely gone ?