Symfony2 form, collection of objects, release update of an existing property of an object

The form consists of one question, which has several answers, so that answers can be dynamically created for each question. This stuff works fine:

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

Here is the form code for AnswerType:

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

I am using a prototype template to populate a container through jquery.

Adding new answer objects to the question object works fine. Removing answers is also not a problem.

However, if I proceed to update an existing property on one of the inputs of the collection form, it does not update the existing object. It saves the question object, although it will update the text of the question itself. I can only delete and create a new one to replace something now, and it’s hard for me to understand why.

Here is the code snippet from the template form that was submitted:

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

edit, here is the full controller code for this update method:

  $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))); } 
+5
source share
5 answers

After searching through Google for hours, I came across a duplicate question similar to mine.

How to force Doctrine to update array type fields?

I configured the setAnswers method as follows to reflect this answer:

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

Now it keeps existing answers in order, more problems :)

+3
source

I think you should use merge to update the object:

 $em->merge($question) $em->flush(); 
+1
source

Responses will not be saved.

Or:

 foreach ($question->getAnswers() as $answer) { $em->persist($answer); } $em->persist($question); $em->flush(); 

Or (in the question object):

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

Additional Information.

+1
source

Add both addAnswer() and removeanswer() to the question object / model.

Set collection by_reference option to false

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

You can compare the graph of an object before and after calling handleRequest .

I advise you to use \Doctrine\Common\Util\Debug::dump(); This will make the conclusion shorter.

Another thing to check is the raw request data to make sure the data presented is correct: just use the tab of the web debugging toolbar of the form (or the request, depending).

Now why is he acting like this is hard to answer. The type of the collection behaves in a very different way, since you are setting it with by_reference or not:

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

if you are using a collection form type where your collection base data is objects (e.g. with Doctrine ArrayCollection), then the by_reference parameter should be set to false if you need to call setter (e.g. setAuthors ()).

and https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php definitely play a big role here. As you can see, ordering is important.

Make sure the data presented is in the expected order.

Last (or maybe check it first :)), most of the time collection just works :) Double-check that your getters and setters don't contain a complex typo that messes up the case:

Try manually, if necessary, by simulating what the form component will do.

Hope this helps!

+1
source

Source: https://habr.com/ru/post/1208088/


All Articles