Symfony2 - 如何在使用表单类时设置和获取选项?

7

我正在使用表单类来构建项目中的各种表单。

在实体类型文件中,对于buildForm函数,有一个名为“array $options”的次要参数(这在官方Symfony 2文档中显示,但从未提到过!)

我已经在控制器中将一个数组传递给了createForm函数,但现在我完全不知道如何检索存储的值?

$form = $this->createForm(new ProductType(array(), array('id' => '2')), $product);

我发现获取选项的唯一方法是使用getOption()函数,但在Symfony 2中不存在(我找到的文章来自2010年)。
我尝试使用:
$id = $options['id'];

但是当我试图在任何地方使用 $id 时,我会收到以下错误提示:

注意:未定义索引:id

怎么回事?

我该如何从 $options 数组中检索我的值?我第一次是否正确设置了它们?

编辑-更多代码:

表单类

<?php

namespace DEMO\DemoBundle\Form\Product;

use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('slug')
            ->add('reference')
            ->add('description')
            ->add('active_from')
            ->add('active_till')
            ->add('is_active')
            ->add('category', 'entity', array(
                'class' => 'DEMO\DemoBundle\Entity\Product\ProductCategory',
                'query_builder' => function(EntityRepository $er) {
                    return $er->createQueryBuilder('u')
                        ->where('u.section = :id')
                        ->setParameter('id', ***ID VARIABLE NEEDS TO GO HERE***)
                        ->orderBy('u.root', 'ASC')
                        ->addOrderBy('u.lft', 'ASC');
                },
                'empty_value' => 'Choose an option',
                'property' => 'indentedName',
            ));
    }

    public function getDefaultOptions()
    {
        return array(
            'data_class' => 'DEMO\DemoBundle\Entity\Product\Product'
        );
    }

    public function getName()
    {
        return 'demo_demobundle_product_type';
    }
}
6个回答

17

我认为你在最开始的时候没有正确地设置它们。你应该将它们作为第三个参数传递给createForm()

编辑: 这是您的表单类应该如何编写:

<?php
namespace DEMO\DemoBundle\Form\Product;

use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('slug')
            ->add('reference')
            ->add('description')
            ->add('active_from')
            ->add('active_till')
            ->add('is_active')
            ->add('category', 'entity', array(
                'class' => 'DEMO\DemoBundle\Entity\Product\ProductCategory',
                'query_builder' => function(EntityRepository $er) use($options) {
                    return $er->createQueryBuilder('u')
                        ->where('u.section = :id')
                        ->setParameter('id', $options['id'])
                        ->orderBy('u.root', 'ASC')
                        ->addOrderBy('u.lft', 'ASC');
                },
                'empty_value' => 'Choose an option',
                'property' => 'indentedName',
            ));
    }

    public function getDefaultOptions()
    {
        return array(
            'data_class' => 'DEMO\DemoBundle\Entity\Product\Product',
            'id'         => null
        );
    }

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

1
我相信 createForm() 的第三个选项是用于设置选项,例如: "attr"、"by_reference"、"cascade_validation"、"csrf_field_name"、"csrf_protection"、"csrf_provider"、"data"、"data_class"、"disabled"、"empty_data"、"error_bubbling"、"error_delay"、"error_mapping"、"error_type"、"field_error_type"、"help_block"、"help_inline" 等等(基本上,我尝试了一下,它说 "id" 选项不存在。) - Mr Pablo
1
说实话,我不想去“黑客”任何核心结构。函数buildForm()显然有一个第二个参数来设置选项数组。我想知道它如何正确地被利用。 - Mr Pablo
该页面并未展示如何自定义getDefaultOptions()方法。它只展示了如何使用该方法的一些可用选项,例如CSRF保护和设置data_class。请明确指出在哪里展示了如何自定义该方法,以便我可以添加自己的参数? - Mr Pablo
不要问我,我只是实现了你的代码,它不起作用。 - Mr Pablo
显然,现在不再使用getDefaultOptions(),而是使用setDefaultOptions()。否则会显示:“选项“no_animal_type”不存在。已知选项为:“action”,“attr”,“auto_initialize”,...” - Bonswouar
显示剩余8条评论

9
让我展示一下对我有效的方法。
在控制器中:
$form = $this->createForm(new UsersType(), $entity, array(
    'attr' => array('locationId' => $currentLocationId)));

在 FormType 中:
->add('location', 'entity', array(
        'class' => 'Ro\RoinventBundle\Entity\Locations',
         'query_builder' => function (\Doctrine\ORM\EntityRepository $er) use ($options)
        {
            if (isset($options['attr']['locationId']) && ($options['attr']['locationId'] != NULL))
            {
                return $er->createQueryBuilder('Locations')
                    ->where('Locations.id = :param')
                    ->setParameter('param', $options['attr']['locationId']);
            }
            //else do what you want
},
));

8

显然,现在不是使用 getDefaultOptions() 方法了,而是使用 setDefaultOptions() 方法。

否则会出现如下错误:

选项“my_custom_option”不存在。已知的选项有:“action”,“attr”,“auto_initialize”等。

因此,我需要像这样更新 setDefaultOptions:

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array('my_custom_option' => false));
    // Others if needed, like in the documentation for : 'data_class' => 'VENDOR\Bundle\Entity\MyEntity', 'csrf_protection' => true
}

然后您可以在buildForm方法中检索它。

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $myCustomOption = $options['my_custom_option'];
}

5
根据Google Groups的说法,"greg0ire"是正确的,实际上我已经尝试过并且完美地运行了!你说:"我真的不想去“黑客”任何核心结构",但你最终使用了不是最好的方法...事实上,从我的角度来看,你最终做了你不想做的事情。
因此,最后你应该这样做:
在formType中:
public function buildForm(FormBuilder $builder, array $options)
{
    $builder
        ->add('name')
        ->add('slug')
        ->add('reference')
        ->add('description')
        ->add('active_from')
        ->add('active_till')
        ->add('is_active')
        ->add('category', 'entity', array(
            'class' => 'DEMO\DemoBundle\Entity\Product\ProductCategory',
            'query_builder' => function(EntityRepository $er) {
                return $er->createQueryBuilder('u')
                    ->where('u.section = :id')
                    ->setParameter('id', $options['id'])
                    ->orderBy('u.root', 'ASC')
                    ->addOrderBy('u.lft', 'ASC');
            },
            'empty_value' => 'Choose an option',
            'property' => 'indentedName',
        ));
}

public function getDefaultOptions()
{
    return array(
        'data_class' => 'DEMO\DemoBundle\Entity\Product\Product'
        'id' => null
    );
}

在控制器中:
$form = $this->createForm(new ProductType(), $product, array('id' => $id ));

1
将选项通过表单类的__construct方法传递,如下所示:
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class ProductType extends AbstractType
{

    private $options = array();
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('slug')
            ->add('reference')
            ->add('description')
            ->add('active_from')
            ->add('active_till')
            ->add('is_active')
            ->add('category', 'entity', array(
                'class' => 'DEMO\DemoBundle\Entity\Product\ProductCategory',
                'query_builder' => function(EntityRepository $er) {
                    return $er->createQueryBuilder('u')
                        ->where('u.section = :id')
                        ->setParameter('id', $this->options['id'])
                        ->orderBy('u.root', 'ASC')
                        ->addOrderBy('u.lft', 'ASC');
                },
                'empty_value' => 'Choose an option',
                'property' => 'indentedName',
            ));
    }

    public function getDefaultOptions()
    {
        return array(
            'data_class' => 'DEMO\DemoBundle\Entity\Product\Product'
        );
    }

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

    public function __construct(array $options)
    {
        $this->options = $options;
    }
}

然后你可以做:

new ProductType(array('id'=>1));

我尝试了这种方法,但最终出现了“未定义变量”的错误。我完全复制了它,所以我无法弄清楚为什么会出现这个错误,因为据我所知,该变量已经被设置了... - Mr Pablo
哈哈,是的,我几天前就弄清楚了,看看我的答案 :)谢谢帮助! - Mr Pablo

1

事实证明,Gregoire的答案非常接近,但是当我尝试将变量放入createQueryBuilder函数时,却给了我一个“未定义变量”的错误。

我花了一些时间来找出原因,并发现问题所在。您必须在“query_builder”选项中向函数添加一个额外的参数,就像这样:

'query_builder' => function(EntityRepository $er) use ($options) {
                    return $er->createQueryBuilder('u')
                        ->where('u.section = :id')
                        ->setParameter('id', $options['id'])
                        ->orderBy('u.root', 'ASC')
                        ->addOrderBy('u.lft', 'ASC');
                },

神奇的设置是"use ($options)"。这使您可以在查询构建器中成功使用$options['id']。


抱歉,实际上是采用了greg0ires的答案进行了实现,我复制代码时出错了。已经编辑过以澄清。 - Mr Pablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接