形式中的依赖关系Symfony2
问题描述:
我正在研究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;
}
答
为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;
}
它的工作,非常感谢! –
Vadim Ashikhman,只有我的编辑模式工作atm,因为卡中有值。我仍然需要确保我的getCardValues()从CardAttributeSet返回每个属性,而不仅仅是存在值实体的属性。我做了一些研究,但我现在很困惑,嘿嘿。你能再帮我一次吗? –
我已经更新了我的答案。我没有测试过这种方法,我想你会明白。 –