Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony One To Many not linking parent

I have a Quiz structure with 3 entities:

  • Quiz has Questions (OneToMany)
  • Question has Quiz (ManyToOne)
  • Question has Answers (OneToMany)
  • Answer has Question (ManyToOne)

The code looks like such:

Quiz Entity

class Quiz
{    
    /**
     * @ORM\OneToMany(targetEntity="Question", mappedBy="quiz", cascade={"persist", "remove"})
     */
    private $questions;

    public function __construct() {
        $this->questions = new ArrayCollection();
    }

    public function addQuestion(\Cariboo\QuizBundle\Entity\Question $questions)
    {
        $questions->setQuiz( $this );
        // die(); Not dying here...
        $this->questions[] = $questions;

        return $this;
    }

    public function removeQuestion(\Cariboo\QuizBundle\Entity\Question $questions)
    {
        $this->questions->removeElement($questions);
    }

    public function getQuestions()
    {
        return $this->questions;
    }
}

Question Entity

class Question
{
    /**
     * @ORM\OneToMany(targetEntity="Answer", mappedBy="question", cascade={"persist", "remove"})
     */
    private $answers;

    /**
     * @ORM\ManyToOne(targetEntity="Cariboo\QuizBundle\Entity\Quiz", cascade={"persist"})
     */
    private $quiz;

    public function addAnswer(\Cariboo\QuizBundle\Entity\Answer $answers)
    {
        $answers->setQuestion( $this );
        $this->answers[] = $answers;

        return $this;
    }

    public function removeAnswer(\Cariboo\QuizBundle\Entity\Answer $answers)
    {
        $this->answers->removeElement($answers);
    }

    public function getAnswers()
    {
        return $this->answers;
    }

    public function setQuiz(\Cariboo\QuizBundle\Entity\Quiz $quiz = null)
    {
        $this->quiz = $quiz;

        return $this;
    }

    public function getQuiz()
    {
        return $this->quiz;
    }
}

Answer entity

class Answer
{
    /**
     * @ORM\ManyToOne(targetEntity="Cariboo\QuizBundle\Entity\Question")
     */
    private $question;

    public function setQuestion(\Cariboo\QuizBundle\Entity\Question $question = null)
    {
        $this->question = $question;

        return $this;
    }

    public function getQuestion()
    {
        return $this->question;
    }
}

I cascade persist them.

I configured my setters as explained in Cascaded persist not working (Doctrine ORM + Symfony 2)

The addAnswer gets executed and for answers, the Question is set properly. However the addQuestion does not set the quiz.

image of what gets dumped upon sending the form

I can add a foreach in my controller but I am not satisfied with this, as I feel I am not exploiting symfony's power. ( No duplicate of Entity doesn't associate correctly )

    if ( $form->isValid() ) {
        foreach ( $quiz->getQuestions() as $question ) {
            $question->setQuiz( $quiz );
        }
        $em = $this->getDoctrine()->getManager();
        $em->persist( $quiz );
        $em->flush();

        return $this->redirect( $this->generateUrl( 'quiz_show', array(
            'slug' => $quiz->getSlug()
        ) ) );
    }

I cannot figure out why the addQuestion does not get executed.

Edit

My Quiz form

    $builder
        ->add( 'questions', 'collection', array(
            'type' => new QuestionType(),
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'prototype_name' => '__qst_prot__'
        ) )
    ;

Partial builder of Question

    $builder
        ->add( 'question', 'text' )
        ->add( 'answers', 'collection', array(
            'type' => new AnswerType(),
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'prototype_name' => '__asw_prot__'
        ) );

My Answer form

$builder
        ->add( 'answer', 'text' )
        ->add( 'correct' )
    ;
like image 800
Reynald Lechapt Avatar asked Feb 25 '16 10:02

Reynald Lechapt


1 Answers

Problem is in collection form type. You need to set by_reference to false if you want to call parent entity setter.

Symfony docs:

Similarly, if you're using the CollectionType field where your underlying collection data is an object (like with Doctrine's ArrayCollection), then by_reference must be set to false if you need the adder and remover (e.g. addAuthor() and removeAuthor()) to be called.

Read more here: http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference

like image 108
Paweł Mikołajczuk Avatar answered Nov 15 '22 00:11

Paweł Mikołajczuk