1

我正在创建一个动态的问题/答案表格。我需要为仅与登录用户相关的给定部分显示一组答案字段。数据模型为:

Section有很多SectionQuestion(一个section代表表单的一个页面)SectionQuestion有一个问题和很多答案答案有一个用户和一个SectionQuestion

我的表单代码是:

//SectionFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('sectionQuestions', 'collection', array(
            'type' => new SectionQuestionFormType($this->answerListener),
            'label' => false
        ))
        ->add('save', 'submit');
}

//SectionQuestionFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->addEventSubscriber($this->answerListener);
}

//AnswerListener.php
public function preSetData($event)
{
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) {
        return;
    }

    $form->add(
        'answers',
        'collection',
        array(
            'type' => new AnswerFormType($data->getQuestion()),
            'auto_initialize' => false,
            'label' => false,
            'required' => false,
        )
    );
}

//AnswerFormType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{

    $fieldType = $this->question->getAnswerType();

    $config = array(
        'required' => true,
        'label'    => $this->question->getText(),
        'auto_initialize' => false
    );

    if ($fieldType == 'choice') {
        $valueList = $this->question->getValueList();
        $values = $valueList->loadChoiceList();

        $config['choice_list'] = $values;
        $config['empty_value'] = 'Please select one';
    }

    $builder->add('answer', $fieldType, $config);
}

这段代码是功能性的,但不是我真正需要的。我需要在 AnswerListener 中添加的集合来提供与当前登录用户相关的现有答案尚未输入答案的空白答案的混合。

  1. 我知道,与其在 AnswerListener 'answers' 中命名集合字段(与 SectionQuestions 中的关系属性匹配),我可以将其命名为 'filteredAnswers' 并在 SectionQuestions 实体类中编写一个 getter/setter 来返回答案的子集. 但!我无法访问 Entity 类的 getter 中的登录用户。

  2. 我也无法将字段类型更改为实体,因为据我所知,我将无法规定使用 AnswerFormType 表单,这至关重要,因为它使用我的问题中的值设置答案字段标签实体(实际问题文本)。

  3. 在 AnswerListener 中,我可以使用 $form->add($this->factory->createNamed(....)) 并以这种方式提供数据子集(因为我可以访问 AnswerListener 中的实体管理器登录用户类并执行查询)。但!我不知道如何使它成为一个集合字段类型。我可以像这样使用 createNamed 使表单正确显示:

    $form->add(
        $this->factory->createNamed(
            'answer', 
            new AnswerFormType(
                $data->getQuestion()), 
                $answer, 
                array(
                        'auto_initialize' => false,
                        'mapped' => false,
                        'label' => false
                 )
            )
        )
    )
    

...但!这只会将单个答案字段添加到表单中,因此发布的值永远不会保存到数据库中(可能是因为 SectionQuestions 希望通过未达到的“答案”属性添加它们)。

似乎我每一次都被难住了。关于如何让这个工作的任何想法?

4

1 回答 1

0

好的,我自己想通了。如上文第 3 点所述,我必须嵌入单独的“答案”表格。如前所述,SectionQuestions 通过 $answers 属性与 Answer 相关,该属性期望是一个集合,因此我无法保存表单。为了解决这个问题,我在 createNamed 中使用了 'mapped' => false 选项,并将表单数据作为数组访问。在代码中更容易看到,所以这里是:

//AnswerListener.php
public function preSetData($event)
{
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) {
        return;
    }

    $answerRepository = $this->entityManager
                             ->getRepository('RecruitmentCoreBundle:Answer');

    $answer = $answerRepository->findOneBy(
        array(
            'sectionQuestion_id' => $data->getId(),
            'user_id' => $authenticated_user_id
        )
    );

    if(!$answer) {
     $answer = null;
    }

    $form->add(
        $this->factory->createNamed(
            'answer',
            new AnswerFormType($data->getQuestion()),
            $answer,
            $formOptions = array (
                'auto_initialize' => false,
                'mapped' => false,
                'label' => false,

            )
        )
    );
}

您可以在这里看到我检查数据库以查看登录用户是否已经为给定的 SectionQuestion 提供了答案。如果有,则将其传递给 createdNamed,如果没有,则传递 null 并在屏幕上显示一个空白的答案表单字段。

为了保存表单,我有一个如下所示的服务:

//FormService.php
class FormService
{
    private $formFactory;
    private $entityManager;
    private $sectionForm;

    /**
     * @param FormFactoryInterface $factory
     * @param EntityManager $em
     * @param SectionFormType $form
     */
    public function __construct(
         FormFactoryInterface $factory, 
         EntityManager $em, 
         SectionFormType $form)
    {
        $this->formFactory = $factory;
        $this->entityManager = $em;
        $this->sectionForm = $form;
    }

    public function generateSectionForm($roundId, $sectionId)
    {

        $sectionRepository = $this->entityManager
                                  ->getRepository('RecruitmentCoreBundle:Section');

        $section = $sectionRepository->findOneBy(array('id' => $sectionId));

        return $this->formFactory->create($this->sectionForm, $section);
    }


    public function saveSectionAnswers($form, Section $section)
    {
        foreach($form['sectionQuestions'] as $sectionQuestion) {

            $answer = $sectionQuestion['answer']->getData();

            if (null === $answer->getId()) {
                $sectionQuestion = $sectionQuestion->getData();
                $answer->setSectionQuestion($sectionQuestion);
                $answer->setUser(//logged in user);
            }

            $this->entityManager->persist($answer);
        }

        $this->entityManager->flush();

        return $form;
    }
}

即使我在 AnswerListener.php 中的 createNamed 方法调用中使用了 'mapped' => false,您也可以在我的 FormService 类的 saveSectionAnswers 方法中看到 $sectionQuestion['answer']->getData(); 返回一个 Answer 对象。这填充了给定 SectionQuestion 的提交表单数据,然后我可以将其保存到数据库中。大概提供了 Answer 对象,因为我在 AnswerFormType.php 类中将 Answer 实体定义为 data_class:

//AnswerFormType.php
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(
         array(
        'data_class' => 'Recruitment\CoreBundle\Entity\Answer'
         )
    );
}

无论如何,它可以正常工作并提供我需要的功能。

于 2013-11-12T13:00:18.657 回答