2013-09-10 101 views
1

我試圖獲得一個多關係(多個依賴一對多關係)的窗體,但沒有成功。我使用的是Symfony 2.3和FOSUserbundle。Symfony形式中的多個依賴一對多關係

實體用戶

use FOS\UserBundle\Entity\User as BaseUser; 
    [...] 

    /** 
    * @ORM\Entity 
    * @Gedmo\Loggable 
    * @ORM\Table(name="ta_user", indexes={@ORM\Index(name="IDX_LOGIN_TOKEN", columns={"login_token"})}) 
    */ 
    class User extends BaseUser 
    { 
      [...] 

     /** 
     * @ORM\OneToMany(targetEntity="UserLifestyle", mappedBy="user", fetch="LAZY", cascade={"persist", "remove"}) 
     */ 
     protected $lifestyle; 

的UserManager

use Doctrine\ORM\EntityManager; 
    use FOS\UserBundle\Entity\UserManager as BaseUserManager; 
    use Acme\UserBundle\Entity\LifestyleQuestion; 
    use Acme\UserBundle\Entity\UserLifestyle; 
    [...] 

    class UserManager extends BaseUserManager { 
     public function createUser() { 
      $user = parent::createUser(); 
      $lifestyle = new UserLifestyle(); 
      $lifestyle->setQuestion($this->objectManager->getReference('Acme\UserBundle\Entity\LifestyleQuestion', 1)); 
      $user->addLifeStyle($lifestyle); 
      $lifestyle = new UserLifestyle(); 
      $lifestyle->setQuestion($this->objectManager->getReference('Acme\UserBundle\Entity\LifestyleQuestion', 2)); 
      $user->addLifeStyle($lifestyle); 
      $lifestyle = new UserLifestyle(); 
      $lifestyle->setQuestion($this->objectManager->getReference('Acme\UserBundle\Entity\LifestyleQuestion', 3)); 
      $user->addLifeStyle($lifestyle); 
      return $user; 
     } 

實體UserLifestyle

/** 
    * @ORM\Entity 
    * @Gedmo\Loggable 
    * @ORM\Table(name="ta_user_lifestyle") 
    */ 
    class UserLifestyle 
    { 
     /** 
     * @ORM\Id 
     * @ORM\Column(type="smallint") 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
     protected $id; 

     /** 
     * @ORM\ManyToOne(targetEntity="User", inversedBy="lifestyle") 
     * @ORM\JoinColumn(name="user_id") 
     */ 
     protected $user; 

     /** 
     * @ORM\ManyToOne(targetEntity="LifestyleQuestion", inversedBy="answeredByUser") 
     * @ORM\JoinColumn(name="question_id") 
     */ 
     protected $question; 

     /** 
     * @ORM\ManyToOne(targetEntity="LifestyleAnswer", inversedBy="userAnswers") 
     * @ORM\JoinColumn(name="answer_id") 
     * @Gedmo\Versioned 
     */ 
     protected $answer; 

然後,有一個形式類型

use Symfony\Component\Form\AbstractType; 
    use Symfony\Component\Form\FormBuilderInterface; 
    use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
    use Doctrine\ORM\EntityRepository; 

    class RegistrationType extends AbstractType 
    { 
     public function buildForm(FormBuilderInterface $builder, array $options) 
     { 
      $builder 
       ->add('email', NULL, array('label' => 'E-Mail')) 
          [...] 
       ->add('lifestyle', 'collection', array(
        'type' => new RegistrationLifestyleType(), 
        'allow_add' => false, 
        'allow_delete' => false, 
        'label' => false, 
       )) 

現在應該有一個相關的RegistrationLifestyleType。但我不知道它應該是什麼樣子。我期望在我的註冊表格中有三個選擇字段,顯示與這些問題相關的問題(如標籤)和一堆答案(作爲選擇字段)。該分配的UserManager三個問題到新創建的用戶,所以我們可以得到一個問題有:

$lifestyles = $user->getLifestyles(); 
    foreach ($lifestyles as $lifestyle) { 
     $question = $lifestyle->getQuestion(); // echo $question->getQuestion(); 
     $answers = $lifestyle->getQuestion()->getAnswers(); // loop through $answers and echo $answer->getAnswer(); 
    } 

但我怎麼能修改表單類型,得到這個工作。重要說明:我的意圖是儘可能使用內置功能,並儘量避免通過注入服務容器和實體管理器來擴充表單類型和其他類型。

回答

1

找到了一個解決方案,也許有人可以使用它。問題似乎是,LifestyleQuestionLifestyleAnswer在同一個對象(UserLifestyle)上是1:n的關係,所以Symfony不知道如何處理它,即使我已經在UserManager中將LifestyleQuestion設置爲一個特定問題。關於https://stackoverflow.com/a/9729888/672452必須使用窗體監聽器,所以父對象可用於子窗體。所以這裏是我的「簡單」RegistrationLifestyleType(不使用任何注入容器或管理器):

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
use Symfony\Component\Form\FormBuilderInterface; 
use Doctrine\ORM\EntityRepository; 
use Symfony\Component\Form\FormEvents; 
use Symfony\Component\Form\FormEvent; 
use Symfony\Component\Security\Core\SecurityContext; 

class RegistrationLifestyleType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) { 
     $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder) { 
      $form = $event->getForm(); 
      $lifestyle = $event->getData(); 
      if (!($lifestyle instanceof \Acme\UserBundle\Entity\UserLifestyle) || !$lifestyle->getQuestion()) return; 
      $label = $lifestyle->getQuestion()->getQuestion(); 
      $questionId = $lifestyle->getQuestion()->getId(); 
      $form->add('answer', 'entity', array(
       'class' => 'AcmeUserBundle:LifestyleAnswer', 
       'empty_value' => '', 
       'property' => 'answer', 
       'query_builder' => function(EntityRepository $er) use ($questionId) { 
        return $er 
         ->createQueryBuilder('t1') 
         ->andWhere('t1.question = :question') 
         ->setParameter('question', $questionId) 
         ->orderBy('t1.answer', 'ASC') 
        ; 
       }, 
       'label' => $label, 
      )); 
     }); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'Acme\UserBundle\Entity\UserLifestyle', 
      'error_bubbling' => false, 
     )); 
    } 
}