Зависимости в формах Symfony2
Я работаю над веб-приложением в Symfony2. Я подошел к тому моменту, когда мне нужен совет/объяснение от кого-то более продвинутого в Symfony.
У меня есть часть моей базы данных, которая настроена следующим образом:
У меня есть карты, которые принадлежат набору атрибутов карты и состоят из значений карт.
У меня есть наборы атрибутов карт, которые имеют множество атрибутов, атрибут карты может принадлежать многим наборам атрибутов карт (очевидно, многим ко многим отношения).
Затем, в зависимости от атрибута карты, атрибут имеет значение атрибута, например, текст имеет значение value_text типа varchar, а логическое значение имеет значение value_boolean типа boolean.
Вы можете себе представить, что при создании формы для создания новой карты форма должна генерировать поля ввода в зависимости от набора атрибутов карты, к которому она принадлежит, и в зависимости от атрибутов, которые принадлежат набору атрибутов правильно?
Итак, вот мой вопрос; есть ли способ динамически создайте поля ввода в форме, зависящей от сущности, выбранной пользователем. Я читал о событиях, но не уверен, что они удовлетворяют моим потребностям.
Это код для моих сущностей (я удалил геттеры и сеттеры для более простого представления):
Карточка:
/**
* 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;
}
1 answers
Создайте тип формы CardAttributeValueType
для сущности CardAttributeValue
, внутри этой формы добавьте поля в зависимости от переданного типа атрибута:
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
, а не только те, для которых существуют сущности значений.
ОБНОВЛЕНИЕ
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;
}