How to create a custom logout event (onLogout) listener using FOSUserBundle in Symfony 3


Normally, the implementation of FOSUserBundle tends to be straight forward and it solves almost all of your requirements. However, there are special tasks, that probably are hard to find in the official documentation or aren't easy to understand. One of these tasks is to do something after an user succesfully start a session (logging into your app) and you need to know when an user do that in order to do something extra (to add parameters in the session according to the email etc).

You could easily replace the "event listener" modifying the code in the bundle (vendor directory), however this is discouraged as it's obviously a bad practice and your changes will be lost on any update, therefore is recommendable to add a logout event listener instead. In this article, you'll learn how to listen specifically for the logout event when an user succesfully logouts from your app.

Implementation

The recommended way, is to create a folder with the name Listeners into your bundle, and create a class with the name LogoutListener inside with the following code:

Note: do not forget to change the namespace of the class according to the name of your bundle and location of the class.

<?php

// LogoutListener.php - Change the namespace according to the location of this class in your bundle
namespace myBundle\Listeners;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
use FOS\UserBundle\Model\UserManagerInterface;

class LogoutListener implements LogoutHandlerInterface {
    protected $userManager;
    
    public function __construct(UserManagerInterface $userManager){
        $this->userManager = $userManager;
    }
    
    public function logout(Request $Request, Response $Response, TokenInterface $Token) {
        // ..
        // Here goes the logic that you want to execute when the user logouts
        // ..
        
        // The following example will create the logout.txt file in the /web directory of your project
        $myfile = fopen("logout.txt", "w");
        fwrite($myfile, 'logout succesfully executed !');
        fclose($myfile);
    }
}

Now that you have a class that will handle the logout event, we need to create a service that will use it. Proceed to modify the services.yml file of your project and register a new service as shown below:

services:
    # Register the LogoutListener service
    # The namespace where the class is located 
    # and the class name at the end.
    # we'll inject the user_manager in case that you need it
    mybundle_logoutlistener:
        class: myBundle\Listeners\LogoutListener
        arguments:
            userManager: "@fos_user.user_manager"

Finally, the registered service that in this case has the name mybundle_logoutlistener (that you can obviously customize) , needs to be inyected to the handlers of the logout event in your security.yml file:

security:
    ## ...
    firewalls:
        ## ...
        main:
            ## ...
            logout:
                handlers: [mybundle_logoutlistener]

And you're ready to go ! Remember to clear the cache (manually or with the command) and proceed to login into your project and then logout. As made in this example, a file ("logout.txt") will be created in the web directory of your project only for test purposes, feel free to change it for whatever you need to do.

Happy coding !

Become a more social person