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?
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.
In general, there are two main types of form validation: After submit validation. Inline validation.
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.
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
));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With