Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cascade Validation not working on third layer of a form

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:

  1. 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).

  2. Why is the bet persisted even if I dont call $em-persist($bet), is this some magic that happens with the binding?

like image 470
m0c Avatar asked Aug 26 '12 19:08

m0c


People also ask

What is Cascade validation?

grails-cascade-validation This plugin establishes a 'cascade' constraint property for validateable objects. If "cascade:true" is set on a nested object, the nested object's validate() method will be invoked and the results will be reported as part of the parent object's validation.

What are different types of form validation?

In general, there are two main types of form validation: After submit validation. Inline validation.


2 Answers

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.

like image 182
Mun Mun Das Avatar answered Oct 23 '22 02:10

Mun Mun Das


You just forget to add cascade_validation to games collection type

$builder->add('games', 'collection', array(
    'required' => false,
    'allow_add' => true,
    'prototype' => true,
    'by_reference' => false,
    'type' => new GameBetType(),
    'cascade_validation' => true
));
like image 35
Maciej Pyszyński Avatar answered Oct 23 '22 02:10

Maciej Pyszyński