Symfony2 Form Dependencies

I am working on a web application in Symfony2. I came to the point where I needed a few tips / explanations from another advanced Symfony.

I have a part of my database that is configured as follows:

I have maps that belong to a set of map attributes and consist of map values.

I have a set of map attributes that have many attributes, a map attribute can belong to many map attributes (obviously, this relationship is many, many).

Then, depending on the map attribute, the attribute has an attribute value, for example, text has text_value of type varchar, and boolean has value_boolean of type boolean.

Can you imagine, when you create a form for creating a new map, the form should generate input fields depending on the attribute of the map to which it belongs, and depending on the attributes that belong to the set attribute?

So here is my question; There is a way to dynamically generate input fields in a form depending on the object selected by the user. I read about events, but I'm not sure that they satisfy my needs.

This is the code for my entities (I removed Getters and Setters for a simpler view):

map:

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

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

Map Attributes 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(); } } 

Map 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; } 
+7
php events forms symfony entities
source share
1 answer

Create a form type CardAttributeValueType for the CardAttributeValueType object, add fields inside this form depending on the type of attribute passed:

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

Then add the collection field type for card_values inside the card_values form CardType and pass CardAttributeValueType as the type of the collection item.

In the Card object, edit the getCardValues() method so that it returns each attribute from the CardAttributeSet , and not just those for which value objects exist.

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; } 
+3
source share

All Articles