2015-06-18 36 views
7

我正在研究Symfony2中的一個Web應用程序。我來到了一個需要Symfony中更高級的建議/解釋的地方。形式中的依賴關係Symfony2

我有我的數據庫,建立如下的一部分:

我有屬於設置卡屬性,包括卡值卡。

我有卡屬性集有很多屬性,卡屬性可以屬於許多卡屬性集(顯然是多對多的關係)。

然後根據卡片屬性該屬性有一個屬性值,例如文本有一個varchar類型的value_text和一個布爾類型的value_boolean。

你可以想象當創建一個新卡的窗體時,窗體需要根據它屬於的卡屬性集來生成輸入字段,並且取決於屬性屬性集的屬性是否正確?

所以這裏是我的問題;有沒有一種方法可以根據用戶選擇的實體動態生成表單中的輸入字段。我已閱讀過有關事件,但我不確定它們是否滿足我的需求。

這是我的實體的代碼(我除去getter和setter方法更簡單的視圖):

卡:

/** 
* card 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="clientsBundle\Entity\cardRepository") 
* @UniqueEntity(
*  fields={"cardLabel"}, 
*  message="A card with this label already exists" 
*) 
*/ 
class card 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="card_label", type="string", length=999) 
    */ 
    private $cardLabel; 

    /** 
    * @ORM\ManyToOne(targetEntity="project", inversedBy="project_cards") 
    * @ORM\JoinColumn(name="project_id", referencedColumnName="id", onDelete = "SET NULL") 
    */ 
    protected $card_project; 

    /** 
    * @ORM\ManyToOne(targetEntity="cardAttributeSet", inversedBy="cas_cards") 
    * @ORM\JoinColumn(name="cas_id", referencedColumnName="id") 
    **/ 
    protected $cardAttrSet; 

    /** 
    * @ORM\OneToMany(targetEntity="cardAttrValue", mappedBy="card", cascade={"persist"}, orphanRemoval=true) 
    **/ 
    protected $card_values; 

    /** 
    * @ORM\ManyToMany(targetEntity="user", mappedBy="cards") 
    */ 
    private $users; 

    public function __construct() { 
     $this->card_values = new ArrayCollection(); 
     $this->users = new ArrayCollection(); 
    } 
} 

卡屬性:

/** 
* cardAttribute 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="clientsBundle\Entity\cardAttributeRepository") 
* @UniqueEntity(
*  fields={"name"}, 
*  message="An attribute with this name already exists" 
*) 
*/ 
class cardAttribute 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="name", type="string", length=255) 
    */ 
    private $name; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="type", type="string", length=255) 
    */ 
    private $type; 
} 

卡屬性集

/** 
* cardAttributeSet 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="clientsBundle\Entity\cardAttributeSetRepository") 
* @UniqueEntity(
*  fields={"casLabel"}, 
*  message="An attribute set with this label already exists" 
*) 
*/ 
class cardAttributeSet 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    public $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="cas_label", type="string", length=255) 
    */ 
    private $casLabel; 

    /** 
    * @ORM\OneToMany(targetEntity="card", mappedBy="cardAttrSet") 
    */ 
    private $cas_cards; 

    /** 
    * @ORM\ManyToMany(targetEntity="cardAttribute") 
    * @ORM\JoinTable(name="cas_attribute", 
    *   joinColumns={@ORM\JoinColumn(name="cas_id", referencedColumnName="id")}, 
    *   inverseJoinColumns={@ORM\JoinColumn(name="attribute_id", referencedColumnName="id")} 
    *   ) 
    */ 
    private $attributes; 

    public function __construct() 
    { 
     $this->cas_cards = new ArrayCollection(); 
     $this->attributes = new ArrayCollection(); 
    } 
} 

卡屬性值

/** 
* cardAttrValue 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="clientsBundle\Entity\cardAttrValueRepository") 
* @UniqueEntity(
*  fields={"valueText"} 
*) 
*/ 
class cardAttrValue 
{ 
    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="value_text", type="string", length=255, nullable=true) 
    */ 
    private $valueText; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="value_varchar", type="string", length=255, nullable=true) 
    */ 
    private $valueVarchar; 

    /** 
    * @var integer 
    * 
    * @ORM\Column(name="value_int", type="integer", nullable=true, nullable=true) 
    */ 
    private $valueInt; 

    /** 
    * @var boolean 
    * 
    * @ORM\Column(name="value_boolean", type="boolean", nullable=true, nullable=true) 
    */ 
    private $valueBoolean; 

    /** 
    * @ORM\ManyToOne(targetEntity="card", inversedBy="card_values") 
    * @ORM\JoinColumn(name="card_id", referencedColumnName="id") 
    **/ 
    private $card; 

    /** 
    * @ORM\ManyToOne(targetEntity="cardAttribute") 
    * @ORM\JoinColumn(name="cardAttributes_id", referencedColumnName="id") 
    **/ 
    private $cardAttribute; 
} 

回答

3

CardAttributeValue實體創建一個表單類型CardAttributeValueType,這裏面的表單字段添加根據傳遞的屬性類型:

class CardAttributeValueType extends AbstractType 

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { 
     $value = $event->getData(); 
     $form = $event->getForm(); 

     if (!$value) { 
      return; 
     } 

     switch ($value->getCardAttribute()->getType()) { 
      case 'text': 
       $form->add('valueVarchar', 'text'); 
       break; 

      // Same for other attribute types 
     } 
    } 
} 

然後,添加collection字段類型card_values裏面CardType表單類型並傳遞CardAttributeValueType作爲收集項目類型。

Card實體編輯getCardValues()方法,因此它將返回CardAttributeSet的每個屬性,而不僅僅是存在值實體的屬性。

UPDATE

public function getCardValues() 
{ 
    $collection = new ArrayCollection(); 

    if (!$this->cardAttrSet) { 
     return $collection; 
    } 

    // Add existing values 
    foreach ($this->card_values as $value) { 
     $collection[$value->getCardAttribute()->getId()] = $value; 
    } 

    // Get all attributes from the set and create values for missing attributes 
    foreach ($this->cardAttrSet->getAttributes() as $attr) { 
     if (!isset($collection[$attr->getId()])) { 
      $value = new cardAttrValue(); 
      $value->setCardAttribute($attr); 

      $collection[$attr->getId()] = $value; 
     } 
    } 

    return $collection; 
} 
+0

它的工作,非常感謝! –

+0

Vadim Ashikhman,只有我的編輯模式工作atm,因爲卡中有值。我仍然需要確保我的getCardValues()從CardAttributeSet返回每個屬性,而不僅僅是存在值實體的屬性。我做了一些研究,但我現在很困惑,嘿嘿。你能再幫我一次嗎? –

+1

我已經更新了我的答案。我沒有測試過這種方法,我想你會明白。 –