表单 Symfony2 中的依赖项

Dependencies in forms Symfony2

我正在使用 Symfony2 开发一个网络应用程序。我到了一个地步,我需要一些来自 Symfony 更高级的 advice/explanation。

我有一部分数据库设置如下:

我有一些卡片属于卡片属性集并且由卡片值组成。

我的卡片属性集有很多属性,一个卡片属性可以属于很多卡片属性集(显然是多对多关系)。

然后根据卡片属性,该属性有一个属性值,例如文本有一个 value_text 类型的 varchar 和一个布尔值有一个 value_boolean 类型的布尔值。

你可以想象一下,在制作表单创建新卡片时,表单需要根据其所属的卡片属性集并根据属于该属性集的属性生成输入字段对吗?

所以这是我的问题;有没有一种方法可以根据用户选择的实体动态生成表单中的输入字段。我读过有关活动的信息,但我不确定它们是否满足我的需求。

这是我的实体的代码(为了更简单的视图,我移到了 Getters 和 Setters):

卡片:

/**
 * 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;
}

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
        }
     }
}

然后,在 CardType 表单类型中为 card_values 添加 collection 字段类型,并将 CardAttributeValueType 作为集合项类型传递。

Card 实体编辑 getCardValues() 方法中,因此它将 return 来自 CardAttributeSet 的每个属性,而不仅仅是存在值实体的属性。

更新

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;
}