Cascade Validation not working on third layer of a form

php, symfony, symfony-2.1, symfony-forms

Solution

To answer your second question, you may have declared bi-directional `OneToMany` relationship between `User` and `Bet` entity and set `cascade={"persist"}` on `User` side of the relation. So entity manager automatically marks `Bet` entity objects for insert/update in next `flush` operation. Also move `$em->flush();` line out of the loop. As `flush` method issues db query, it connects to db every time code enters the loop. Whereas if `$em->flush();` is outside of the loop the entity will query once with all the changed sql wrapped in a single transaction.

Problem

I have a form with 3 layers: First Layer is the container for the games: ``` class GameListType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('games', 'collection', array( 'required' => false, 'allow_add' => true, 'prototype' => true, 'by_reference' => false, 'type' => new GameBetType(), )) ; } public function setDefaultOptions(OptionsResolverInterface $resolver) { parent::setDefaultOptions($resolver); $resolver->setDefaults(array( 'cascade_validation' => true, )); } } ``` Second Layer is the Game itself, since i don't intend to change the game, but the bet on it, it only includes the form for the bet: ``` class GameBetType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('bet', new BetType()); } public function setDefaultOptions(\Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver) { parent::setDefaultOptions($resolver); $resolver->setDefaults(array( 'data_class' => 'Strego\TippBundle\Entity\Game', 'cascade_validation' => true, )); } } ``` And the third layer is the form for the bet: ``` class BetType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('scoreT1' , 'text') ->add('scoreT2' , 'text'); ; } public function setDefaultOptions(\Symfony\Component\OptionsResolver\OptionsResolverInterface $resolver) { parent::setDefaultOptions($resolver); $resolver->setDefaults(array( 'data_class' => 'Strego\TippBundle\Entity\Bet', )); } } ``` The issue is, that if there are validation constraints on the third level, the root form is always valid, but if I specifically validate the bet entity, I get the correct violation list in my controller: ``` // Form processing $form = $this->createForm(new GameListType(), $entity); $request = $this->getRequest(); if ($request->getMethod() == 'POST') { $form->bind($request); $entity = $form->getData(); if ($form->isValid()) { foreach ($entity->getGames() as $game) { if($game->hasBet()){ $bet = $game->getBet(); $bet->setUser($user); $validator = $this->container->get('validator'); $errors = $validator->validate($bet); var_dump($errors) //<-- i see there are errors if(count($errors) == 0){ print($bet. ' gets persisted<br>'); $em->persist($bet); } } } $em->flush(); } } ``` Another issue is that even if I don't call `$em->persist($bet)` the entities gets persisted. I don't see the output described in the line ``` print($bet.'gets persisted<br>'); ``` but the form input is still persisted to the database. So my two questions: How do I get the errors if the validation fails on the bet fails to the form (I don't want the whole form to be invalid, since there could only 1 out of 3 bets be invalid). Why is the bet persisted even if I dont call `$em-persist($bet)`, is this some magic that happens with the binding?

Original source