2017-06-18 33 views
0

我使用select2插件與Ajax在我的窗體上有一個動態字段,但是當我提交它時,返回錯誤「此值爲無效「,這是正常的原因,我使用ChoiceType與創建choices選項中的空array()。根據symfony文檔的this部分,表單事件是我的救世主,所以試圖使用它,但它看起來像我的代碼有問題,並不能真正看到什麼。Symfony,如何使用窗體事件來驗證動態客戶端窗體

我的問題是:

怎樣的選擇可能傳遞到字段中,形式是有效的。

我的表單類型

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')的網址發出ajax請求,我認爲它會加載choices選項,並且可能有<option>,但我的選擇仍然返回沒有<option>

以及更多(不能remmenber)。

而且我在select2插件的v4.0.3中使用了框架的v3.1,如果需要更多的信息,只需要問和thx閱讀和嘗試幫助。

編輯

只需添加一些信息

回答

0

你做的事情太複雜更清晰。在您的文檔示例中,他們爲已有的表單字段('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); 
      } 

     )); 
     } 
    } 
} 
+0

我不認爲使用'EntityType'是最好的方法。我的表單上有一個與我的Article實體有ManyToOne關係的字段圖像,但圖像表可能有數千個條目,所以我使用ajax(使用select2插件)在客戶端傳遞選擇可能性, m在字段的選項選項中使用空數組,然後我想將選項傳遞給字段以使表單有效 –

+0

那麼您可以使用EntityType進行ajax加載。我自己實際上遇到了這個問題,而且我的做法是通過向構建器添加eventListener來處理PRE_SET_DATA和PRE_SUBMIT事件。我已經更新了我的答案。 –

+0

它適用於我,我確定我正在做這樣的事情,但無論如何,它完美的工作。所以事情就是用EntityType來工作,而我正在路上,我的意思是我想。我用我的最終代碼發佈答案。 Thx尋求幫助 –