Symfony 3 - Define form as a service

2020-08-09 07:38发布

问题:

in my Symfony 3-master project, I use this code to create a form in a controller:

$form = $this->createForm(ApplicantType::class, $applicant);

Now I decided to make a service out of this form, so I can use EntityManager inside of it. So in Symfony2.x, this would be pretty easy, just with a declaration in services.yml and this line of code:

$form = $this->createForm($this->get("applicant.form"), $applicant);

However, this is no longer possible in Symfony 3, because this first parameter expect a string, not the form itself.

So my question is: How do I create a form as a service in Symfony 3, or is there any other way how to pass EntityManager inside of the form?

Thank you for any help!

回答1:

Defining a form type as service does not imply passing the instance retrieved from to container to createForm. when doing this, the container is not involved as far as the form component is involved.

To use a form type registered as a service (with the form.type tag so that the form component knows about it), you just just reference it by its name (i.e. the fully qualified class name in Symfony 2.8+ and the type name in older versions) in createForm or in FormBuilder::add. This is exactly what you do for Symfony core types btw (text, choice and so on), which are registered as services. the code of your controller does not change at all when using the form type as a service rather than having a form type without dependency and registered implicitly on first usage.



回答2:

This is what i did to inject a form as a service in Symfony 3 from my Symfony 2 Code.

In my service.yml i changed

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 }

In my controller i changed

$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")
]); 


回答3:

In issue #17013 on GitHub, aliemre stated:

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);

I've tested and it works!



回答4:

I tried to look into the problem and I dig into the change in github, which is this one: https://github.com/symfony/symfony/commit/abca2d6fdc89479586e052cd11241d5a9bc885e5#diff-5c1348d69be32426ff20446c9e812365R64

Then I found the PR into Symfony which has this BC removal, I decided to ask why the reason and you can see it here: https://github.com/symfony/symfony/pull/16075#issuecomment-165106123

I hope this helps you with the concept around it!



回答5:

On symfony 3.4, you can easily create a service to, for example, inject EntityManager in your form :

class addDiverseType extends AbstractType {

private $em;

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

Then, you have to "transform" your form as service in the service.yml file :

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

Finally, you call your form in the controller :

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