层级表单中第三层级的级联验证不起作用。

12

我有一个包含3个层的表单: 第一层是游戏容器:

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,
        ));
    }  
}

第二层是游戏本身,因为我不打算改变游戏,而只是在其上下注,它仅包括下注的表单:

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,
        ));
    }  
}

第三层是下注表单:

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',
        ));
    }

}

问题在于,如果第三级有验证约束条件,根表单始终有效,但是如果我专门验证赌注实体,则可以在我的控制器中获得正确的违规列表:
// 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();
    }
}

另一个问题是即使我不调用$em->persist($bet),实体仍然会被持久化。我没有看到第8行描述的输出。
print($bet.'gets persisted<br>'); 

但表单输入仍然被保留在数据库中。

所以我的两个问题:

  1. 如果验证失败,如何获取错误信息并将其传递给表单(我不希望整个表单无效,因为可能只有3个中的1个下注无效)?

  2. 为什么即使我没有调用 $em-persist($bet),下注也会被保留,这是绑定过程中发生的魔术吗?


请提供抽象类AbstractType的类。 - Vineet1982
这是Symfony2默认的AbstractType:https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/AbstractType.php - m0c
3个回答

3
回答你的第二个问题,可能您已经在UserBet实体之间声明了双向OneToMany关系,并在User端的关系上设置了cascade={"persist"}。因此,实体管理器会自动将Bet实体对象标记为下一次flush操作中要插入/更新的对象。同时,将$em->flush();代码移到循环外面。因为flush方法会发出数据库查询,每次进入循环时都会连接到数据库。而如果$em->flush();在循环外面,实体将在单个事务中查询所有更改的SQL语句。

我有一个双向关系,但是在任何一侧都没有cascade={persist]。刷新在循环外面,可能是我复制错了。 - m0c

1
你只是忘记在游戏的集合类型中添加 cascade_validation
$builder->add('games', 'collection', array(
    'required' => false,
    'allow_add' => true,
    'prototype' => true,
    'by_reference' => false,
    'type' => new GameBetType(),
    'cascade_validation' => true
));

0

我相信你应该持久化game实体而不是bet实体。

对于验证,请检查是否设置了某些验证组,这可能是验证不正确的原因。


在这个表单中,只提交投注,游戏之前已经存在且没有改变。并且没有验证组。 - m0c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接