2012-10-04 87 views
9

我有2個實體 - 用戶和組。他們有多對多的關係,Group用於存儲用戶的角色。Symfony 2嵌入式表單集合多對多

我試圖通過增加集合,使用戶編輯表單,我希望能夠通過從下拉列表中選擇它來添加一個新的角色(僅限於什麼是已經在DB)

用戶類型。 PHP:

class UserType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('username') 
      ->add('email') 
      ->add('forename') 
      ->add('surname') 
      ->add('isActive') 
      ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) 
      ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) 
      ->add('groups', 'collection', array(
        'type' => new GroupType(), 
        'allow_add' => true, 
        )) 
     ; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'Sfox\CoreBundle\Entity\User' 
     )); 
    } 
} 

和GroupType.php:

class GroupType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('name') 
      ->add('role'); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
       "data_class" => 'Sfox\CoreBundle\Entity\Group' 
       )); 
    } 
} 

這顯示在基本的文本框的形式的作用,但如果我添加到表單中的條目,它會堅持級聯新耳鼻喉科進入組,如果我要編輯一個條目,它會更改底層的組數據。

我試圖使一個GroupSelectType.php:

class GroupSelectType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('role', 'entity', array('class'=>'SfoxCoreBundle:Group', 'property'=>'name')); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
       "data_class" => 'Sfox\CoreBundle\Entity\Group' 
       )); 
    } 
} 

添加字段作爲一個「實體」型,這顯示了正確的選擇框(但是默認值),我似乎無法綁定到UserType表單!

我希望表單所要做的就是修改用戶實體中的基礎'組'ArrayCollection。

有誰知道我該如何做到這一點?

回答

14

嗯,我制定了其他人有類似問題所困擾的解決方案......

我不得不創建一個自定義表單類型,並宣佈它作爲一種服務,所以我可以通過在實體管理器。然後,我需要做出dataTransformer改變我的組對象爲整數的形式

定製GroupSelectType:

class GroupSelectType extends AbstractType 

{ 
    /** 
    * @var ObjectManager 
    */ 
    private $om; 

    private $choices; 

    /** 
    * @param ObjectManager $om 
    */ 
    public function __construct(ObjectManager $om) 
    { 
     $this->om = $om; 

     // Build our choices array from the database 
     $groups = $om->getRepository('SfoxCoreBundle:Group')->findAll(); 
     foreach ($groups as $group) 
     { 
      // choices[key] = label 
      $this->choices[$group->getId()] = $group->getName() . " [". $group->getRole() ."]"; 
     } 
    } 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $transformer = new GroupToNumberTransformer($this->om); 
     $builder->addModelTransformer($transformer); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
       "choices" => $this->choices, 
       )); 
    } 

    public function getParent() 
    { 
     return 'choice'; 
    } 

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

在構造函數中我得到所有可用組,並把它們放入一個「選擇」作爲選項傳遞給選擇框的數組。

您還會注意到我正在使用自定義數據轉換器,這是將groupId(用於呈現表單)更改爲Group實體。我提出的GroupSelectType服務以及與在[@ doctrine.orm.entity_manager]

services.yml傳遞(束配置):

services: 
    sfox_core.type.group_select: 
     class: Sfox\CoreBundle\Form\Type\GroupSelectType 
     arguments: [@doctrine.orm.entity_manager] 
     tags: 
      - { name: form.type, alias: group_select } 

GroupToNumberTranformer.php

class GroupToNumberTransformer implements DataTransformerInterface 
{ 
    /** 
    * @var ObjectManager 
    */ 
    private $om; 

    /** 
    * @param ObjectManager $om 
    */ 
    public function __construct(ObjectManager $om) 
    { 
     $this->om = $om; 
    } 

    /** 
    * Transforms an object (group) to a string (number). 
    * 
    * @param Group|null $group 
    * @return string 
    */ 
    public function transform($group) 
    { 
     if (null === $group) { 
      return ""; 
     } 

     return $group->getId(); 
    } 

    /** 
    * Transforms a string (number) to an object (group). 
    * 
    * @param string $number 
    * @return Group|null 
    * @throws TransformationFailedException if object (group) is not found. 
    */ 
    public function reverseTransform($number) 
    { 
     if (!$number) { 
      return null; 
     } 

     $group = $this->om 
     ->getRepository('SfoxCoreBundle:Group') 
     ->findOneBy(array('id' => $number)) 
     ; 

     if (null === $group) { 
      throw new TransformationFailedException(sprintf(
        'Group with ID "%s" does not exist!', 
        $number 
      )); 
     } 

     return $group; 
    } 
} 

而我修改過的UserType.php - 注意我現在使用自定義表單類型「group_select」,因爲它是作爲服務運行的:

class UserType extends AbstractType 
{ 
    private $entityManager; 

    public function __construct($entityManager) 
    { 
     $this->entityManager = $entityManager; 
    } 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $transformer = new GroupToNumberTransformer($this->entityManager); 

     $builder 
      ->add('username') 
      ->add('email') 
      ->add('forename') 
      ->add('surname') 
      ->add('isActive') 
      ->add('joinDate', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')) 
      ->add('lastActive', 'date', array('input' => 'datetime', 'format' => 'dd-MM-yyyy')); 
     $builder 
      ->add(
       $builder->create('groups', 'collection', array(
        'type' => 'group_select', 
        'allow_add' => true, 
        'options' => array(
          'multiple' => false, 
          'expanded' => false, 
          ) 
        )) 
     ); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'Sfox\CoreBundle\Entity\User' 
     )); 
    } 

    public function getName() 
    { 
     return 'sfox_corebundle_usertype'; 
    } 
} 
+0

這個答案幫了我一噸!謝謝! – jcbwlkr

+0

非常感謝! –

+0

非常有幫助。謝謝 – Rinat