基于表单选择的Symfony动态表单

时间:2013-12-31 05:02:43

标签: php forms symfony

假设我们有表格,我们必须为客户选择会员类型。每种类型的成员都有不同数量的共同成员(选择字段的实体类型),可以为该成员选择什么。

现在我需要实现表单,根据成员资格类型选择将选择字段的实体类型的数量添加到表单中。

当表单已呈现为前端时,成员资格类型选择将为bade。

问题可能过于笼统,但我应该如何实现这个FormType?

我看过这个coockbook条目: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data 但据我所知,EventListener在常规表单呈现期间工作,因此在它显示到前端之前。我应该实现AJAX hocus pocus以形成MembershipType字段,所以当它被选中时,整个表单会再次呈现吗?

这种任务的一般逻辑是什么?

1 个答案:

答案 0 :(得分:3)

正如@keyboardSmasher在评论中提到的,多步形式策略可能是一个很好的解决方案。有很多方法可以实现这一点,但我们可以稍微探讨一下。

首先,表单事件不仅在呈现之前有用。您可以在多个点拦截表单呈现过程。您可以检测到记录是新记录,并且只有在这种情况下才显示(或不显示)特定字段。您可以在保留之前更改新提交的表单数据。您只能向具有正确权限的人员显示字段(使用表单工厂作为注入此安全上下文的服务),或者甚至根据某些标准显示用户要连接的朋友列表,如菜谱中所示。表单事件非常强大。此外,您还可以创建一个custom validator来检查所选的选项是否允许,在您的情况下,选择的成员资格,我强烈建议这样做(这与表单非常分开,应该更多与您的模型/文档/实体/等密切相关。)

如果我理解正确,您希望显示包含特定类型成员资格的选项的多选字段。在用户选择成员资格类型后,该选择字段(称为MembershipSubOptions)将填充选项。我希望这是对的。请注意,除了我快速搜索的几个链接之外,以下是我的头脑,这已经很晚了,但它应该与你想要达到的目标有些接近。

你可以从基本的ajax开始(我不建议使用hocus pocus,这些东西真的很奇怪;-))。在客户端,您可以使用诸如Select2之类的库来通过ajax轻松填充MembershipSubOptions。根据选择填充选择的成员资格设置返回选项(json)的路径。现在你有一个select填充了与该成员类型相关的选项,如果我理解正确,那些选项来自数据存储,所以从表单的角度看它是一个实体类型。

我猜你希望用户从这个选择字段中选择多个选项,这些选项可能存储为该用户的ManyToMany关系。由于我们在这里处理实体类型,我们需要转换提交的数据,以便表单组件知道如何处理它。让我们创建一个相当空的MembershipSubOptionsType表单类型。它看起来如下所示:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class MembershipSubOptionsType extends AbstractType
{
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(

            )
        );
    }

    public function getParent()
    {
        return 'hidden';
    }

    public function getName()
    {
        return 'membership_suboptions';
    }
}

在主窗体中为子选项选择字段添加如下内容。您会注意到我引用$ this-em并将其传递给变换器。将您的表单设置为由注册为服务的工厂类进行管理,并注入Doctrine Manager,以便获取所需的实体记录。

$membershipSubOptionsTransformer = new MembershipSubOptionsTransformer($this->em);
$builder->add($builder->create('membershipSubOptions', new \My\GreatBundle\Form\Type\MembershipSubOptionsType(), array(
                'required'      => true, // or false if they arent required
                'label'         => 'membership.suboptions.label',
                'attr'          => array(
                    'class'     => 'membershipSubOptionsSelect',
                    'data-placeholder' => 'Select some options'
                )
            ))->addModelTransformer($membershipSubOptionsTransformer))

现在您已准备好以某种方式实际处理membershipSubOptions。在客户端的select中,每个都只是一个字符串或整数,但在你的应用程序中,它们代表一个真实的记录/模型/实体。表单知道将提交的数据传递给现在仍需要构建的变换器。要完成这项工作而不是最终写一本小说,请查看Data Transformer documentation。实际的变压器比以往任何时候都要清楚得多。

现在,您可以使用在呈现表单时最初未提供的相关选项动态填充某些选择字段。有趣的是,数据转换器是双向的,因此在编辑表单时,将设置当前设置的选项,当它们最初提交或更新时,它们将“转换”为您的应用程序理解的内容。

我会为没有成员资格的新记录设置选项字段隐藏,并在选择成员资格后将其设置为js可见。对于编辑表单,您需要使用表单事件(或类似方法)将可见性设置为可见。

我希望所有这些都有道理。就像我说的那样,头顶如此YMMV,但我希望这会让你走上正确的道路。我确信还有很多其他方法可以完成你想要做的事情,所以我也期待着阅读其他人的想法。请让我们都知道您的最终解决方案是什么样的,这样我们都会更加了解情况。