Reputation: 142
I'm currently having trouble with shutting down some validation constraints if a certain option is selected in the form. This option is not related to the model and is not set using the data_class
option.
My form contains two embedded address forms which are exactly the same as in one invoice address and one shipment address. If the alternative option is selected, I want to make the shipment address form required through validation. If no alternative option is selected the shipment address form requires no validation and needs to be left alone.
CustomerCheckoutForm
class CustomerCheckoutForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'hidden')
->add('firstName', 'text')
->add('nameAdditions', 'text')
->add('lastName', 'text')
->add('gender', 'choice', array('expanded' => true, 'choices' => array('m' => 'M', 'f' => 'F')))
->add('birthDate', 'date', array(
'required' => true,
'input' => 'string',
'widget' => 'choice',
'years' => range(DATE_CURRENT_YEAR - 80, DATE_CURRENT_YEAR - 18),
'empty_value' => array('year' => 'Year', 'month' => 'Month', 'day' => 'Day')
))
->add('invoiceAddress', new AddressForm($options['countryMapper']), array(
'label' => false,
'required' => true,
))
->add('alternative_shipment_address', 'choice', array(
'expanded' => true,
'choices' => array(0 => 'Delivery on the current address', 1 => 'Alternative shipping address'),
'mapped' => false,
'required' => true,
'label' => 'Delivery address',
'data' => 0,
))
->add('shipmentAddress', new AddressForm($options['countryMapper']), array(
'label' => false,
'required' => false,
))
->add('Continue', 'submit');
$this->registerListeners($builder);
}
private function registerListeners(FormBuilderInterface $builder)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
$customer = $event->getData();
$form = $event->getForm();
if (!$customer || $customer->getId() === null) {
$form->add('password', 'password');
}
});
}
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'EHV\SharedBundle\Model\Customer',
'countryMapper' => null,
'validation_groups' => array(
'Default',
'checkout',
),
));
}
public function getName()
{
return 'customerCheckout';
}
}
AddressForm
class AddressForm extends AbstractType
{
private $countryMapper;
public function __construct(CountryMapper $countryMapper)
{
$this->countryMapper = $countryMapper;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new CountryToIdTransformer($this->countryMapper);
$countries = $this->countryMapper->getAll();
$data[''] = 'Make a choice...';
/** @var Country $country */
foreach ($countries as $country) {
$data[$country->getId()] = $country->getName();
}
$builder
->add('id', 'hidden')
->add('streetName', 'text')
->add('streetNumber', 'text')
->add('streetNumberAddition', 'text')
->add('postalCode', 'text')
->add('city', 'text')
->add(
$builder->create('country', 'choice', array('choices' => $data))
->addModelTransformer($transformer)
);
}
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'EHV\SharedBundle\Model\Address',
));
}
public function getName()
{
return 'address';
}
}
Both models have their own constraints set through the function:
public static function loadValidatorMetadata(ClassMetaData $metadata) {}
Upvotes: 2
Views: 280
Reputation: 142
I managed to use a Form event listener
with the Constraint Callback
answered by Hpatoio, details below.
CustomerCheckoutForm
$builder->addEventListener(FormEvents::SUBMIT, function(FormEvent $event) {
$form = $event->getForm();
$customer = $event->getData();
if ($form->get('alternative_shipment_address')->getData() === 0) {
$customer->setShipmentAddress(null);
}
});
CustomerConstraint
$callback = function($customer) use ($metadata) {
$metadata->addPropertyConstraint('invoiceAddress', new Valid());
/** @var Customer $customer */
if ($customer->getShipmentAddress() !== null) {
$metadata->addPropertyConstraint('shipmentAddress', new Valid());
}
};
$metadata->addConstraint(new Callback($callback));
Credits to Hpatoio for pointing out the right direction.
Upvotes: 0
Reputation: 1815
Checkout Callback constraints http://symfony.com/doc/current/reference/constraints/Callback.html
You can read the value of your addresses and rise error if needed.
Upvotes: 1