以symfony4形式在CollectionType上使用query_builder吗?

时间:2018-12-19 04:57:30

标签: symfony symfony4

在symfony 4格式中,我需要使用类似query_builder的选项,该选项在EntityType上可用,但可以在CollectionType上使用。存在类似的问题here,但没有很好的答案。

在我的项目中,每个Site实体都有许多Goal。每个Goal都有一个数字目标和一个特定日期。我只想编辑特定日期的网站目标。问题在于,CollectionType表单会提取 all 个目标以在表单中显示,但是我只想在给定日期内提取目标。怎么样? query_builder上没有CollectionType上的EntityType。我可以在Site实体中更改吸气剂,但是我不知道如何将所需的日期传递给吸气剂。

现在,我的解决方法是呈现整个表单(具有给定站点的所有关联目标),然后使用一些javascript隐藏所有目标(带有编辑日期的目标除外)。这行得通,但是对于目标范围跨越日期范围的网站来说,这是一个糟糕的解决方案。

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

class Site
{
    public function __construct()
    {
        $this->goals = new ArrayCollection();
    }

    /** @ORM\OneToMany(targetEntity="App\Entity\Goal", mappedBy="site") */
    private $goals;


    public function getGoals()
    {
        return $this->goals;
    }
}

和我相关的Goal实体:

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,
        ]);
    }
}

2 个答案:

答案 0 :(得分:1)

使用Form Events,同时避免使用CollectionType表单的allow_addallow_delete选项,可能会使您进入正确的邻居:

首先-为了方便示例,我们假设按年份进行过滤,并且年份是从?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]);
    // ...
}

这意味着我们应该更新SiteGoalsAdminForm类的默认选项:

<?php

// SiteGoalsAdminForm.php

// ...
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
          'data_class' => Site::class,
          'year_filter' => 2018
        ]);
     }
// ...

然后,在同一类的buildForm方法中,我们可以访问Site对象,并从其中删除Goals,如果目标日期的年份不属于表单的< / p>

<?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,
                ]);
            }
        );
    }

    // ...
}

并非完全是query_builder,但功能相似。

答案 1 :(得分:0)

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

$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']);
}

buildForm的{​​{1}}方法中,通过选项将数据设置为“收集类型”字段。

SiteGoalsType::class

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

'mapped' => false