Reputation: 2936
I have a form which contains three objects:
$builder
->add('customer', new CustomerType())
->add('shippingAddress', new AddressType())
->add('billingAddress', new AddressType())
->add('sameAsShipping', 'checkbox', ['mapped' => false])
;
Each of the embedded forms has their own validation constraints and they work. In my main form, I have cascade_validation => true
so that all of the embedded form validation constraints are applied. This also works.
I am having trouble 'disabling' the validation on the billingAddress
form if the sameAsShipping
checkbox is enabled. I can't make the validation in the AddressType form conditional because it always needs to be enforced for the shippingAddress form.
Upvotes: 3
Views: 1095
Reputation: 1697
Create a form model (I use it in nearly every form, but this code here is not tested):
/**
* @Assert\GroupSequenceProvider()
*/
class YourForm implements GroupSequenceProviderInterface {
/**
* @Assert\Valid()
*/
private $customer;
/**
* @Assert\Valid()
*/
private $shippingAddress;
/**
* @Assert\Valid(groups={'BillingAddressRequired'})
*/
private $billingAddress;
private $billingSameAsShipping;
public function getGroupSequence() {
$groups = ['YourForm'];
if(!$this->billingSameAsShipping) {
$groups[] = 'BillingAddressRequired';
}
return $groups;
}
}
Try to use meaningful names. sameAsShipping
is hard to understand. Read the if-condition in getGroupSequence
: if not billing (address) same as shipping (address) then billing address required.
That's all, clear code in my opinion.
Upvotes: 1
Reputation: 593
I've solved this same problem by using validation groups.
First, this is important: use the validation_groups
option in your AddressType
to set the validation groups of every constraint of each field in the type:
<?php
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Form\FormBuilderInterface;
class AddressType extends \Symfony\Component\Form\AbstractType
{
function buildForm(FormBuilderInterface $builder, array $options)
{
$groups = $options['validation_groups'];
$builder->add('firstName', 'text', ['constraints' => new Assert\NotBlank(['groups' => $groups])]);
$builder->add('lastName', 'text', ['constraints' => new Assert\NotBlank(['groups' => $groups])]);
}
}
Then, in the parent form pass different validation groups to the two fields:
<?php
$formBuilder = $this->get('form.factory')
->createNamedBuilder('checkout', 'form', null, [
'cascade_validation' => true,
])
->add('billingAddress', 'address', [
'validation_groups' => 'billingAddress'
])
->add('shippingAddress', 'address', [
'validation_groups' => 'shippingAddress'
]);
Then, determine determine your validation groups by looking at the value of the checkbox.
if ($request->request->get('sameAsShipping')) {
$checkoutValidationGroups = ['Default', 'billingAddress'];
} else {
$checkoutValidationGroups = ['Default', 'billingAddress', 'shippingAddress'];
}
You can then validate only either the billingAddress
or the shippingAddress
, or both using the validation group mechanism.
I chose to use a button:
$formBuilder->add('submitButton', 'submit', ['validation_groups' => $checkoutValidationGroups]);
Upvotes: 1