Symfony,如何使用表单事件来验证动态客户端表单

时间:2017-06-18 20:46:45

标签: php forms symfony symfony-forms

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

所以我的问题是:

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

我的表单类型

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字段不依赖于doc示例等任何其他字段,因此我需要填充choices事件上的PRE_SUBMIT选项以提供可能的选择。

image实体中Article也有一个ManyToOne关系

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

如果我的方式不好让我知道因为我现在已经不在乎了,我会尝试很多东西,比如

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

以及更多(无法挽回)。

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

修改

只需添加一些信息即可更清晰

1 个答案:

答案 0 :(得分:0)

你让事情变得太复杂了。在您的文档示例中,他们为已存在的表单字段('sport')添加了eventListener,并且您只将它添加到以后添加的不存在的字段(文档示例中的'image'字段和'position'字段)。

您应该使用EntityType,如果您需要(我确定不是),请使用query_builder选项过滤您的图片,以便验证添加constraints({{3} })。

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

         ));
         }
    }
}