2014-12-01 11 views
5

Das Formular besteht aus einer Frage, die mehrere Antworten hat, so dass die Antworten für jede Frage dynamisch erstellt werden können. Dieses Zeug alles funktioniert gut:symfony2 Formular, Sammlung von Objekten, Ausgabe Aktualisierung vorhandener Objekteigenschaften

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder 
     ->add('question','textarea') 
     ->add('answers', 'collection', array(
      'type'=>new AnswerType(), 
      'allow_add'=>true, 
      'allow_delete'=>true, 
      'label' => false 
     )) 
    ; 
} 

Hier Codeform für AnswerType:

$builder 
     ->add('answer','text', array(
      'attr'=>array(
       'class'=>'form-control' 
      ), 
      'label'=>false 
     )) 
     ->add('isGoodAnswer', 'checkbox', array(
      'label'=>'Good?', 
      'required'=>false 
     )) 
    ; 

I Prototyp template bin mit Container über jquery zu füllen.

Das Hinzufügen neuer Antwortobjekte zum Frageobjekt funktioniert einwandfrei. Löschen von Antworten ist auch kein Problem.

Wenn ich jedoch gehe, um vorhandene Eigenschaft auf einer der Sammelformulareingaben zu aktualisieren, wird das vorhandene Objekt nicht aktualisiert. Es bleibt jedoch das Frageobjekt bestehen, da es den Text der Frage selbst aktualisiert. Ich kann nur löschen und neu erstellen, um etwas aktuell zu ersetzen, und es fällt mir schwer, herauszufinden, warum.

Hier Code-Schnipsel aus der Schablonenform ist, die eingereicht wird:

<ul id="answer-fields-list" data-prototype="{{ form_widget(form.answers.vars.prototype)|e }}"> 
    {% for answer in form.answers %} 
     <li> 
      <div class='col-md-12'>     
       {{ form_widget(answer) }}     
       <div> 
        <a href='#' class='btn btn-sm btn-danger delete-this'><span class='glyphicon glyphicon-trash'></span></a> 
       </div> 
      </div>     
     </li> 
    {% endfor %} 
    </ul>   
    <a href="#" id="add-answer" class='btn btn-sm btn-success'><span class='glyphicon glyphicon-plus-sign'></span> Add Answer</a>   

bearbeiten, ist hier voll Controller-Code für dieses Update-Methode:

$question = $em->getRepository('ChecklistMainBundle:ChecklistQuestion')->findOneById($questionId); 
    if(!$question) throw new NotFoundHttpException('Question not found'); 

    $form = $this->createForm(new QuestionAnswerType(), $question); 

    $form->handleRequest($request); 

    if($request->getMethod()=='POST' && $form->isValid()) 
    { 
     if($form->get('attachment')->getData() != null) { 
      $question->uploadAttachment(); 
     } 
     $em->persist($question); 
     $em->flush(); 

     $this->get('session')->getFlashBag()->add('success', 'Question was modified successfully!'); 

     return $this->redirect($this->generateUrl('admin_checklists_view', array('id'=>$id))); 
    } 
+0

Sie sollten Code-Snippet teilen, wo Sie behandeln Eingabe –

+0

Hey Michal, ich mache nur '$ Form-> handleRequest ($ Anfrage);' dann persistent das $ -Frage-Objekt. Das Formular wird über symfony2 form builder erstellt: $ form = $ this-> createForm (new QuestionAnswerType(), $ question); ' – skrilled

+1

Ok, nur um zu verdeutlichen, dass ich richtig verstanden habe: Ihre Änderungen werden in der Datenbank beibehalten, das Objekt jedoch nicht in PHP-Code geändert und Form wird mit alten Sachen gerendert, oder? Ihr Ansatz sieht gut aus (nach dem Buch). Ich frage nach Code-Snippet, weil es vielleicht einen kleinen Fehler gibt, das Objekt neu zu erstellen, es erneut zu rendern, es aus der Datenbank zu lesen, anstatt vom Formular etc. –

Antwort

3

Nachdem ich stundenlang durch Google gesucht hatte, stieß ich auf eine doppelte Frage, die meiner ähnelte.

How to force Doctrine to update array type fields?

I durch setAnswers Verfahren eingestellt, wie diese Antwort zu reflektieren folgt:

public function setAnswers($answers) 
    { 
     if(!empty($answers) && $answers === $this->answers) { 
      reset($answers); 
      $answers[key($answers)] = clone current($answers); 
     } 
     $this->answers = $answers; 
     return $this; 
    } 

Es speichert jetzt bestehende Antworten in Ordnung, nicht mehr Probleme :)

+0

Sie haben keine Assoziationen angegeben und alle dachten, dass wir über eine OneToMany-Beziehung sprechen. Der elegantere Weg ist '$ uow-> propertyChanged ($ entity, $ propertyName, $ oldValue, $ newValue)' (zum Beispiel im Listener) aufzurufen. – origaminal

+0

Auch wenn Sie das Klonen bevorzugen, können Sie dies mit 'by_reference => false' in' AnswerType' Optionen tun. – origaminal

+0

Das ist nicht der Fall origaminal. Ich habe diese ausprobiert und es hat nichts für mich getan, das würde funktionieren, wenn ich mit verwalteten Entitäten anstatt mit einfachen PHP-Objekten arbeiten würde. Da ich mit einer Sammlung von Objekten anstelle einer Sammlung von Elementen arbeite, erkennt der Entitätsmanager nur, dass eine Änderung an der Sammlung vorgenommen wurde, aber keine Änderung an der Eigenschaft eines Objekts in der Sammlung. – skrilled

1

ich glaube, Sie verwenden sollten fusionieren das Objekt zu aktualisieren:

$em->merge($question) 
$em->flush(); 
+3

Die Entity Frage wird vom EntityManager gefunden, also bereits verwaltet. Lesen Sie [die Dokumente] (http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#merging-entities) nach was 'merge()' tatsächlich tut. Auch die Frage bleibt gut, es ist eine Antwort (in einem bestimmten Anwendungsfall), die nicht ist. –

1

Ein sie werden nicht persistieren.

Entweder:

foreach ($question->getAnswers() as $answer) { 

    $em->persist($answer); 
} 

$em->persist($question); 
$em->flush(); 

Oder (in Ihrer Frage Einheit):

/** 
* @ORM\OneToMany(targetEntity="YourBundle\Etc\Entity\Answer",mappedBy="question",cascade={"persist"}) 
*/ 

More info.

+2

Wenn Sie die standardmäßige Änderungsverfolgungsrichtlinie nicht geändert haben, aktualisiert sich eine verwaltete Entität _will_ selbst (oder vielmehr die Arbeitseinheit behält die Änderungen bei, die automatisch mit der Standardrichtlinie für die Änderungsverfolgung erfasst werden). –

+0

In dem Link, auf den verwiesen wird, steht: "Standardmäßig sind keine Operationen kaskadiert". Es sei denn, ich vermisse etwas, das scheint ziemlich abgeschnitten und getrocknet. Die Frage fragt, warum keine Änderungen an den Antwort-Entitäten bestehen und meine Antwort scheint von der Dokumentation unterstützt zu werden. – Richard

+1

'cascade = persist' stellt sicher, dass _new_ entities, die der Sammlung/Assoziation hinzugefügt wurden, beibehalten werden, was in der Regel nicht standardmäßig erfolgt. Aber wir reden über die Aktualisierung einer bestehenden Entität hier :) –

1

sowohl addAnswer() und removeanswer() auf Ihre Frage Einheit/Modell hinzufügen.

Set der by_reference Option Sammlung zu false

$builder 
     ->add('question','textarea') 
     ->add('answers', 'collection', array(
      'type'=>new AnswerType(), 
      'allow_add'=>true, 
      'allow_delete'=>true, 
      'label' => false, 
      'by_reference' = > false 
     )) 
    ; 
+0

Versucht dies, aber immer noch nur lassen Sie mich hinzufügen und entfernen, nicht vorhandene Objekte aktualisieren – skrilled

1

Sie können das Objektgraph vor und nach der handleRequest Aufruf zu vergleichen.

Ich rate Ihnen, \Doctrine\Common\Util\Debug::dump(); zu verwenden, wird es Ausgabe kürzer machen.

Eine andere Sache, die zu überprüfen ist, ist die rohe Anfrage Daten selbst, um zu sehen, ob die eingereichten Daten selbst korrekt ist: Verwenden Sie einfach das Formular Web Debug Toolbar Registerkarte (oder Anfrage, abhängig).

Jetzt warum es verhält sich wie das ist schwer zu beantworten. Die Sammlung Typ sehr unterschiedlich angegeben verhält konfigurieren Sie es mit by_reference oder nicht:

http://symfony.com/doc/current/reference/forms/types/collection.html

, wenn Sie die Sammlung Formulartyp verwenden, wenn die zugrunde liegende Sammlungsdaten ein Objekt (wie mit Lehre der Arraycollection) ist , dann muss by_reference auf false gesetzt werden, wenn der Setter (zB setAuthors()) aufgerufen werden muss.

und die https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php spielt definitiv eine große Rolle hier. Wie Sie sehen können, ist die Bestellung wichtig.

Überprüfen Sie, ob die übermittelten Daten in der erwarteten Reihenfolge vorliegen.

Last (oder vielleicht auch diese erste :) überprüfen), collection die meiste Zeit funktioniert :) zweimal Stellen Sie sicher, dass Ihre Getter und Setter keine knifflige Tippfehler enthalten, die die whiole Sache vermasselt:

Versuchen Sie es bei Bedarf manuell, indem Sie nachahmen, was die Formularkomponente tun würde.

Hoffe es hilft!

+0

Versucht all dies, im Prozess der Unordnung entdeckt, dass ich * vorhandene Objekte bearbeiten kann, wenn und nur wenn ich gleichzeitig ein anderes Objekt hinzufüge oder lösche. I.e. Wenn ich den Text einer Antwort bearbeite, aber gleichzeitig auch eine neue Antwort hinzufüge - funktioniert es. Immer noch versuchen, ein Mittel zu finden, um es ohne diese Schlupflöcher zu tun. – skrilled

Verwandte Themen