Php 级联验证在表单的第三层不起作用

Php 级联验证在表单的第三层不起作用,php,symfony,symfony-forms,symfony-2.1,Php,Symfony,Symfony Forms,Symfony 2.1,我有一个包含3层的表单: 第一层是游戏的容器: class GameListType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('games', 'collection', array( 'required' => false, '

我有一个包含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',
        ));
    }

}
第三层是下注的形式:

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();
    }
}
但是表单输入仍然保留到数据库中

所以我有两个问题:

  • 如果对表单的下注失败(我不希望整个表单无效,因为3次下注中只能有1次无效),如何获得错误

  • 为什么即使我不调用
    $em persist($bet)
    ,赌注仍然存在,这是绑定中发生的魔法吗


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

    我很确定你应该坚持
    游戏
    实体,而不是
    下注
    实体


    对于验证检查,如果有一些验证组设置,这可能是验证不正确的原因。

    您只是忘记了将
    cascade\u验证添加到游戏
    collection
    类型中

    $builder->add('games', 'collection', array(
        'required' => false,
        'allow_add' => true,
        'prototype' => true,
        'by_reference' => false,
        'type' => new GameBetType(),
        'cascade_validation' => true
    ));
    

    还请提供类AbstractType它是symfony2默认的AbstractType:我有一个双向关系,但两边都没有cascade={persist]。刷新在循环之外,可能是我复制错了。在这种形式下,只提交赌注,游戏以前存在过,没有更改。并且没有验证组。