Choice根据实体属性键入多个属性(如何在返回实体集合或一个实体之间进行选择)



我正在做一个测试项目,使用Symfony框架(4.4版(和Doctrine作为ORM。

Answer和Question实体之间存在ManyToOne关系,就像QuizQuestion和Answer实体一样。我使用QuizQuestion实体在测验、问题和所选答案之间建立链接。

我使用EntityType";QuizQuestionType";将multiple属性设置为true以收集答案,并且它按预期工作:

$builder
->add('answers', EntityType::class, [
'class' => Answer::class,
'choices' => $this->fillAnswers($quizQuestion),
'expanded' => true,
'multiple' => true,
]);

问题是,我希望能够将问题设置为多选或单选。如果我将EntityType multiple属性设置为false,我会得到错误:

类型为"的实体;条令\ORM\PersistentCollection"传递给必须管理选项字段。也许你忘了在实体经理?

我可以使用具有OneToMany和OneToOne关系的两个答案实体,但对我来说,这似乎是一个非常糟糕的设计。

我想知道如何做到这一点,理想情况下,使用Question实体中的属性来指示这是一个多选题还是唯一选择题。这将允许我在后台简单地声明它(因为从技术上讲,一个多选题可能只有一个好答案,所以我不能用答案的数量来计算它(。

你知道我怎样才能做到这一点吗?

以下是概念数据模型:

CDM-

答案实体:https://pastebin.com/kiRTHnvL

QuizQuestion实体:https://pastebin.com/wL3v9fwT

谢谢你的帮助,

编辑日期:2020年8月1日

根据@victor-vasiloi的建议,我在表单类型中添加了一个事件侦听器,以便设置正确的扩展。不过我无法添加变压器。我在这里找到了解决方案,并创建了一个扩展来使用来自事件侦听器的数据转换器:

测验问题类型

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($builder){
$quizQuestion = $event->getData();
$form = $event->getForm();
if ($quizQuestion->getQuestion()->getIsMultiple()){
$form->add('answers', EntityType::class, [
'class' => Answer::class,
'choices' => $this->fillAnswers($quizQuestion),
'expanded' => true,
'multiple' => true,
]);
} else {
$form->add('answers', EntityType::class, [
'class' => Answer::class,
'choices' => $this->fillAnswers($quizQuestion),
'expanded' => true,
'multiple' => false,
'model_transformer' => new CollectionToAnswerTransformer(),
]);
}
})
;
}

模型转换器扩展

class ModelTransformerExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
// return FormType::class to modify (nearly) every field in the system
return [FormType::class];
}
public function buildForm(FormBuilderInterface $builder, array $options) {
parent::buildForm($builder, $options);
if (isset($options['model_transformer'])) {
$builder->addModelTransformer($options['model_transformer']);
}
}
public function configureOptions(OptionsResolver $resolver) {
parent::configureOptions($resolver);
$resolver->setDefaults(array('model_transformer' => null));
}
}

现在可以加载表单了。然而,在提交时(在带有单选按钮的唯一答案的情况下(,CollectionToArrayTranformer给出了以下错误:

预期的参数类型为"App\Entity\Answer"阵列";在属性路径";答案";。

我尝试了一个自定义CollectionToAnswerTransformer,它看起来像这样:

class CollectionToAnswerTransformer implements DataTransformerInterface
{
/**
* @param mixed $collection
* @return mixed|string
*/
public function transform($collection)
{
if (null === $collection){
return '';
}
else
{
foreach ($collection as $answer){
return $answer;
}
}
}
/**
* @param mixed $answer
* @return ArrayCollection|mixed
*/
public function reverseTransform($answer)
{
$collection = new ArrayCollection();
$collection->add($answer);
return $collection;
}
}

但没有更好的结果。我得到错误:

预期的参数类型为"App\Entity\Answer"的实例条令\Common\Collections\ArrayCollection"在属性路径中给定"答案";。

看起来反向转换器方法有问题,但如果我更改它以返回实体,我会得到相反的错误:

无法确定属性"的访问类型;答案";在课堂上"App\Entity\QuizQuestion":财产";答案";在课堂上"App\Entity\QuizQuestion"可以用方法定义"addAnswer(("removeAnswer(("但新值必须是数组或Traversable的实例;应用程序\实体\答案"鉴于

我想我差不多了,但我不知道我的变压器是可行的,还是更容易。。。

要设置单选题,可以使用单选按钮和复选框进行多选。单选按钮被展开";真";以及多个";false";。复选框被展开";真";以及多个";真";。显示复选框的代码示例:

$builder
->add('filter', EntityType::class, array(
'class' => 'FilterBundle:Filter',
'multiple' => true,
'expanded' => true,
'required' => true
));

来源:https://symfony.com/doc/current/reference/forms/types/choice.html#select-标签复选框或单选按钮

如果你想在显示之前为每个问题定义它,那么你的问题实体上可能有一个字段(例如布尔值"倍数"(。

您可以在SymfonyComponentFormFormEvents::PRE_SET_DATA事件上使用表单事件监听器,根据给定的Question动态设置multiple选项,在这里您可以了解有关动态修改表单和表单事件的更多信息。

使用相同的逻辑,当multiple选项设置为true时,您可以像$builder->get('answers')->addModelTransformer(new CollectionToArrayTransformer());一样将SymfonyBridgeDoctrineFormDataTransformerCollectionToArrayTransformer模型转换器添加到答案字段,这将确保条令集合和选项数组(包括单选(之间的转换。

最新更新