我正在尝试显示一种测验样式的表单,在该表单中,最终用户会收到可以具有一个或多个正确答案的问题。
实体:
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
字段。如果问题只有一个答案,而问题有多个答案,则不会显示复选框,我得到的是一组不相关的字段(输入)。非常感谢您的帮助!
[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属性,如果它不添加有关无效内容的注释,而我自己实现,则这应该可以解决您的问题