【问题标题】:Symfony, how to use form event to validate dynamic client-side formSymfony,如何使用表单事件来验证动态客户端表单
【发布时间】:2017-06-18 20:46:44
【问题描述】:

我正在使用带有 ajax 的 select2 插件在我的表单上有一个动态字段,但是当我提交它时它返回一个错误 “此值无效”,这是正常原因我在创建时的choices 选项中使用ChoiceType 和一个空的array()。根据 symfony 文档的this 部分,表单事件是我的救星,所以尝试使用它,但我的代码看起来有问题,看不出是什么。

所以我的问题是:

如何将选择的可能性传递给字段,以使表单有效。

我的表单类型

class ArticleType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            //My other field

        //My functions to add the field with the possible choices
        $formModifier = function (FormInterface $form, $imageValue) use ($options) {
            if ($imageValue !== null) {
                $listImages = $this->getChoiceValue($imageValue, $options);

                if (!$listImages) {
                    $form->get('image')->addError(new FormError(
                    'Nous n\'avons pas pu trouver l\'image, veuiller choisir une autre'
                    ));
                }
            } else {
                $listImages = array();
            }

            //die(var_dump($listImages)); //Array of Image

            $form->add('image', ChoiceType::class, array(
                'attr' => array(
                    'id' => 'image'),
                'expanded' => false,
                'multiple' => false,
                'choices' => $listImages));
        };

        $formModifierSubmit = function (FormInterface $form, $imageValue) use ($options) {
            if ($imageValue !== null) {
                $listImages = $this->getChoiceValue($imageValue, $options);

                if (!$listImages) {
                    $form->get('image')->addError(new FormError(
                        'Nous n\'avons pas pu trouver l\'image, veuiller choisir une autre'
                    ));
                }
            } else {
                $form->get('image')->addError(new FormError(
                    'Veuillez choisir une image s.v.p.'
                ));
            }

            //die(var_dump($listImages)); //Array of Image object

            $config = $form->get('image')->getConfig();
            $opts = $config->getOptions();
            $chcs = array('choices' => $listImages);
            //die(var_dump($chcs)); //output an array with a 'choices' keys with array value
            array_replace($opts, $chcs); //not work
            //array_merge($opts, $chcs); //not work
            //die(var_dump($opts)); //replacements/merge are not made
        };

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($formModifier) {
                // this would be the entity Article
                $data = $event->getData();

                $formModifier($event->getForm(), $data->getImage());
            }
        );

        //$builder->get('image')->addEventListener( //give error cause the field image don't exist
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) use ($formModifierSubmit) {
                $imageVal = $event->getData();
                //die(var_dump($imageVal)); //return all the submitted data field in an array
                //But when change this event to Submit it return the Article model populated by the submitted data, EXCEPT the image field which have null as value

                $formModifierSubmit($event->getForm(), $imageVal['image']);
            }
        );
    }

    public function getChoiceValue($imageValue, $options)
    {
        $listImages = $options['em']->getRepository('AlmotivAppBundle:Image')->findBy(array(
            'id' => $imageValue
        ));

        return $listImages; //array of Image object
    }
    [...]
}

供参考

我的image 字段不依赖于文档示例等任何其他字段,因此我需要在PRE_SUBMIT 事件上填充choices 选项以提供可能的选择。

而且image 在我的Article 实体中有一个多对一关系

class Article implements HighlightableModelInterface
{
    //some properties
    /**
     * @ORM\ManyToOne(targetEntity="Image\Entity\Path", cascade={"persist"})
     * @Assert\Valid()
     */
    private $image;
}

如果我的情况不好,请告诉我,因为我现在不知道,我会尝试很多事情,比如

  • array_replace 用配置字段中的选项但是没有错。
  • 向表单操作url : $form.attr('action') 的url 发出一个ajax 请求,我认为它会加载choices 选项,可能是<option>,但我的选择仍然返回,没有<option>

还有更多(记不得了)。

而且我正在使用框架的 v3.1 和 select2 插件的 v4.0.3,如果需要更多信息,请询问并感谢阅读和尝试帮助。

编辑

添加一些信息更清楚

【问题讨论】:

    标签: php forms symfony symfony-forms


    【解决方案1】:

    你把事情弄得太复杂了。在您的文档示例中,他们为已经存在的表单字段('sport')添加了 eventListener,并且您仅将其添加到稍后添加的不存在的字段(文档示例中的您的 'image' 字段和 'position' 字段)。

    你应该使用EntityType,如果你需要(我不确定你是否需要)使用query_builder选项过滤你的图像,添加constraintsexample with controller)进行验证。

    class ArticleType extends AbstractType {
    /**
     * {@inheritdoc}
     */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
    
             // $builder
             // My other field
             $imageFieldFunction = $this->getImageFieldFunction();
    
             $builder->addEventListener(FormEvents::PRE_SET_DATA, $imageFieldFunction);
             $builder->addEventListener(FormEvents::PRE_SUBMIT, $imageFieldFunction);
    
        }
        private function getImageFieldFunction()
        {
             return function(FormEvent $event) {
                 $form = $event->getForm();
                 $data = $event->getData();
                 //when your data_class is Article 
                 $image = $data->getImage();//depending on your Article class
                 /*if you are using data_class => null
                 $image = $data['image'];
                  */
                 $imageId = $image ? $image->getId() : 0;
    
                 $builder->add('image', EntityType::class , array(
                'class' => 'AlmotivAppBundle:Image',
                 'attr' => array(
                    'id' => 'image'
                 ) ,
                 'expanded' => false,
                 'multiple' => false,
                 'constraints' => new NotBlank(),
                 'query_builder' => function (EntityRepository $er) use ($imageId) {
                      return $er->createQueryBuilder('i')
                                ->where('i.id = :image_id')
                                ->setParameter('image_id', $imageId);
                 }
    
             ));
             }
        }
    }
    

    【讨论】:

    • 我不认为使用EntityType 是最好的方法。我的表单上有一个与我的 Article 实体有 ManyToOne 关系的字段图像,但图像表可能有数千个条目,所以我使用 ajax(使用 select2 插件)在客户端传递选择的可能性,因为我m 在字段的选择选项中使用空数组,然后我想将选择传递给字段以使表单有效
    • 您也可以使用 EntityType 进行 ajax 加载。实际上,我自己也遇到过这个问题,我的做法是将 eventListener 添加到 PRE_SET_DATA 和 PRE_SUBMIT 事件的构建器中。我已经更新了我的答案。
    • 它对我有用,我确信我正在做类似的事情,但无论如何它工作得很好。所以问题是使用 EntityType,我在路上,我的意思是我想。我用我的最终代码发布了一个答案。谢谢帮助
    • 很糟糕,我似乎无法发布答案,我发了一个gist
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多