dqyin0101 2013-04-23 11:54
浏览 33
已采纳

在EventListener中添加表单错误

I have a Symfony 2.2 based application with a form that has a field that is only required based on another field in the form. I bound an EventListener to catch when the form is submitted so I can verify if the 'required' field is actually not needed when the form is submitted.

I've noticed that I can't set a FormError inside the PRE_BIND form event. Doing so doesn't show the error, but if I bind to the BIND event listener then the form error is displayed properly but I don't want to wait until the BIND event to check for my errors (I don't want the potential of bad data being bound to my entity).

Can someone tell me why this is so?

public function buildForm(FormBuilderInterface $builder, array $options)
{
    // snip ...

    $builder->addEventListener(FormEvents::PRE_BIND, function(FormEvent $event) use ($options) {
        $data = $event->getData();
        $form = $event->getForm();
        if ($data === null) {
            return;
        }

        // yes, this is definitely called; If I remove the if() and just
        // and just add the formError it still doesn't work.
        if ($data['type'] == 'port' and empty($data['protocol'])) {
            $form->get('protocol')->addError(new FormError('A valid protocol must be selected.'));
        }

    });

}
  • 写回答

1条回答 默认 最新

  • doulan7166 2013-05-06 08:53
    关注

    In this case you should use Validation Groups based on Submited Data. This method available since symfony 2.1.

    And you don't need to pull events. Look here:

    forms - http://symfony.com/doc/current/book/forms.html#groups-based-on-submitted-data

    validation - http://symfony.com/doc/current/book/validation.html#validation-groups

    Try this approach. And you should get code like this:

    Entity script with validators: src/Acme/AcmeBundle/Entity/Url.php

    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
    
    ...
        /**
         * @ORM\Column(name="port", type="integer")
         * @Assert\NotBlank(groups={"validation_partial", "validation_full"})
         */
        private $port;
    
        /**
         * @ORM\Column(name="protocol", type="string", length=10)
         * @Assert\NotBlank(groups={"validation_full"})
         */
        private $protocol;
    ...
    

    Form script: src/Acme/AcmeBundle/Form/UrlType.php

    use Symfony\Component\Form\FormInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    
    ...
    
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'validation_groups' => function(FormInterface $form) {
                $data = $form->getData();
    
                if ('port' == $data->getType()) {
                    return array('validation_full');
                } else {
                    return array('validation_partial');
                }
            },
        ));
    
     }
    

    Ok, I will try answer on your question in detail. For example. We have FormType like this:

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name') // Some text field 'Name'
        ;
    
        $builder->addEventListener(FormEvents::PRE_BIND, function(FormEvent $event) use ($options) {
            $event->getForm()->get('name')->addError(new FormError('*** ERROR PRE_BIND'));
        });
        $builder->addEventListener(FormEvents::BIND, function(FormEvent $event) use ($options) {
            $event->getForm()->get('name')->addError(new FormError('*** ERROR BIND'));
        });
        $builder->addEventListener(FormEvents::POST_BIND, function(FormEvent $event) use ($options) {
            $event->getForm()->get('name')->addError(new FormError('*** ERROR POST_BIND'));
        });
    }
    

    You are right. If add errors in listeners for events: PRE_BIND, BIND, POST_BIND. You will get only errors from BIND and POST_BIND events. To understand why this is so you need to know 2 points.

    First thing: Every element in form is also form. In our case our main form has children 'Name'(text element) which is also a form.

    [MainForm]

    -> [NameForm]

    // there can be additional forms if your form has another elements

    Second thing: When you bind request to a MainForm you invoke bind() function.

    And this function invoke bind() function for every child of MainForm.

    Answer for your question is in algorithm of this function. bind() function algorithm:

    function bind($submittedData) {
        1) clear all errors
        2) dispatch event PRE_BIND
        3) invoke bind() function for children
        4) dispatch event BIND
        5) dispatch event POST_BIND
    }
    

    So based of our example programm flow will be:

    Invoke bind() function for MainForm
    1) MainForm - clear all errors
    2) MainForm - dispatch event PRE_BIND // there our listener add error for child NameForm.
    3) MainForm - invoke bind() function for child NameForm:
        1) NameForm - clear all errors // is the answer for your question, error from event MainForm:PRE_BIND cleared!!!
        2) NameForm - dispatch event PRE_BIND // no changes
        3) NameForm - invoke bind() for children // this form does not have children, so will be passed
        4) NameForm - dispatch event BIND // no changes
        5) NameForm - dispatch event POST_BIND // no changes
    4) MainForm - dispatch event BIND // there our listener add error to child NameForm
    5) MainForm - dispatch event POST_BIND // there our listener add another error to child NameForm.
    

    I hope this explanation is helpful for you.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP