Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 2 - Setting a Flash Message outside of Controller

Tags:

symfony

I have a logout Listener where I'd like to set a flash message showing a logout confirmation message.

namespace Acme\MyBundle\Security\Listeners;

use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;

class LogoutListener implements LogoutSuccessHandlerInterface
{
  private $security;  

  public function __construct(SecurityContext $security)
  {
    $this->security = $security;
  }

  public function onLogoutSuccess(Request $request)
  {
    $request->get('session')->getFlashBag()->add('notice', 'You have been successfully been logged out.');

    $response = new RedirectResponse('login');
    return $response;
  }
}

Here is my services.yml (as it pertains to this):

logout_listener:
   class:  ACME\MyBundle\Security\Listeners\LogoutListener
   arguments: [@security.context]

This is generating an error:

Fatal error: Call to a member function getFlashBag() on a non-object

How do I set a flashBag message in this context?

Also, how do get access to the router so I can generate the url (via $this->router->generate('login')) instead of passing in a hard-coded url?

Resolution Note

To get the flash to work, you must tell your security.yml config not invalidate the session on logout; otherwise, the session will be destroyed and your flash will never appear.

logout:
    path: /logout
        success_handler: logout_listener
        invalidate_session: false
like image 635
doremi Avatar asked Nov 12 '12 17:11

doremi


3 Answers

You should inject the services for session and router into the LogoutListener and use them to perform these tasks. This is the way to do it in yml:

logout_listener: 
class: ACME\MyBundle\Security\Listeners\LogoutListener 
arguments: [@security.context, @router, @session]

Then in your class you write:

class LogoutListener implements LogoutSuccessHandlerInterface
{
    private $security;
    private $router;
    private $session;

    public function __construct(SecurityContext $security, Router $router, Session $session)
    {
        $this->security = $security;
        $this->router = $router;
        $this->session = $session;
    }
    [...]

When you want to use the session now you can just say:

$this->session->getFlashBag()->add('notice', 'You have been successfully been logged out.');

And in the same way you can use the router service to generate routes.

like image 145
Aldo Stracquadanio Avatar answered Sep 20 '22 21:09

Aldo Stracquadanio


You can get the Session object (as well as any other service) trough the service container:

$session = $ServiceContainer->get('session');
$session->setFlash('notice', 'Message');

The way you can access to the service container in different ways:

  • From a controller or any container aware class: just use $this->get('session');
  • From a service: you have to inject the service container object as Aldo Said
like image 37
ButterDog Avatar answered Sep 19 '22 21:09

ButterDog


The answers are very old on this post. 10 years later (2022), Symfony allows to deal with flashes very easily outside of a controller using the FlashBagInterface:

<?php

namespace App\Service;

use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;

class MyService
{
    private $flash;

    public function __construct(FlashBagInterface $flash)
    {
        $this->flash = $flash;
    }

    public function myRandomMethod(): string
    {
        // ...
        $this->flash->add('success', 'This is a success!');
    }
}
like image 29
Edouard Avatar answered Sep 21 '22 21:09

Edouard