2015-11-25 85 views
2

我正在開發我的第一個複雜的表格與Symfony 2,我已經卡住了。Symfony2字段的自定義句柄

This image represents my situation

所以,我有一個名爲T恤具有以下屬性很簡單的實體:

  • 名稱 - >映射爲數據庫中的字符串列
  • tags_data - >映射爲數據庫中的字符串列(將包含JSON對象)

然後我有一個比實體具有更多字段的表單:

class TShirtType extends AbstractType { 

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

     $builder 
      ->add('name', 'text', array(
       'required' => true, 
      )) 
      ->add('colours', 'choice', array(
       'choices' => $availableColours, 
       'multiple' => true, 
       'expanded' => true, 
       'mapped' => false, 
      )) 
      ->add('sizes', 'choice', array(
       'choices' => $availableSizes, 
       'multiple' => true, 
       'expanded' => true, 
       'mapped' => false, 
      )) 
      ->add('materials', 'choice', array(
       'choices' => $availableMaterials, 
       'multiple' => true, 
       'expanded' => true, 
       'mapped' => false, 
      )); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function setDefaultOptions(OptionsResolverInterface $resolver) { 
     $resolver->setDefaults(array(
      'data_class' => 'AppBundle\Entity\TShirt', 
     )); 
    } 


    public function getName() { 
     return 'app_bundle_tshirt_form'; 
    } 
} 

我看了一下Data Transformers,但據我所知,他們不能幫助我在這個問題上,因爲它們具有映射下地幹活。

在給出這種情況下,我想添加一些類似於數據變換器的東西,它採用顏色,大小和材質表單字段並構建JSON對象以將其存儲在實體中。

所以我的問題是:有沒有辦法自定義處理窗體類中的非映射字段?

任何幫助將不勝感激!謝謝!!

+0

D ataTransformers不能只使用映射的字段......它們採用所有的形式並期望輸出中有正確的實體,或反之亦然 – Jean

+0

一種方法是添加get/setColors方法,並讓方法從您的json對象中拉出/推送必要的數據。另一種方法是爲顏色,大小和材質創建一個FormType,並創建一個數據轉換器,將json對象轉換爲數組或從數組轉換而來。當然,將標籤存儲爲php數組而不是json對象可能更有意義。 – Cerad

+0

謝謝Cerad。我認爲這個解決方案可以完美工作。我也認爲你對JSON序列化是正確的。 但是,我終於使用[DataMapper](http://api.symfony.com/2.3/Symfony/Component/Form/DataMapperInterface.html)來解決問題。 –

回答

0

也許你可以在你的FormType使用事件偵聽象下面這樣:

/** 
    * @param FormBuilderInterface $builder 
    * @param array    $options 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $formFactory = $builder->getFormFactory(); 
     $builder->addEventListener(
      FormEvents::PRE_SET_DATA, 
      function (\Symfony\Component\Form\FormEvent $event) use ($formFactory, $builder) { 
       $data = $event->getData(); 
       $form->add(
        'customFieldName', 
        'text', 
         array('some_options' => 'someOptionValue') 
       ); 

} 

要小心FormEvents(此處PRE_SET_DATA)。

此外,$data = $event->getData();允許您獲取相關對象。你可以循環它並解析JSON (或者創建儘可能多的方法,因爲你的JSON數組包含並反覆調用它們)爲了顯示儘可能多的$form->add(..,因爲你具有JSON數組的屬性。

0

這不是一個好的解決方案,將它存儲在tagsData中!爲symfony1.2 2.7

Controller.php這樣

解決方案:

$colors = [ 
    'white' => 'white', 
    'black' => 'black', 
    'green' => 'green' 
]; 
$sizes = [ 
    'M' => 'M', 
    'L' => 'L', 
    'XL' => 'XL' 
]; 
$materials = [ 
    'Cotton' => 'Cotton', 
    'Wool' => 'Wool', 
    'Silk' => 'Silk' 
]; 

$object = new TShirt(); 
$form = $this->createForm(new TShirtType(), $object, ['colours' => $colors, 'sizes' => $sizes, 'materials' => $materials]); 
$form->handleRequest($request); 

TShirtType.php

class TShirtType extends AbstractResourceType 
{ 

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

     $builder 
      ->add('name', 'text', array(
       'required' => true, 
      )) 
      ->add('colours', 'choice', array(
       'choices' => $options['colours'], 
       'multiple' => true, 
       'expanded' => true, 
       'mapped' => false 
      )) 
      ->add('sizes', 'choice', array(
       'choices' => $options['sizes'], 
       'multiple' => true, 
       'expanded' => true, 
       'mapped' => false 
      )) 
      ->add('materials', 'choice', array(
       'choices' => $options['materials'], 
       'multiple' => true, 
       'expanded' => true, 
       'mapped' => false 
      )); 

      $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) 
      { 
       $object = $event->getData(); 
       $form = $event->getForm(); 

       $tagsData = [ 
        'colours' => $form->get('colours')->getData(), 
        'sizes' => $form->get('sizes')->getData(), 
        'materials' => $form->get('materials')->getData(), 
       ]; 
       $object->setTagsData($tagsData); 

       $event->setData($object); 
      }); 
    } 

    public function finishView(FormView $view, FormInterface $form, array $options) 
    { 
     $tagsData = $view->vars['data']->getTagsData(); 

     if($tagsData) { 
      $types = ['colours', 'sizes', 'materials']; 
      foreach($types as $type) { 
       foreach($view->offsetGet($type) as $checkbox) { 
        $checkbox->vars['checked'] = isset($tagsData[$type]) && in_array($checkbox->vars['value'], $tagsData[$type]); 
       } 
      } 
     } 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function configureOptions(OptionsResolver $resolver) { 
     $resolver->setDefaults(array(
      'data_class' => 'AppBundle\Entity\TShirShirt', 
     )); 
     $resolver->setRequired(['colours', 'sizes', 'materials']); 
    } 

    public function getName() { 
     return 'app_bundle_tshirt_form'; 
    } 
}