Symfony 2如何找到自定义表单类型?

时间:2011-12-11 12:27:50

标签: forms dependency-injection symfony

我正在阅读Data Transformations我在代码中对其进行了一些修改。我正在

  

无法加载类型“csv2tags”

我有自定义表单类型

class CSV2TagsType extends AbstractType {
    public function buildForm(FormBuilder $builder, array $opts) {
        $builder->appendClientTransformer(new CSV2TagsTransformer());
    }
    public function getParent() {
        return 'text';
    }
    public function getName() {
        return 'csv2tags';
    }
}

使用变压器:

class CSV2TagsTransformer implements DataTransformerInterface {
    /**
     * @var EntityManager
     */
    protected $em;
    public function __construct(EntityManager $em) {
        $this->em = $em;
    }
    // ... 
}

services.yml

services:
    jm.blog.csv2tagsTransformer:
        class: JM\BlogBundle\Form\DataTransformer\CSV2TagsTransformer
        arguments: ["@doctrine.orm.entity_manager"]

几个问题:

  • 我将EntityManager移到变换器而不是表单类型,是吗?
  • 我没有像文档那样为变换器服务声明别名。我认为表单类型的别名来自AbstractType::getName()函数?我是否需要将自定义表单类型声明为服务
  • 我将EntityManager移到变压器上。当我new CSV2TagsTransformer()没有EntityManager时,我做了正确的事吗?

2 个答案:

答案 0 :(得分:3)

我将完成@ greg0ire给出的答案,这几乎是正确的。

首先,您定义的服务应该是您的表单类型(CSV2TagsType)而不是您的转换器(CSV2TagsTransformer),因为它是表单构建器使用的表单类型。由于表单生成器需要AbstractType,因此它不适用于您的服务定义,因为数据转换器不是AbstractType。正如@ greg0ire所说,您必须使用form.type标记标记自定义表单类型。

services:
  jm.blog.csv2tagsType:
    class: JM\BlogBundle\Form\Type\CSV2TagsType
    arguments: ["@doctrine.orm.entity_manager"]
    tags:
      - { name: form.type, alias: csv2tags }

自定义表单类型中函数getName返回的值必须与您提供的别名(cvs2tags)或您定义的服务ID(jm.blog.csv2tagsType)相匹配。这是Symfony可以找到您的自定义类型的方式。它试图找到getName()方法给出的服务ID。

对于您的数据转换器,存在一个小问题。您正在执行new CSV2TagsTransformer(),但您没有通过实体管理器。这将导致错误。你不能这样做,因为无法以服务方式注入数据转换器。

您需要做的是以自定义表单类型注入实体管理器,然后在实例化时将其传递给数据转换器。

class CSV2TagsType extends AbstractType 
{
    protected $em;

    public function __construct(EntityManager $em) {
        $this->em = $em;
    }

    public function buildForm(FormBuilder $builder, array $opts) {
        $builder->appendClientTransformer(new CSV2TagsTransformer($this->em));
    }

    // Rest of class
}

这样,您可以在表单类型中注入实体管理器,这是可能的,因为表单类型被定义为服务。在表单类型中,您实例化数据转换器并将已注入表单类型的实体管理器传递给构造。

另一种方法是将数据转换器声明为服务,然后将其注入表单类型。这样,您不会自己实例化数据转换器,而是使用在表单类型的构造函数中注入的数据转换器。因此,如果您不需要表单类型中的实体管理器,则可以省略注入它。这是另一个例子:

services:
  jm.blog.csv2tagsTransformer:
    class: JM\BlogBundle\Form\DataTransformer\CSV2TagsTransformer
    arguments: ["@doctrine.orm.entity_manager"]

  jm.blog.csv2tagsType:
    class: JM\BlogBundle\Form\Type\CSV2TagsType
    arguments: ["@jm.blog.csv2tagsTransformer"]
    tags:
      - { name: form.type, alias: csv2tags }

class CSV2TagsType extends AbstractType 
{
    protected $transformer;

    public function __construct(CSV2TagsTransformer $transformer) {
        $this->transformer= $transformer;
    }

    public function buildForm(FormBuilder $builder, array $opts) {
        $builder->appendClientTransformer($this->transformer);
    }

    // Rest of class
}

这是您问题答案的小简历:

  1. 这是对的。
  2. 变压器服务不需要别名。但是正如@ greg0ire所说,你需要为你的表单类型定义一个服务。 getName()函数必须返回应该使用的id。它可以是定义的别名,也可以是服务ID。通常,人们使用别名作为getName返回的值。
  3. 执行new CSV2TagsTransformer()是不正确的,因为这样,您不会将实体管理器发送到您的类,因为它不能接受空值,所以它将在PHP中失败。
  4. 希望这有帮助。

    的问候,
    马特

答案 1 :(得分:1)

关于您的主要问题,在services.yml文件中,您应该将服务标记为form.type,如下所示:

services:
    jm.blog.csv2tagsTransformer:
        class: JM\BlogBundle\Form\DataTransformer\CSV2TagsTransformer
        arguments: ["@doctrine.orm.entity_manager"]
        tags:
          - { name: form.type, alias: csv2tags }

对于其他问题,我不知道。