2017-07-25 7 views
1

Das Problem, das ich habe, ist in Bezug auf Symfony (3) Formbuilder. Ich habe 3 Entitäten, für die ich 3 FormTypes erstellt habe. Siehe unten; tatsächliche Frage unter dem Code.Speichern mehrerer eingebetteter Formulare mit dem Symfony-Formbuilder, mehrere Vorläufe funktionieren gut 1 Ebene tief, geht 2 Ebenen tief. (1-zu-viele),

Ich habe folgende Einheiten:

DocumentBaldoc 1 -> * DocumentBaldocConnectionPoint 1 -> * DocumentBaldocAccount

Ich versuche, die folgenden zu erreichen. Ich möchte ein Formular für ein DocumentBaldoc erstellen, ich möchte mehrere Formulare für DocumentBaldocConnectionPoints erstellen und ich möchte mehrere Formulare für DocumentBaldocConnectionPointAccounts erstellen. Wenn gespeichert, müssen diese in der Datenbank mit der Relation (fk) gespeichert werden.

Ich habe folgende Klasse für DocumentBaldoc (Form)

namespace FooBundle\Form\Documents\Baldoc; 

use FooBundle\Entity\Documents\Baldoc\DocumentBaldoc; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\Extension\Core\Type\SubmitType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 
use Symfony\Component\Form\Extension\Core\Type\CollectionType; 

class DocumentBaldocType extends AbstractType 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('document_release') 
      ->add('identification') 
      ->add('version') 
      ->add('type') 
      ->add('creationDateTime') 
      ->add('validityPeriod') 
      ->add('contractReference') 
      ->add('contractType') 
      ->add('issuerMarketParticipantIdentification') 
      ->add('issuerMarketParticipantIdentificationCodingScheme') 
      ->add('issuerMarketParticipantMarketRoleCode') 
      ->add('recipientMarketParticipantIdentification') 
      ->add('recipientMarketParticipantIdentificationCodingScheme') 
      ->add('recipientMarketParticipantMarketRoleCode') 
      ->add('applicationContext') 
      ->add('applicationContextCodingScheme') 
      ->add('connectionPoints', CollectionType::class, [ 
       'entry_type' => DocumentBaldocConnectionPointType::class, 
       'allow_add' => true, 
       'by_reference' => false, 
      ]) 
      ->add('save', SubmitType::class); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => DocumentBaldoc::class 
     )); 
    } 
} 

I die folgende Klasse für DocumentBaldocConnectionPoint (Form)

namespace FooBundle\Form\Documents\Baldoc; 

use FooBundle\Entity\Documents\Baldoc\DocumentBaldocConnectionPoint; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\Extension\Core\Type\CollectionType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 

class DocumentBaldocConnectionPointType extends AbstractType 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('identification') 
      ->add('identificationCodingScheme') 
      ->add('measureUnitCode') 
      ->add('accounts', CollectionType::class, [ 
       'entry_type' => DocumentBaldocAccountType::class, 
       'allow_add' => true, 
       'by_reference' => false, 
      ]); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => DocumentBaldocConnectionPoint::class 
     )); 
    } 
} 

und ich habe die folgende Klasse für DocumentBaldocAccount (Form) haben

namespace FooBundle\Form\Documents\Baldoc; 

use FooBundle\Entity\Documents\Baldoc\DocumentBaldocAccount; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolver; 

class DocumentBaldocAccountType extends AbstractType 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('identification') 
      ->add('identificationCodingScheme') 
      ->add('accountTso') 
      ->add('accountTsoCodingScheme'); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function configureOptions(OptionsResolver $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => DocumentBaldocAccount::class 
     )); 
    } 

} 

Ich benutze Symfony's Formbuilder zum Generieren der Formular für die DocumentBaldoc-Entität. Indem ich einen CollectionType mit dem DocumentBaldocConnectionPoint als entry_type hinzufüge, kann ich die Prototypvariable in der Vorlage verwenden.

{% block DOCUMENT %} 
    {{ form_start(form) }} 
    <ul class="connectionPoints" 
     data-prototype="{{ form_widget(form.connectionPoints.vars.prototype)|e('html_attr') }}"> 
     {{ form_widget(form) }} 
    </ul> 
    {{ form_end(form) }} 
{% endblock %} 

Danach kann ich einige Javascript verwenden, um einen endlosen Strom von DocumentBaldocConnectionPoint Formulare zu erstellen und wenn ich diese (mehrere !!) DocumentBaldocConnectionPoints in der DB mit einem FK an die Mutter DocumentBaldoc gespeichert sind, drücken Sie speichern.

Bis jetzt funktioniert das perfekt, aber das Problem kommt, wenn ich das gleiche für DocumentBaldocConnectionPointAccount tun möchte. Das DocumentBaldocConnectionPoint Formular existiert nicht auf Pagelad, so dass ich nicht direkt auf das Prototypattribut zugreifen kann, löste ich dies, indem ich einige Javascript-Logik erstelle, die ausgelöst wird, wenn ein DocumentBaldocConnectionPoint-Formular erstellt wird. Es folgt dann der gleichen Logik wie seine Eltern. Das Problem, auf das ich stoße, ist, dass ich nicht mehrere DocumentBaldocConnectionPointAccounts speichern kann. Es speichert immer das Letzte, was mich denken lässt, dass es irgendwo im Prozess nicht als Array gespeichert wird oder irgendwo das Array vom letzten Eintrag überschrieben wird. Ich habe ein paar Tage lang daran herumgebastelt, kann aber keine Unterschiede in der Logik finden (Formtypen oder Entitäten, die Beziehungsdefinitionen folgen der gleichen Struktur), was mich denken lässt, dass ich das nicht so verwende, wie es verwendet werden soll .

Dies sind die Anmerkungsbeziehungsdefinitionen für beide Entitäten. Sowohl $ connectionPoints als auch $ accounts werden als ArrayCollections im Konstruktor der Entity instanziiert.

// DocumentBalcon 
@ORM\OneToMany(targetEntity="DocumentBaldocConnectionPoint", mappedBy="document", cascade={"persist"}) 
private $connectionPoints; 

// DocumentBalconConnectionPoint 
@ORM\OneToMany(targetEntity="DocumentBaldocAccount", mappedBy="connectionPoint", cascade={"persist"}) 
private $accounts; 

Das einzige, was auffällt, ist, dass der Prototyp der DocumentBaldocConnectionPoint Form mit der __name__ Syntax gemacht wird, die mit einer eindeutigen Kennung ersetzt werden muss und dass die gleiche Sache nicht passiert, wenn ich den DocumentBaldocConnectionPointAccount Prototyp greifen Ich habe das gelöst, indem ich einen eigenen Bezeichner erstellt habe, um die Eindeutigkeit zu garantieren.

Ich habe die Symfony-Dokumentation über Formbuilder gelesen und diese Art von eingebetteten Formularen erstellt, aber die Dokumentation besagt nur, dass das, was ich zu tun versuche, ohne Beispiele möglich ist. Ich habe keine Ahnung, ob das, was ich mache, ein richtiger Weg ist, diese Art von eingebetteten Formen zu handhaben oder dass mir einige Schritte im Prozess fehlen.

Alle Informationen oder Hilfe zu diesem Problem ist mehr als willkommen!

Antwort

0

Problem gelöst.

Das erste untergeordnete Dokument DocumentBaldocConnectionPoint enthielt auch das Attribut Prototyp, das das Formular für DocumentBaldocConnectionPointAccount enthält. Beim Ändern des __name__-Werts im DocumentBaldocConnectionPoint wurden die Werte für DocumentBaldocConnectionPointAccount ebenfalls unbeabsichtigt geändert, was zu dem unerwarteten Verhalten führte, dass jedes DocumentBaldocConnectionPointAccount-Formular im Array mit dem Wert 'index' abgelegt wurde, der nur pro DocumentConnectionPoint geändert wurde.

Die Lösung, die ich verwenden, ist wie folgt:

in der DocumentBaldocConnectionPointType Klasse in der Funktion buildForm ich den Prototyp Schlüssel mit dem Wert „Konten“ hinzugefügt, die mir die Möglichkeit gibt, den Prototyp mit Namen Bezug zu holen.

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder 
     ->add('identification') 
     ->add('identificationCodingScheme') 
     ->add('measureUnitCode') 
     ->add('accounts', CollectionType::class, [ 
      'entry_type' => DocumentBaldocAccountType::class, 
      'allow_add' => true, 
      'by_reference' => false, 
      'prototype' => 'accounts' 
     ]); 
} 

Im Zweig Vorlage habe ich ein div, wie folgend:

<div id="prototypes" 
    data-prototype-account="{{ form_widget(form.connectionPoints.vars.prototype.children['accounts'].vars.prototype) | e }}" 
    data-prototype-connection-point="{{ form_widget(form.connectionPoints.vars.prototype) | e }}"> 
</div> 

Dies führt zu einem div, wo die Prototypen Formen gespeichert sind und gibt mir die Möglichkeit, sie auf einfache Weise abzufragen und bei Bedarf zu verwenden.

Verwandte Themen