在 symfony4 形式的 CollectionType 上使用 query_builder ? [英] Use query_builder on CollectionType in symfony4 forms?

查看:30
本文介绍了在 symfony4 形式的 CollectionType 上使用 query_builder ?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 symfony 4 形式中,我需要使用类似 query_builder 的选项,该选项在 EntityType 上可用,但来自 CollectionType.此处有一个类似的问题,但没有很好的答案.

In a symfony 4 form, I need to use something like a query_builder option that is available on EntityType but from a CollectionType. There is a similar question here with no good answers.

在我的项目中,每个Site 实体都有许多Goal.每个 Goal 都有一个数字目标和一个特定的日期.我只想编辑特定日期的网站目标.问题是 CollectionType 表单将 all 目标拉入表单中,但我只想拉出给定日期的目标.如何?CollectionType 上没有 query_builder,就像在 EntityType 上一样.我可以更改 Site 实体中的 getter,但我不知道如何将所需的日期传递给我的 getter.

In my project, each Site entity has many Goal. Each Goal has a numeric goal and a specific date. I'd like to edit the goals of a site for a specific date only. The problem is that a CollectionType form pulls all goals to show in the form, but I only want to pull the goals for a given date. How? There is no query_builder on a CollectionType like there is on an EntityType. I could change the getter in my Site entity, but I don't know how to pass the needed date to my getter.

现在我的解决方法是呈现整个表单(包含给定站点的所有相关目标),然后使用一些 javascript 隐藏所有目标,但要编辑日期的目标除外.这是有效的,但对于具有跨越多个日期范围的大量目标的网站来说,这是一个糟糕的解决方案.

For now my work-around is to render the entire form (with ALL associated goals for a given site), and then use some javascript to hide all goals except those with the date to edit. This works, but it's a terrible solution for sites with lots of goals spanning a range of dates.

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

My Site entity (only relevant code is shown):

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

推荐答案

使用 表单事件,同时避免 allow_addCollectionType 表单的nofollow noreferrer">allow_delete 选项可能会让您找到正确的社区:

Using Form Events, while avoiding the allow_add and allow_delete options for the CollectionType form might land you in the right neighbourhood:

首先 - 让我们假设我们按年份过滤,以方便示例,并且年份是从 ?y=2018 样式的查询字符串中提取的.我们会将这些信息传递给表单构建器:

First - let's assume we're filtering by year, for ease of example, and that the year is being scooped up from a ?y=2018 style of querystring. We'll pass that info down to the form builder:

<?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 类的默认选项:

This implies we should be updating the default options for the SiteGoalsAdminForm class:

<?php

// SiteGoalsAdminForm.php

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

然后,在同一个类的 buildForm 方法中,我们可以访问 Site 对象并从中删除 Goals目标日期不属于表单的

Then, in the buildForm method of that same class, we could access the Site object and remove Goals from it where the year of the goalDate did not fall inside the form's

<?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,但功能相似.

Not a query_builder exactly, but functionally similar.

这篇关于在 symfony4 形式的 CollectionType 上使用 query_builder ?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆