11

I activated user confirmation for FOSUserBundle. But I don't want to take the response from the original listener

$url = $this->router->generate('fos_user_registration_check_email');
$event->setResponse(new RedirectResponse($url));

I want to chose another route. I tried to extend the EventListener

namespace Acme\MyBundle\EventListener;

use FOS\UserBundle\EventListener\EmailConfirmationListener as BaseListener;
// ...

class EmailConfirmationListener extends BaseListener
{
    public function onRegistrationSuccess(FormEvent $event)
    {    
        $url = $this->router->generate('fos_user_registration_check_email');
        $event->setResponse(new RedirectResponse($url));
    }
}

Unfortunately, EventListeners don't seem to be extendable, just as Controllers or Forms are. (Just in case you wonder: of course my bundle is a child of the FOSUserBundle.)

So I want to avoid editing those two lines directly in the vendor folder (as it would be very bad practice to do so!). So what are my ways out of this calamity?

Gottlieb Notschnabel
  • 9,408
  • 18
  • 74
  • 116
  • I already had an idea: Changing the controller and action in my routes definition. But I don't like this idea as it is against my understanding of readable, maintainable and self-explanatory code. – Gottlieb Notschnabel Sep 11 '13 at 15:18
  • 1
    Ugh, looking at the `FOSUserBundle` sources I can tell a PR is needed to make it possible to configure which class is used for the `fos_user.listener.email_confirmation` service. Now it's [hardcoded](https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/config/email_confirmation.xml#L8). If it wasn't, you could extend the class and override a parameter to make the bundle use your subclass instead. – Elnur Abdurrakhimov Sep 11 '13 at 16:01
  • What's a PR? Can I override the service definition XML file? That'd be slack... – Gottlieb Notschnabel Sep 11 '13 at 16:39
  • A pull request for the bundle with code changes that fix that problem. – Elnur Abdurrakhimov Sep 11 '13 at 16:51
  • What is hardcoded here? you can just override the service `fos_user.listener.email_confirmation` with your own class and FOSUserBundle will use it ... A parameter would have been a better choice but the service definition can easily be overriden. – Nicolai Fröhlich Sep 11 '13 at 18:22
  • While a PR introducing a parameter for the class would maybe be nice ... you probably miss the fact that not all those injected services needed in the original listener will be necessary for a custom one - for example `@session`. That's probably why one has chosen not to introduce another parameter to change the class only i guess ... as it's still easy to override the service completely and inject some different services needed. – Nicolai Fröhlich Sep 11 '13 at 18:48

1 Answers1

25

Just override the service fos_user.listener.email_confirmation by creating a service with the same name in your config.yml ...

# app/config/config.yml

services:
    fos_user.listener.email_confirmation:
        class:        "Acme\MyBundle\EventListener\EmailConfirmationListener"
        arguments:    ["@fos_user.mailer", "@fos_user.util.token_generator", "@router", "@session"]
        tags:
            - { name: kernel.event_subscriber }

... or even cleaner - create a parameter that's being used by your service:

parameters:
    my.funky_parameter.class: "Acme\MyBundle\EventListener\EmailConfirmationListener"

services:
    fos_user.listener.email_confirmation:
        class: "%my.funky_parameter.class%"
        # ...

... or inside your bundle's xml/yml/php configuration file loaded by the bundle's extension. Make sure your bundle is being registered after FOSUserBundle in AppKernel.php when choosing this way.

... or the best method:

change the original service's class name in a compiler pass as the documentation chapter How to Override any Part of a Bundle suggests.

Maybe take a dive into the chapter How to work with Compiler Passes before choosing this option.

Nicolai Fröhlich
  • 51,330
  • 11
  • 126
  • 130