Мне нужно управлять ответами на форму в моем проекте Symfony.В настоящее время у меня есть 4 объекта:
- MyForm представляет глобальную форму
- QuestionsBlock представляет блок вопросов
- Вопрос представляет вопрос
- ModelQuestion представляет значение вопроса по умолчанию
В моем классе MyFormType у меня есть атрибут CollectionType типа QuestionsBlockType.Действительно, я хотел бы динамически добавлять / удалять блоки вопросов в моей форме.Но каждый блок вопросов должен содержать вопросы, основанные на объектах типовых вопросов.
Например, если в моей базе данных есть 5 записей questionModel, я хочу, чтобы каждый раз при добавлении блока вопросов создавалось 5 новых вопросов.Когда я передаю вопросы в конструкторе QuestionsBlock, я пытаюсь создавать новый экземпляр QuestionsBlock с параметром каждый раз, когда в CollectionType создается новая запись.
Чтобы добиться этого, я увидел в документе, что яможет использовать атрибут prototype_data для CollectionType: https://symfony.com/doc/current/reference/forms/types/collection.html#prototype-data
При использовании этой опции дочерние типы отображаются на экране, но, похоже, объекты не создаются при отправке формы.
Итак, я увидел, что могу использовать атрибут empty_data в QuestionBlockType для создания экземпляра с параметром: https://symfony.com/doc/current/form/use_empty_data.html
Но, похоже, этого недостаточно.Я знаю, что «код empty_data» выполняется, когда я сохраняю форму, но у меня появляется ошибка «Слишком мало аргументов для функции Question :: __ construct (), 0 передано и ожидается ровно 1».Поэтому я предполагаю, что конструктор QuestionsBlock вызывается при отправке, но я не могу понять, почему он пытается создать экземпляр Question без аргументов.
Что мне делать?
Контроллер
public function addAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$models = $em->getRepository(QuestionModel::class)->findAll();
$myForm = new MyForm();
$form = $this->createForm(MyFormType::class, $myForm, ['models' => $models]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($myForm);
$em->flush();
return $this->redirectToRoute('...');
}
return $this->render('Admin/MyForm/add_edit.html.twig', array(
'myForm' => $myForm,
'models' => $models,
'form' => $form->createView()
));
}
MyForm Entity
/**
* MyForm
*
* @ORM\Table(name="my_form")
* @ORM\Entity()
*/
class MyForm
{
/**
* @ORM\OneToMany(targetEntity="QuestionsBlock", mappedBy="myForm", cascade={"persist", "remove"})
*/
private $questionsBlocks;
...
}
QuestionBlocks Entity
/**
* QuestionsBlock
*
* @ORM\Table(name="questions_block")
* @ORM\Entity()
*/
class QuestionsBlock
{
/**
* @ORM\OneToMany(targetEntity="question", mappedBy="questionsBlock", cascade={"persist", "remove"})
*/
private $questions;
public function __construct($models)
{
$this->questions = new ArrayCollection();
foreach ($models as $model) {
$this->addQuestion(new Question($model));
}
}
...
}
Вопрос Entity
/**
* Question
*
* @ORM\Table(name="question")
* @ORM\Entity()
*/
class Question
{
/**
* @ORM\ManyToOne(targetEntity="ModelQuestion")
*/
private $modelQuestion;
public function __construct($modelQuestion)
{
$this->modelQuestion = $modelQuestion;
}
...
}
MyForm Type
class MyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$models = $options['models'];
$builder
->add('questionsBlocks', CollectionType::class, array(
'entry_type' => QuestionsBlockType::class,
'required' => true,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false,
'prototype_data' => (new QuestionBlock($models))
))
->add('save', SubmitType::class, array(
'label' => 'Enregistrer'
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => MyForm::class,
'models' => []
));
}
}
QuestionsBlock Type
class QuestionsBlockType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('questions', CollectionType::class, array(
'entry_type' => QuestionType::class,
'required' => true,
'allow_add' => true,
'allow_delete' => true,
'delete_empty' => true,
'by_reference' => false
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'empty_data' => function (FormInterface $form) {
return new QuestionsBlock($form->getRoot()->getConfig()->getOption('models'));
},
'data_class' => QuestionsBlock::class
));
}
}
Тип вопроса
class QuestionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, array(
'label' => 'Titre',
'required' => false
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Question::class
));
}
}