5

I'm working on a Form in Symfony (2.6). The user can select a free product, which will be shipped to the user. The user has to fill in some personal details and his address (obligated). If he wants to specify another delivery address, he checks a checkbox that is not mapped to an Entity, and completes the delivery address. Now, I want to submit the form, and only validate the delivery address fields if the user has checked this checkbox. How can this be done?

The address Fields and the Delivery Address Fields use the same Form Class mapped to the same Entity. I Use a YAML-file for my constraints.

(part of) validation.yml:

AppBundle\Entity\Address:
    properties:
        street:
          - NotBlank: { message: "Please fill in your first name." }
          - Length:
              min: 3
              max: 256
              minMessage: "Please fill in your street name."
              maxMessage: "Please fill in your street name."
        number:
          - NotBlank: { message: "Please fill in your house number." }
          - Length:
              min: 1
              max: 10
              minMessage: "Please fill in your house number."
              maxMessage: "Please fill in your house number."
        postCode:
          - NotBlank: { message: "Please fill in your postal code." }
          - Length:
              min: 2
              max: 10
              minMessage: "Please fill in your postal code."
              maxMessage: "Please fill in your postal code."
        city:
          - NotBlank: { message: "Please fill in your city." }
          - Length:
              min: 2
              max: 256
              minMessage: "Please fill in your city."
              maxMessage: "Please fill in your city."
          - Type:
              type: alpha
              message: "Please fill in your city."
        country:
          - NotBlank: { message: "Please select your country." }
          - Country: ~

AppBundle\Entity\Product:
    properties:
      product:
        - NotBlank: { message: "Please select your product." }
        - Type:
            type: integer
            message: "Please select your product."
      contact:
          - Type:
              type: AppBundle\Entity\Contact
          - Valid: ~
      deliveryAddress:
          - Type:
              type: AppBundle\Entity\Address
          - Valid: ~

Product Form Class:

    <?php

class ProductFormType extends AbstractType
{

    /**
     *
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Product'
        ));
    }

    /**
     * Returns the name of this type.
     *
     * @return string The name of this type
     */
    public function getName()
    {
        return 'product';
    }


    /**
     *
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('contact', new ContactFormType()); //CONTACTFORMTYPE also has an AddressFormType for the Address Fields

        $builder->add('differentDeliveryAddress', 'checkbox', array( //delivery address is only specific for this Form
            'label'     => 'Different Shipping Address',
            'required'  => false,
            'mapped'    => false
        ));
        $builder->add('deliveryAddress', new AddressFormType());

        //specific

        $builder->add('product', 'choice', array(
            'choices' => array('a'=>'product x','b' => 'product y'),
            'required' => true,
            'invalid_message' => 'This field is required',
            'label' => 'Your Free Product',
        ));

        $builder->add('submit', 'button', array('label' => 'Submit'));
    }
}

Finally the getProductFormAction in My Controller

   public function getProductFormAction(Request $request)
{

    $product = new Product();
    $form    = $this->get('form.factory')->create(new ProductFormType($product);

    $form->handleRequest($request);

    if($form->isValid()){
        return new Response('Success'); //just to test
    }

    return $this->render(
        'productForm.html.twig',
        array(
            'pageTitle'   => 'Test',
            'form'        => $form->createView()
        )
    );
}
1

2 Answers 2

11

This can relatively easily be achieved through groups.

First, add groups to the fields you only want to validate on certain occasions (your delivery address) fields.

street:
      - NotBlank: 
          message: "Please fill in your first name."
          groups: [delivery]
      - Length:
          min: 3
          max: 256
          minMessage: "Please fill in your street name."
          maxMessage: "Please fill in your street name."
          groups: [delivery]

Now that these validations are in a specific group, they will not be validated unless explicitly told to do so.

So now, we let the form determine when to validate this group.

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'validation_groups' => function (FormInterface $form) {
            $data = $form->getData();

            if ($data->differentDeliveryAddress()) {
                return array('Default', 'delivery');
            }

            return array('Default');
        },
    ));
}

Here the form will always validate the 'Default' group (all validations without any groups set), and will also validate the 'delivery' group when differentDeliveryAddress is set.

Hope this helps

Sign up to request clarification or add additional context in comments.

Comments

0

There is also a lot of material in the Symfony docs about dynamic forms and entity/form validation groups that should point you in the right direction; e.g:

This use case seems to come up a lot on SO. I'd suggest doing a quick search for to see if you can unearth a similar question.

Hope this helps :)

1 Comment

I Read both chapters, and I tried to implement a solution using an eventListener for my checkbox and using validation groups. Maybe I did something wrong, but the validator kept using the validation for the Main Address Type. I'll use a classic php 'is the checkbox checked' -solution. Thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.