【问题标题】:Cascade Validation not working on third layer of a form级联验证不适用于表单的第三层
【发布时间】:2013-12-12 11:31:22
【问题描述】:

我有一个包含 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-&gt;persist($bet),实体也会被保留。我没有看到

行中描述的输出
print($bet.'gets persisted<br>'); 

但是表单输入仍然保存在数据库中。

所以我的两个问题:

  1. 如果对表单的投注验证失败,我如何得到错误(我不希望整个表单无效,因为 3 个投注中只有 1 个无效)。

  2. 为什么即使我不调用$em-persist($bet),赌注仍然存在,这是绑定时发生的某种魔法吗?

【问题讨论】:

标签: php symfony symfony-forms symfony-2.1


【解决方案1】:

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

【讨论】:

  • 我有双向关系,但双方都没有 cascade={persist]。刷新在循环之外,可能是我复制错了。
【解决方案2】:

您只是忘记将cascade_validation 添加到游戏collection 类型

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

【讨论】:

    【解决方案3】:

    我很确定您应该坚持 game 实体而不是 bet 实体。

    对于验证检查是否有一些验证组设置,这可能是它没有正确验证的原因。

    【讨论】:

    • 这种形式只提交投注,游戏已经存在并且没有改变。并且没有验证组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2016-06-04
    • 1970-01-01
    • 2014-11-23
    • 2015-06-06
    • 2014-04-30
    • 2018-10-01
    相关资源
    最近更新 更多