Symfony2容器感知表单类型

时间:2014-01-10 14:57:24

标签: symfony doctrine

有没有办法让表单类型容器知道?

作为一个例子,我有3个实体账户,用户和事件。用户具有ManyToMany关系,以便将许多用户与许多其他用户(称为批准者)相关联,原因是用户创建的事件可以包含能够批准该区域的用户列表。在用户编辑表单中,我有一个批准者多个选择字段,列表需要按帐户过滤,因此我需要我的表单类型才能识别容器,以便按帐户ID过滤可用用户列表。

我认为让表单类型容器知道是正确的方法吗?我想使用实体管理器按帐户筛选用户列表。

3 个答案:

答案 0 :(得分:8)

1 通过构造函数

注入实体管理器
<?php

namespace Acme\YourBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityManager;

class YourType extends AbstractType
{

    /**
     * The entity manager
     *
     * @var EntityManager
     */
    private $entityManager;

    /**
     * @param EntityManager
     */
    public function __construct(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       //build your form here



    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\YourBundle\Entity\YourEntity',
        ));
    }

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

}

2 将其声明为服务

services:
    # Form type
    acme_your_bundle.name_of_your_form.form.type:
        class: Acme\YourBundle\Form\Type\YourType
        arguments:
            entityManager: "@doctrine.orm.entity_manager"

注意:

如果您从Symfony开始,请接受以下建议:

仔细查看FOSMessageBundle的代码,它将准确地为您提供在symfony中所做的任何事情,从表单模型到表单工厂,再到创建特殊服务(如composer,authorizer)等等。)。你学习这个包的次数越多,你学习symfony的速度就越快,我向你保证100%。最后,在您的具体情况下,请查看FormFactory in this bundle

答案 1 :(得分:5)

此解决方案允许您将容器注入多种形式,而不是每种表单类型都是服务:

创建新的表单类型:

class ContainerAwareType extends AbstractType implements ContainerAwareInterface
{

    protected $container;

    public function setContainer(ContainerInterface $container = null) {
        $this->container = $container;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'container' => $this->container
        ));
    }

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

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

宣布为服务:

services:
    app.container_aware_type:
        class: Burgerfuel\CmsBundle\Form\Type\ContainerAwareType
        calls:
          - [setContainer, ['@service_container']]
        tags:
            - { name: form.type, alias: 'container_aware' }

此类型现在可用作任何其他表单类型的“父级” - 无论是否为服务。在这种情况下,重要的部分是来自此类的setDefaultOptions将用于帮助构建将传递到任何“子”表单类型的$options参数。

在任何表单类型中,您都可以执行此操作:

class MyType extends AbstractType
{
    public function getParent() {
        return 'container_aware';
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $container = $options['container'];
        $builder->add( ...

如果由于某种原因无法使表单类型成为服务,则此解决方案将非常有用。 或者,如果您要创建许多需要访问容器的类型,它可以节省您的时间。

答案 2 :(得分:0)

一种简单的方法,无需执行任何依赖注入/声明服务。

在您的FormType文件中,强制表单需要EntityManager

//..    
use Doctrine\ORM\EntityManager;

class YourFormType extends AbstractType
{
    //...
    //...
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\YourBundle\Entity\YourEntity',
        ));
        $resolver->setRequired('entity_manager');
        $resolver->setAllowedTypes('entity_manager', EntityManager::class);
    }
}

然后您将能够(并且强制 - 对测试非常重要),从控制器传递实体管理器。

public function yourControllerAction(Request $request)
{
    //..
    $em = $this->getDoctrine()->getManager();
    $form = $this->createForm('Acme\YourBundle\Form\YourEntityType', $yourEntityObject, array(
                'entity_manager'=>$em,
            )); 
    $form->handleRequest($request);
    //..
}
相关问题