I have a next tables: quiz, question, and question_quiz. I have a many-to-many relationship. Insertion work right for table quiz and question, but in table question_quiz inserted only single record.
My tables
"question", it's all right.
+----+--------+
| id | title |
+----+--------+
| 61 | Title1 |
| 62 | Title2 |
| 63 | Title3 |
+----+--------+
"quiz", it's all right.
+----+-------+--------+
| id | name | status |
+----+-------+--------+
| 27 | Name1 | 0 |
+----+-------+--------+
"question_quiz"
+-------------+---------+
| question_id | quiz_id |
+-------------+---------+
| 61 | 27 |
+-------------+---------+
In last table must be inserted 61,62,63 quiestion_id, but inserted only single record.
Fragment of my controller.
$quiz = new Quiz();
$question = new Question();
$form = $this->get('form.factory')->createNamed('quiz', QuizType::class, $quiz);
$quiz->getQuestions()->add($question);
$question->addQuiz($quiz);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($quiz);
$em->persist($question);
$em->flush();
}
The call evidence of a question entity.
$quiz->getQuestions()->add($question);
$question->addQuiz($quiz);
I use the collection type, and I can insert any number of questions.
UPDATE QuizType form.
class QuizType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array('attr' => ['class' => 'form-control name-quiz'], 'label' => 'Name Quiz'))
->add('status', CheckboxType::class, array(
'label' => 'Status Quiz',
'required' => false))
->add('save', SubmitType::class, ['label' => 'Add', 'attr' => ['class' => 'btn btn-primary']]);
$builder
->add('questions', CollectionType::class, array(
'entry_type' => QuestionType::class,
'entry_options' => array('label' => false),
'allow_add' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Quiz::class
]);
}
}
if I debug the method addQuestion()
I got error INSERT INTO question (title) VALUES (?)' with params [null]. But if I dubug method addQuiz I get
Question {#583 ▼
-id: null
-title: "123"
-quiz: ArrayCollection {#584 ▼
-elements: array:1 [▼
0 => Quiz {#581 ▼
-id: null
-name: "123"
-questions: ArrayCollection {#580 ▶}
-status: false
}
]
}
-answers: ArrayCollection {#585 ▶}
}
The debug $form->get('questions')->getData() return
ArrayCollection {#733 ▼
-elements: array:2 [▼
0 => Question {#736 ▶}
1 => Question {#981 ▶}
]
}
Without Quiz
and Question
entities - it is hard to tell. BUT
I think the problem is in your controller.
$quiz = new Quiz();
$question = new Question();
//...
$question->addQuiz($quiz);
So you create a new Quiz, which should have multiple questions, right? But you asign a question only once..
$question->addQuiz($quiz);
so the right way would be like (a bit verbose so you can get the point)
$quiz = new Quiz();
//Q 1
$question_1 = new Question('Title1');
$quiz->addQuestion( $question_1 );
//Q 2
$question_2 = new Question('Title2');
$quiz->addQuestion( $question_2 );
//Q 3
$question_2 = new Question('Title3');
$quiz->addQuestion( $question_3 );
$em->persist($question_1);
$em->persist($question_2);
$em->persist($question_2);
$em->persist($quiz);
$em->flush();
Take a look at this example (https://gist.github.com/Ocramius/3121916) for ManyToMany relation and especial to addUSerGroup()
and addUser()
methods.
Try the suggested method in a controller (without form) and see if it works and if you get more than one rows into question_quiz
table
UPDATE:
I think the "magic" you're looking for is cascade={"persist"}
in your Quiz Entity. Take a look at this article (https://knpuniversity.com/screencast/collections/add-new-collection-cascade-persist). Even though the video isn't free, the text is fine.
1)set up cascade
in yout entity
2)updated you addQuestion()
method in Quiz class like following
public function addQuestion(Question $question)
{
// do not add same questions more than once.
if ($this->questions->contains($question)) {
return;
}
$this->questions[] = $question; // to add new question to that quiz
$question->addQuiz($this); // this quiz now also belongs to a question
}
3) get embed collection to work with prototype
=> http://symfony.com/doc/current/form/form_collections.html. So you can add new Questions on the fly
4)After submit, just call:
if ($form->isSubmitted() && $form->isValid()) {
$quiz = $form->getData();
$em->persist($quiz);
$em->flush();
}
4.1)If that doesn't work, try looping over the submitted collection of questions
if ($form->isSubmitted() && $form->isValid()) {
$quiz = $form->getData();
// since getQuestions() gives you an ArrayCollection, isEmpty is a built in method
if(!$quiz->getQuestions()->isEmpty())
{
// this is kinda bad, but you'll have to debug and play around
foreach ($quiz->getQuestions() as $new_question)
{
$em->persist($new_question);
}
}
$em->persist($quiz);
$em->flush();
}