【问题标题】:How to manage only one oneToMany entity in parent form如何在父表单中只管理一个 oneToMany 实体
【发布时间】:2017-02-02 17:32:38
【问题描述】:

我有一个实体Criteria,它可以有多个实体Vote(关联)。 我想显示一个标准列表并在每个标准前面只显示一个投票表格(不是零,不是很多),以允许用户为每个标准投票。

但是,由于我有一个 oneToMany 关联,因此在我的 CriteriaForm 中,我必须有一个 CollectionType 投票(我认为?)。我试图只有一个 VoteType :

$builder->add('votesCritere', VoteCritereType::class);

但我有一个错误:

The form's view data is expected to be an instance of class LabelBundle\Entity\VoteCritere, but is an instance of class Doctrine\ORM\PersistentCollection

所以我想我必须有一个 CollectionType。但是,如果我有一个集合类型,我会从零形式开始(因为我的标准还没有包含任何投票)。

我只想(并且总是)在每个标准前面有一个投票表格,以添加对标准的投票(我不希望表格的数量反映投票的数量)

我该怎么做?

感谢您的帮助!

【问题讨论】:

  • 所以,您需要一个仅基于标准列表的复选框(或...)列表 - 对吧?还是 vote 有一些属性要填写?
  • 标准不会被修改。仅针对每个标准投票(并且不是必需的)。投票将有两个单选按钮和一个用于填写注释的文本区域。

标签: forms symfony


【解决方案1】:

让我们大声思考 - 如果您使用实体绑定表单和集合类型进行投票,它总是会显示您所有将绑定到每个条件的投票。

在这种情况下,我会推荐基于标准实体 ID 的表单数组。

创建投票表单类型:

class VoteType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('answer', ChoiceType::class, array(
                'choices' => array(
                    'Yes' => true,
                    'No' => false,
                )
            ))
            ->add('note', TextareaType::class),
            ->add('criteriaId', HiddenType::class),
            ->add('vote', SubmitType::class);
    ...
    ...
}

在控制器中 - 获取可遍历的条件(例如存储库的方法 findAll() 方法)并根据条件实体 ID 创建命名表单数组:

$ff = $this->get('form.factory');
foreach ($criterias as $criteria) {
    $voteForms[] = $ff->createNamedBuilder(
        'vote_'.$criteria->getId(),
        new VoteType,
        array(
            'criteriaId' => $criteria->getId()
        )
    )
    ->getForm()
    ->createView();

}

return $this->render(someView, array("voteForms" => $forms));

提交表单后,您可以通过隐藏的 criteriaId 字段确定投票属于哪个标准。

编辑 - 新增:如何一键提交所有表单

不再需要在 VoteType 中提交的“criteriaId”字段和“投票” - 所以:

class VoteType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('answer', ChoiceType::class, array(
                'choices' => array(
                    'Yes' => true,
                    'No' => false,
                )
            ))
            ->add('note', TextareaType::class);
    ...
    ...
}

在控制器中创建带有 VoteTypes 成员的表单:

$fb = $this->createFormBuilder();
foreach ($criterias as $criteria) {
    $fb->add('vote-criteria-'.$criteria->getId(), VoteType::class);
}
$fb->add('submit', SubmitType::class);
$frm = $fb->getForm();

$frm->handleRequest($request);

if ($frm->isSubmitted() && $frm->isValid()) {
    // all criteria vote data
    $frm->getData();
    ...
}

return $this->render(someView, array('form' => $frm->createView()));

【讨论】:

  • 谢谢 Honza,似乎是个好主意。但是如果可以的话,我宁愿一键提交所有表单(因为我也有一个 globalVote,并且要对每个标准进行投票,我必须进行 globalVote,所以我不能只允许做一个标准投票)。有什么想法吗?
  • 好的,我明白你想让我做什么。但我认为我使用嵌入式表单做了同样的事情。因此,表单希望我添加一个 CollectionType,因为我可以为每个 Criteria 设置多个 Vote。如果我放了一个 CollectionType,我就没有表格(可能是因为我还没有投票?)。我不想要与投票数相对应的表格数量,但始终只有一个表格。也许我误解了什么?
  • 如果你有一个实体绑定表单,它总是取决于实际实体的状态。因此,在您的情况下,如果标准还没有任何投票,则不会呈现任何形式。如果您想要一个,则必须在呈现表单之前将新的投票实体分配给标准。可以理解吗?
  • 好的,我明白了!但是如果我已经有几个投票,我将显示几个表格。在不删除所有选票的情况下如何避免这种情况?
  • 实体绑定表单就是这样工作的——它非常适合编辑现有数据,但对于您的特定需求,您不能简单地省略现有记录。这就是我建议上述解决方案的原因。
猜你喜欢
  • 2012-10-02
  • 1970-01-01
  • 2014-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多