Symfony2 - Validation not working for embedded Form Type

php, symfony

Solution

I spent an age searching and found that it was adding `'cascade_validation' => true` to the `setDefaults()` array in my parent type's class that fixed it (as mentioned already in the thread). This causes the entity constraint validation to trigger in the child types shown in the form. e.g.

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(            
        ...
        'cascade_validation' => true,
    ));
}

For collections, also make sure to add `'cascade_validation' => true` to the `$options` array for the collection field on the form. e.g.

$builder->add('children', 'collection', array(
    'type'         => new ChildType(),
    'cascade_validation' => true,
));

This will have the UniqueEntity validation take place as it should in the child entity used in the collection.

Problem

I have a form that combines two entities (User and Profile). Validation seems to work on the first part of the form that comes form the User Entity and is the basis of the form. The ProfileType is included inside the UserType. The form renders correctly and displays the correct information, so it seems it is properly connected to the Profile entity. It's just the validation that is broken on the ProfileType. Any idea as to why one part would validate and the other wouldn't? Code below: Validation.yml ``` DEMO\DemoBundle\Entity\User\Profile: properties: address1: - NotBlank: { groups: [profile] } name: - NotBlank: { groups: [profile] } companyName: - NotBlank: { groups: [profile] } DEMO\DemoBundle\Entity\User\User: properties: username: - NotBlank: groups: profile message: Username cannot be left blank. email: - NotBlank: groups: profile message: Email cannot be left blank - Email: groups: profile message: The email "{{ value }}" is not a valid email. checkMX: true password: - MaxLength: { limit: 20, message: "Your password must not exceed {{ limit }} characters." } - MinLength: { limit: 4, message: "Your password must have at least {{ limit }} characters." } - NotBlank: ~ ``` UserType.php ``` namespace DEMO\DemoBundle\Form\Type\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackValidator; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; use DEMO\DemoBundle\Form\Type\User\ProfileType; class UserType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('username'); $builder->add('email'); $builder->add('profile', new ProfileType()); } public function getDefaultOptions(array $options) { return array( 'data_class' => 'DEMO\DemoBundle\Entity\User\User', 'validation_groups' => array('profile') ); } public function getName() { return 'user'; } } ``` ProfileType.php ``` namespace DEMO\DemoBundle\Form\Type\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackValidator; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; class ProfileType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('name'); $builder->add('companyName', null, array('label' => 'Company Name')); $builder->add('address1', null, array('label' => 'Address 1')); $builder->add('address2', null, array('label' => 'Address 2')); $builder->add('city'); $builder->add('county'); $builder->add('postcode'); $builder->add('telephone'); } public function getDefaultOptions(array $options) { return array( 'data_class' => 'DEMO\DemoBundle\Entity\User\Profile', ); } public function getName() { return 'profile'; } } ``` Controller ``` $user = $this->get('security.context')->getToken()->getUser(); $form = $this->createForm(new UserType(), $user); if ($request->getMethod() == 'POST') { $form->bindRequest($request); if ($form->isValid()) { // Get $_POST data and submit to DB $em = $this->getDoctrine()->getEntityManager(); $em->persist($user); $em->flush(); // Set "success" flash notification $this->get('session')->setFlash('success', 'Profile saved.'); } } return $this->render('DEMODemoBundle:User\Dashboard:profile.html.twig', array('form' => $form->createView())); ```

Original source