2015-06-18 23 views
7

Pracuję nad aplikacją internetową w Symfony2. Doszedłem do punktu, w którym potrzebuję porady/wyjaśnienia od kogoś bardziej zaawansowanego w Symfony.Zależności w formularzach Symfony2

Mam część mojej bazy danych, który jest ustawiony w następujący sposób:

mam karty, które należą do atrybutu zestaw kart i składa się z wartości karty.

Posiadam zestawy atrybutów kart, które mają wiele atrybutów, atrybut karty może należeć do wielu zestawów atrybutów kart (oczywiście wiele do wielu relacji).

Następnie, w zależności od atrybutu karty, atrybut ma wartość atrybutu, na przykład tekst ma wartość_tekstu typu varchar, a boolean ma wartość_boolean typu boolean.

Możesz sobie wyobrazić przy tworzeniu formularza do utworzenia nowej karty, formularz musi wygenerować pola wejściowe w zależności od zestawu atrybutów karty, do którego należy i w zależności od atrybutów należących do ustawionego atrybutu, prawda?

Oto moje pytanie; czy istnieje sposób dynamicznego generowania pól wejściowych w formularzu w zależności od podmiotu wybranego przez użytkownika. Czytałem o wydarzeniach, ale nie jestem pewien, czy spełniają one moje potrzeby.

Jest to kod dla moich podmiotów (usunąłem do pobierające i ustawiające metody bardziej prostej):

kart:

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

Atrybut kart:

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

Zestaw atrybutów karty

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

Karta Atrybut Wartość

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

Odpowiedz

3

Utwórz typ formularz CardAttributeValueType dla CardAttributeValue podmiotu, wewnątrz ta forma dodać pola w zależności od przeszedł typu atrybutu:

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

Następnie dodać collection typ pola dla card_values wewnątrz CardType typ formularza i podanie CardAttributeValueType jako typ pozycji kolekcji.

Metoda edycji jednostki powoduje, że zwrócony zostanie każdy atrybut z CardAttributeSet, nie tylko dla tych, dla których istnieją jednostki wartości.

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

Udało się, dziękuję! –

+0

Vadim Ashikhman, tylko mój mod modyfikuje bankomat, ponieważ karta ma w nim wartości. Jednak nadal muszę się upewnić, że moja funkcja getCardValues ​​() zwraca każdy atrybut z CardAttributeSet, nie tylko te, dla których istnieją wartości.Zrobiłem trochę badań, ale jestem teraz bardzo zdezorientowany, hehe. Czy możesz mi jeszcze raz pomóc? –

+1

Zaktualizowałem moją odpowiedź. Nie testowałem tej metody, myślę, że wpadniesz na ten pomysł. –