symfony 3 - how to add a eventsubscriber as a service in a form

Viewed 1457

In my application, I created a listener for onPostSubmit event in forms. I created a new class that implement EventSubscriberInterface. In the builderForm I added the evnet subscriber like this : ->addEventSubscriber(new MyNewListener())

Everything is working well, but not as I would like...

In my listener, I need the entity manager to query the database.

The first solution I have found is to add the entity manager in the form via the options and pass it to the listener via the constructor. The code is now : ->addEventSubscriber(new MyNewListener($options['entity_manager']))

This solution works but I don't want to use it like this, I prefer to use a service and add the entity manager in the service definition.

Then, my question is: How to declare the listener as a service (and pass the entity manager) and how to call it in the form declaration ?

Thank you for your help.

2 Answers

Just treat your subscriber as a service.

Yml configuration. You can spare autowire:true if you have all classes autowired:

services:
    My\Form\Type:
        autowire: true
        tags:
            - { name: form.type }

    My\Form\Listener\MyNewListener:
        autowire: true

Form class:

...

class MyForm extends AbstractType
{
    /**
     * @var MyNewListener
     */
    private $listener;

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

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        ...
        $builder->addEventSubscriber($this->listener);
    }
}

You can define your form as a service in the container, like Cerad mentioned in his comment.

Since you are using Symfony 3 you can either choose to configure the service with autowire: true, or manually declare your arguments. Then inside your FormType you can pass those class properties to your Subscriber class. When you define your form as a service, be sure to tag it with form.type. Here is example code below.

Services.yml

services:
    your.form.type:
        class: EventsBundle\Form\MarketerType
        autowire: true # this is not needed if using arguments
        arguments: [ '@doctrine.orm.entity_manager' ] # this is not needed if using autowire
        tags:
            - { name: form.type }

FormType.php

<?php

namespace EventsBundle\Form;

use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
...

class FormType extends AbstractType
{
    /** @var EntityManager */
    private $em;

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

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        ...
        $builder->addEventSubscriber(new YourNewListener($this->em));
    }
    ...

Then, to be on the safe side, you'll want to clear the application cache. I hope this helps!

Related