是否在symfony4表单中的CollectionType上使用查询生成器?

是否在symfony4表单中的CollectionType上使用查询生成器?,symfony,symfony4,Symfony,Symfony4,在symfony4表单中,我需要使用类似于query\u builder的选项,该选项在EntityType上可用,但来自CollectionType。有一个类似的问题没有很好的答案 在我的项目中,每个站点实体都有许多目标。每个目标都有一个数字目标和一个特定日期。我只想编辑特定日期的网站目标。问题是CollectionType表单会将所有目标拉入表单中显示,但我只想拉入给定日期的目标。怎么用?在CollectionType上没有像在EntityType上那样的query\u builder。我可

在symfony4表单中,我需要使用类似于
query\u builder
的选项,该选项在
EntityType
上可用,但来自
CollectionType
。有一个类似的问题没有很好的答案

在我的项目中,每个
站点
实体都有许多
目标
。每个
目标都有一个数字目标和一个特定日期。我只想编辑特定日期的网站目标。问题是CollectionType表单会将所有目标拉入表单中显示,但我只想拉入给定日期的目标。怎么用?在
CollectionType
上没有像在
EntityType上那样的
query\u builder
。我可以在我的站点实体中更改getter,但我不知道如何将所需的日期传递给getter

目前,我的工作是呈现整个表单(带有给定站点的所有相关目标),然后使用一些javascript隐藏所有目标,除了那些带有编辑日期的目标。这是可行的,但对于那些目标跨越一系列日期的网站来说,这是一个糟糕的解决方案

我的
网站
实体(仅显示相关代码):

以及我的相关
目标
实体:

class Goal
{
    /** @ORM\Column(type="date") */
    private $goalDate;

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

    /** @ORM\ManyToOne(targetEntity="App\Entity\Site", inversedBy="goals") */
    private $site;

    // ...
}
我的表格:

class SiteGoalsAdminForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('goals', CollectionType::class, [
                'entry_type' => GoalsEmbeddedForm::class,
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Site::class
        ]);
    }
}
个人目标表:

class GoalsEmbeddedForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('goal', IntegerType::class)
            ->add('goalDate', DateType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Goal::class,
        ]);
    }
}
在避免使用
CollectionType
表单的和选项的同时,使用可能会使您处于正确的环境中:

首先-为了方便起见,让我们假设我们是按年份过滤的,并且年份是从
?y=2018
样式的查询字符串中提取出来的。我们将把该信息传递给表单生成器:

<?php
// Inside a *Action method of a controller

public function index(Request $request): Response
{
    // ...
    $filteredYear = $request->get('y');
    $form         = $this->createForm(SiteGoalsAdminForm::class, $site, ['year_filter' => $filteredYear]);
    // ...
}
然后,在同一类的
buildForm
方法中,我们可以访问
站点
对象,并从中删除
目标
,其中目标日期的年份不在表单的

<?php

// SiteGoalsAdminForm.php

namespace App\Form;

// ... other `use` statements, plus:
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class SiteGoalsAdminForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) use ($options) {
                $form = $event->getForm();
                /** @var Site */
                $site  = $event->getData();
                $goals = $site->getGoals();

                foreach ($goals as $g) {
                    if ($g->getGoalDate()->format('Y') !== (string) $options['year_filter']) {
                        $site->removeGoal($g);
                    }
                }

                $form->add('goals', CollectionType::class, [
                    'entry_type' => GoalsEmbeddedForm::class,
                ]);
            }
        );
    }

    // ...
}

使用要在集合类型上设置的控制器中的实体管理器过滤结果

$goals = $entityManager->getRepository(Goals::class)->findBy(['year' => 2020]);
$form = $this->createForm(SiteGoalsType::class, $site, [
   'goals' => $goals
]);
然后配置
SiteGoalsType::class
以接受新的选项目标

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => Site::class,
    ]);
    $resolver->setRequired(['goals']);
}
SiteGoalsType::class
buildForm
方法中,从选项中将数据设置为集合类型字段

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('goals', Type\CollectionType::class, [
        'entry_type' => GoalsEmbeddedType::class,
        'data' => $options['goals'],
        'mapped` => false
    ]);
}
确保将
'mapped'=>false添加到您的集合类型字段,否则可能会导致删除我们在控制器中编写的筛选器中未包含的记录

$goals = $entityManager->getRepository(Goals::class)->findBy(['year' => 2020]);

我认为,
CollectionType
的选项意味着提交的表单数据属于集合中的所有实体。在特定的日期范围内只编辑
Goal
s可能在
CollectionType
之外做得更好。实际上,我可能完全错了!如果编辑(而不是删除或添加新内容)是路线中这些
目标的唯一关注点,那么最好使用!谢谢@Cameronhard。你是对的,我不需要在这个应用程序中添加/删除目标,我只需要编辑现有的目标。表单事件的想法很有趣,但很难看到如何应用于整个实体数组和相关参数。哇,这是严重的symfony表单巫毒!!非常感谢,它工作得很好。
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('goals', Type\CollectionType::class, [
        'entry_type' => GoalsEmbeddedType::class,
        'data' => $options['goals'],
        'mapped` => false
    ]);
}
$goals = $entityManager->getRepository(Goals::class)->findBy(['year' => 2020]);