Register a form as a service in Symfony 2

If you use the Symfony 2 form builder and create your form types as classes then you may already know that you can define those form types as services and call them in your controller. That process is well documented in the The Book, and works very well. I have an alternative solution which is to define the form itself as a service, which allows you to easily use that form in other model or service classes outside of the controller. This is useful if you have a separate class that handles form submission which may need the form as well and you can inject the actual form into that service.

The typical way of defining a form type as a service and using the form factory to create the form in the controller looks like this:

# src/Acme/TaskBundle/Resources/config/services.yml

services:
    acme_demo.form.type.task:
        class: Acme\TaskBundle\Form\Type\TaskType
        tags:
            - { name: form.type, alias: task }
// src/Acme/TaskBundle/Controller/DefaultController.php
// ...

public function newAction()
{
    $task = ...;
    $form = $this->createForm( 'task', $task );

    // ...
}

 

To use the Symfony 2 form factory to create the form in the service container, add the following to your services config file.

If you use YAML:

# src/Acme/TaskBundle/Resources/config/services.yml

services
    acme_demo.form.task:
        factory_method: createNamed
        factory_service: form.factory
        class: Symfony\Component\Form\Form
        arguments:
            - task_form                        # name of the form
            - task                             # alias of the form type
            - null                             # data to bind, this is where your entity could go if you have that defined as a service
            - { validation_groups: [Default] } # validation groups

    acme_demo.form.type.task:
        class: Acme\TaskBundle\Form\Type\TaskType
        tags:
        - { name: form.type, alias: task }

If you use XML:

<!-- src/Acme/TaskBundle/Resources/config/services.xml -->

<services>
    <service id="acme_demo.form.task" factory-method="createNamed" factory-service="form.factory" class="Symfony\Component\Form\Form">
        <argument>task_form</argument> <!-- name of the form -->
        <argument>task</argument>      <!-- alias of the form type -->
        <argument>null</argument>      <!-- data to bind, this is where your entity could go if you have that defined as a service -->
        <argument type="collection">   <!-- validation groups -->
            <argument key="validation_groups">Default</argument>
        </argument>
    </service>

    <service id="acme_demo.form.type.task" class="Acme\TaskBundle\Form\Type\TaskType">
        <tag name="form.type" alias="task" />
    </service>
</services>

 

Now you can call your form like this in your controller

// src/Acme/TaskBundle/Controller/DefaultController.php
// ...

public function newAction()
{
    $task = ...;
    $form = $this->get( 'acme_demo.form.task' );

    // set initial form data if needed
    $form->setData( $task );
}

 

Wherever you have the service container you can call the form and you can inject the form into other services, as you may want to do with a class that handles form submission.

5 comments on “Define a Symfony 2 Form as a Service

  1. satahippy says:

    beware! with this approach DI will always returns the same Form
    that differs from Controller::createForm

    1. rasta says:

      doesn’t have to, if you define the proper scope

  2. Horecio says:

    Very good.
    I was trying to do so. For I use in ZF2 this way. But I was kind of lost in yaml.
    Thanks and good job.

  3. George Ploscaru says:

    Go to https://github.com/symfony/symfony/issues/17013 aliemre’s comment for Symfony 3

  4. sathi says:

    if i am using a symfony 3.2 version then how can i register form….?

Comments are closed.