I'm working on a webapplication in Symfony2. I came to a point in which I need some advice/explanation from some one more advanced in Symfony.
I have a part of my database that is set up as follows:
I have cards that belong to a card attribute set and consists of card values.
I have card attribute sets that have many attributes, a card attribute can belong to many card attribute sets (obviously a many to many relationship).
Then depending on the card attribute the attribute has an attribute value, for example a text has a value_text of type varchar and a boolean has a value_boolean of type boolean.
You can imagine when making a form to create a new card, the form needs to generate input fields depending on the card attribute set it belongs to and depending on the attributes that belong to the attribute set right?
So here's my question; is there a way to dynamically generate input fields in a form depending the entity chosen by the user. I've read about events but I'm not sure that they satisfy my needs.
This is the code for my entities (I removed to Getters and Setters for a more simple view):
Card:
/**
* 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();
}
}
Card Attribute:
/**
* 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;
}
Card Attribute Set
/**
* 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();
}
}
Card Attribute Value
/**
* 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;
}
Create a form type
CardAttributeValueType
forCardAttributeValue
entity, inside this form add fields depending on passed attribute type:Then, add
collection
field type forcard_values
insideCardType
form type and passCardAttributeValueType
as collection item type.In the
Card
entity editgetCardValues()
method so it will return every attribute fromCardAttributeSet
, not only ones for which value entities exist.UPDATE