Symfony 3 - 将表单定义为服务

18

在我的Symfony 3-master项目中,我使用以下代码在控制器中创建表单:

$form = $this->createForm(ApplicantType::class, $applicant);
现在我决定将这个表单做成一个服务,这样我就可以在其中使用EntityManager。所以在Symfony2.x中,这相当容易,只需要在services.yml中声明并添加此行代码:
$form = $this->createForm($this->get("applicant.form"), $applicant);

然而在Symfony 3中,这已不再可能,因为这个第一个参数期望的是一个字符串,而不是表单本身。

所以我的问题是:在Symfony 3中如何将表单创建为服务,或者是否有其他方法可以在表单内部传递EntityManager?

非常感谢任何帮助!


2
将您的服务标记为表单,然后传递别名。http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html#creating-your-field-type-as-a-service。应该与S2相同。 - Cerad
你尝试过这个吗:$form = $this->createForm("applicant.form", $applicant); - Matteo
5个回答

23

将表单类型定义为服务并不意味着要将从容器中检索到的实例传递给createForm。在执行此操作时,就表单组件而言,容器不会参与其中。

要使用作为服务注册的表单类型(使用form.type标记使表单组件知道它),只需按其名称引用它(在Symfony 2.8+中为完全限定类名,在早期版本中为类型名称)在createFormFormBuilder :: add中。这正是您对Symfony核心类型(例如textchoice等)所做的事情,它们已被注册为服务。当使用表单类型作为服务而不是具有依赖关系且在首次使用时自动注册的表单类型时,您的控制器代码根本不会改变。


3
关于@Xatoo在赏金中提出的传递依赖项的首选方式,这取决于依赖项的类型。如果预计在每次使用表单类型(例如Symfony中“entity”类型的QueryBuilder)时都会更改,则属于选项。如果始终相同(用于访问实体管理器的“doctrine”服务),则应将其放入构造函数中,以避免通过传递选项来使表单也依赖于该服务。 - Christophe Coevoet
太好了,这对我也起作用,我试图从服务传递到 createForm,但不起作用,而 SearchForm:class 很好地工作,并且实体管理器也通过表单服务传递,这真是神奇.. :) - Muzafar Ali
亲爱的stof,您能否更新您的答案,包括Symfony 3.3的示例(在控制器内部对服务类进行类型提示)? - Peyman Mohamadpour
对于Symfony 3.3+,除了自动配置功能可能会自动为您添加form.type标签而不是显式添加之外,没有任何区别。您永远不会在控制器中获取表单类型实例。 - Christophe Coevoet
@ChristopheCoevoet 使用表单作为服务是一个好的实践吗? - Hamza Abdaoui
将表单 类型 定义为服务绝对是一个好的实践(如果你使用 Symfony Flex 结构启动项目,自 Symfony 4 起,所有表单类型都会自动注册为服务)。通过 createForm 方法创建的表单实例不应该作为服务,因为它们是有状态的对象,不可重用。 - Christophe Coevoet

6
这是我在Symfony 2代码中将表单注入为服务的步骤。以下是需要更改的service.yml文件中的内容:

issue.form:
    class: Gutersohn\Bundle\CoreBundle\Form\IssueType
    arguments: ['@service_container']
    tags:
        - { name: form.type, alias: issue }

to

issue.form:
    class: Gutersohn\Bundle\CoreBundle\Form\IssueType
    arguments: ['@service_container']
    tags:
        - { name: form.type }

在我的控制器中,我进行了更改

$form = $this->container->get('form.factory')->create($this->container->get('issue.form'), $issue, [
        "method" => "post",
        "action" => $this->container->get('router')->generate("ticket_add")
]);

to

$form = $this->container->get('form.factory')->create(IssueType::class, $issue, [
        "method" => "post",
        "action" => $this->container->get('router')->generate("ticket_add")
]); 

请注意,如果services.xml中的类路径存在拼写错误,则不会出现错误。我花了3天时间才找到问题所在。 - Chopchop

5
GitHub上的问题#17013中,aliemre表示:

Adding form.type tag is enough in your service definition.

app.form.corporation_type:
    class: App\CorporationBundle\Form\CorporationType
    arguments: ["@doctrine.orm.entity_manager"]
    tags:
        - { name: form.type }

Controller should remain same:

$form = $this->createForm(CorporationType::class, $corporation);

我已经测试过,它可以正常工作!


1

感谢您找出并指向 Github 上的这个问题。 - Sander Toonen
我也对此很感兴趣!我在这里可以提供帮助! :) - Renato Mefi

0
在Symfony 3.4上,你可以轻松地创建一个服务,例如,在你的表单中注入EntityManager:
```php class addDiverseType extends AbstractType { ```
private $em;

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

然后,您需要在service.yml文件中将您的表单“转换”为服务:

 form.add_diverse:
    class: PlatformBundle\Form\addDiverseType
    arguments: ['@doctrine.orm.entity_manager']
    tags:
        - { name: form.type }

最后,在控制器中调用您的表单:

$form = $this->createForm(addDiverseType::class, $parameter);

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