Symfony 4测验样式形式,嵌入式集合类型

问题描述 投票:0回答:1

我正在尝试显示一种测验样式的表单,在该表单中,最终用户会收到可以具有一个或多个正确答案的问题。

实体:

Exam Question

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Ramsey\Uuid\UuidInterface;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ExamQuestionRepository")
 */
class ExamQuestion
{
    use TimestampableEntity;

    /**
     * @var UuidInterface
     *
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Module", inversedBy="questions")
     * @ORM\JoinColumn(nullable=false)
     */
    private $module;

    /**
     * @ORM\Column(type="text")
     */
    private $text;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\ExamQuestionAnswer", mappedBy="question", orphanRemoval=true, cascade={"persist"})
     */
    private $examQuestionAnswers;

    /**
     * @ORM\Column(type="boolean")
     */
    private $hasMultipleAnswers;

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

    public function __toString()
    {
        return $this->text;
    }

    public function getId(): ?UuidInterface
    {
        return $this->id;
    }

    public function getModule(): ?Module
    {
        return $this->module;
    }

    public function setModule(?Module $module): self
    {
        $this->module = $module;

        return $this;
    }

    public function getText(): ?string
    {
        return $this->text;
    }

    public function setText(string $text): self
    {
        $this->text = $text;

        return $this;
    }

    /**
     * @return Collection|ExamQuestionAnswer[]
     */
    public function getExamQuestionAnswers(): Collection
    {
        return $this->examQuestionAnswers;
    }

    public function addExamQuestionAnswer(ExamQuestionAnswer $examQuestionAnswer): self
    {
        if (!$this->examQuestionAnswers->contains($examQuestionAnswer)) {
            $this->examQuestionAnswers[] = $examQuestionAnswer;
            $examQuestionAnswer->setQuestion($this);
        }

        return $this;
    }

    public function removeExamQuestionAnswer(ExamQuestionAnswer $examQuestionAnswer): self
    {
        if ($this->examQuestionAnswers->contains($examQuestionAnswer)) {
            $this->examQuestionAnswers->removeElement($examQuestionAnswer);
            // set the owning side to null (unless already changed)
            if ($examQuestionAnswer->getQuestion() === $this) {
                $examQuestionAnswer->setQuestion(null);
            }
        }

        return $this;
    }

    public function getHasMultipleAnswers(): ?bool
    {
        return $this->hasMultipleAnswers;
    }

    public function setHasMultipleAnswers(bool $hasMultipleAnswers): self
    {
        $this->hasMultipleAnswers = $hasMultipleAnswers;

        return $this;
    }
}
Exam Question Answer

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Ramsey\Uuid\UuidInterface;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ExamQuestionRepository")
 */
class ExamQuestionAnswer
{
    use TimestampableEntity;

    /**
     * @var UuidInterface
     *
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\ExamQuestion", inversedBy="examQuestionAnswers")
     * @ORM\JoinColumn(nullable=false)
     */
    private $question;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isCorrect;

    /**
     * @ORM\Column(type="text")
     */
    private $text;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $selected;

    public function __toString()
    {
        return $this->text;
    }

    public function getId(): ?UuidInterface
    {
        return $this->id;
    }

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

    public function setQuestion(ExamQuestion $question): self
    {
        $this->question = $question;

        return $this;
    }

    public function getIsCorrect(): ?bool
    {
        return $this->isCorrect;
    }

    public function setIsCorrect(bool $isCorrect): self
    {
        $this->isCorrect = $isCorrect;

        return $this;
    }

    public function getText(): ?string
    {
        return $this->text;
    }

    public function setText(string $text): self
    {
        $this->text = $text;

        return $this;
    }

    public function getSelected(): ?bool
    {
        return $this->selected;
    }

    public function setSelected(?bool $selected): self
    {
        $this->selected = $selected;

        return $this;
    }
}
Exam Take

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Ramsey\Uuid\UuidInterface;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ExamTakeRepository")
 */
class ExamTake
{
    use TimestampableEntity;

    /**
     * @var UuidInterface
     *
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\ExamQuestion")
     */
    private $questions;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Module", inversedBy="examTakes")
     * @ORM\JoinColumn(nullable=false)
     */
    private $module;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Student", inversedBy="examTakes")
     * @ORM\JoinColumn(nullable=false)
     */
    private $student;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $passed;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\ExamQuestionStudentAnswer", mappedBy="examTake", orphanRemoval=true)
     */
    private $examQuestionStudentAnswers;

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

    public function getId(): ?UuidInterface
    {
        return $this->id;
    }

    /**
     * @return Collection|ExamQuestion[]
     */
    public function getQuestions(): Collection
    {
        return $this->questions;
    }

    public function addQuestion(ExamQuestion $question): self
    {
        if (!$this->questions->contains($question)) {
            $this->questions[] = $question;
        }

        return $this;
    }

    public function removeQuestion(ExamQuestion $question): self
    {
        if ($this->questions->contains($question)) {
            $this->questions->removeElement($question);
        }

        return $this;
    }

    public function getModule(): ?Module
    {
        return $this->module;
    }

    public function setModule(?Module $module): self
    {
        $this->module = $module;

        return $this;
    }

    public function getStudent(): ?Student
    {
        return $this->student;
    }

    public function setStudent(?Student $student): self
    {
        $this->student = $student;

        return $this;
    }

    public function getPassed(): ?bool
    {
        return $this->passed;
    }

    public function setPassed(?bool $passed): self
    {
        $this->passed = $passed;

        return $this;
    }

    /**
     * @return Collection|ExamQuestionStudentAnswer[]
     */
    public function getExamQuestionStudentAnswers(): Collection
    {
        return $this->examQuestionStudentAnswers;
    }

    public function addExamQuestionStudentAnswer(ExamQuestionStudentAnswer $examQuestionStudentAnswer): self
    {
        if (!$this->examQuestionStudentAnswers->contains($examQuestionStudentAnswer)) {
            $this->examQuestionStudentAnswers[] = $examQuestionStudentAnswer;
            $examQuestionStudentAnswer->setExamTake($this);
        }

        return $this;
    }

    public function removeExamQuestionStudentAnswer(ExamQuestionStudentAnswer $examQuestionStudentAnswer): self
    {
        if ($this->examQuestionStudentAnswers->contains($examQuestionStudentAnswer)) {
            $this->examQuestionStudentAnswers->removeElement($examQuestionStudentAnswer);
            // set the owning side to null (unless already changed)
            if ($examQuestionStudentAnswer->getExamTake() === $this) {
                $examQuestionStudentAnswer->setExamTake(null);
            }
        }

        return $this;
    }
}

和表格:

class ExamTakeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('questions', CollectionType::class, [
                'entry_type' => ExamQuestionType::class,
                'allow_add' => false,
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => ExamTake::class,
        ]);
    }
}
class ExamQuestionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('text', TextType::class, [
                'attr' => ['readonly' => true],
            ])
            ->add('examQuestionAnswers', CollectionType::class, [
                'entry_type' => ExamQuestionAnswerType::class,
                'allow_add' => false,
            ])
        ;

    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => ExamQuestion::class,
        ]);
    }
}
class ExamQuestionAnswerType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('text');

        $builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) {

            $form = $event->getForm();

            /** @var ExamQuestion $question */
            $question = $event->getData()->getQuestion();

            if ($question->getHasMultipleAnswers()) {
                $form
                    ->add('select', ChoiceType::class, [
                        'expanded' => true,
                        'multiple' => true,
                        'mapped' => false,
                    ]);
            } else {
                $form
                    ->add('select', ChoiceType::class, [
                        'expanded' => true,
                        'multiple' => false,
                        'mapped' => false,
                    ]);
            }
        });
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => ExamQuestionAnswer::class,
        ]);
    }
}

似乎我无法正确显示集合中的examQuestionAnswers字段。如果问题只有一个答案,而问题有多个答案,则不会显示复选框,我得到的是一组不相关的字段(输入)。非常感谢您的帮助!

php symfony doctrine-orm doctrine symfony-forms
1个回答
0
投票

[ChoiceType需要选择属性”

if ($question->getHasMultipleAnswers()) {
                $form
                    ->add('select', ChoiceType::class, [
                        'choices' => $question->getExamQuestionAnswers(),
                        'expanded' => true,
                        'multiple' => true,
                        'mapped' => false,
                    ]);
            } else {
                $form
                    ->add('select', ChoiceType::class, [
                        'choices' => $question->getExamQuestionAnswers(),
                        'expanded' => true,
                        'multiple' => false,
                        'mapped' => false,
                    ]);
            }

这将把$ examQuestionAnswers作为选择项放入ChoiceType。万一发生异常,将类型更改为EntityType(它继承自ChoiceType),因此选择应该仍然起作用。您可能还需要在您的ExamQuestionAnswer实体中实现__toString()方法或定义choice_label属性,如果它不添加有关无效内容的注释,而我自己实现,则这应该可以解决您的问题

© www.soinside.com 2019 - 2024. All rights reserved.