2015-06-18 13 views
7

Ich arbeite an einer Webanwendung in Symfony2. Ich kam zu einem Punkt, an dem ich einen Rat/eine Erklärung von jemand anderem in Symfony benötige.Abhängigkeiten in Formularen Symfony2

Ich habe einen Teil meiner Datenbank, die wie folgt aufgebaut ist:

I-Karten, die auf ein Kartenattribut gehören und bestehen aus Kartenwerten.

Ich habe Kartenattributsätze, die viele Attribute haben, ein Kartenattribut kann zu vielen Kartenattributsätzen gehören (offensichtlich eine Viele-zu-Viele-Beziehung).

Dann hat das Attribut abhängig vom Kartenattribut einen Attributwert, zum Beispiel hat ein Text einen value_text vom Typ varchar und ein boolean hat einen value_boolean vom Typ boolean.

Sie können sich vorstellen, wenn Sie ein Formular erstellen, um eine neue Karte zu erstellen, muss das Formular Eingabefelder abhängig von dem Kartenattributsatz generieren, zu dem es gehört, und abhängig von den Attributen, die zu dem richtigen Attribut gehören?

Also hier ist meine Frage; Gibt es eine Möglichkeit, Eingabefelder dynamisch in einer Form zu generieren, die von der vom Benutzer gewählten Entität abhängt. Ich habe über Ereignisse gelesen, aber ich bin mir nicht sicher, ob sie meine Bedürfnisse befriedigen.

Dies ist der Code für meine Entitäten (I bis Getter entfernt und Setters für eine einfache Ansicht):

Karte:

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

Karte Attribut:

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

Kartenattributsatz

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

Karte Attribut Wert

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

Antwort

3

erstellen Typ Form CardAttributeValueType für CardAttributeValue Einheit, innerhalb dieses Formularfelder hinzufügen weitergegeben Attributtyp abhängig:

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

Dann fügen Sie collection Feldtyp für card_values innerhalb CardType Formulartyp und übergeben CardAttributeValueType als Sammlungselementtyp.

In der Card Einheit bearbeiten Sie getCardValues() Methode, so dass es jedes Attribut von CardAttributeSet zurückgibt, nicht nur diejenigen, für die Wert Entitäten existieren.

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

Es funktionierte, alot Dank! –

+0

Vadim Ashikhman, nur meine Bearbeitung modal arbeitet atm, weil die Karte Werte enthält. Tho muss ich noch sicherstellen, dass meine getCardValues ​​() jedes Attribut von CardAttributeSet zurückgibt, nicht nur diejenigen, für die Wertelemente existieren.Ich habe etwas recherchiert, aber ich bin gerade ziemlich verwirrt, hehe. Könnten Sie mir bitte noch einmal helfen? –

+1

Ich habe meine Antwort aktualisiert. Ich habe diese Methode nicht getestet, ich denke, Sie werden die Idee bekommen. –