DEV Community

Abdelkarim ELAMEL
Abdelkarim ELAMEL

Posted on

[Symfony]: Empty token storage when injecting service in an event listener

Another Symfony mistery

You might have been struggling to fetch the logged-in user from a listener that includes a UserService class which contains the logic of fetching the logged-in user.

Let's take the below code as an example:

//UserService.php <?php namespace App\Service; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class UserService { private $tokenStorage; private $currentUser; /** * @required */ public function setSecurityContext(TokenStorageInterface $tokenStorage) { $token = $tokenStorage->getToken(); if ($token) { $this->currentUser = $token->getUser(); } } public function getCurrentUser() { return $this->currentUser; } } ?> 
Enter fullscreen mode Exit fullscreen mode
//MyListner <?php namespace App\Listener; use Doctrine\Persistence\Event\LifecycleEventArgs; class MyListener { private $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function onFlush(LifecycleEventArgs $args) { $currentUser = $this->userService->getCurrentUser(); var_dump($currentUser); // prints NULL } } ?> 
Enter fullscreen mode Exit fullscreen mode

Why the currentUser is NULL ?

The answer: Doctrine listeners are called whenever a corresponding event occurs. Initialization of them may occur before the security context.

You have two options here:

The first one: inject your TokenStorage directly in your Listener and retrieve the token inside your event handler.

//MyListner <?php namespace App\Listener; use Doctrine\Persistence\Event\LifecycleEventArgs; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class MyListener { private $tokenStorage; public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } public function onFlush(LifecycleEventArgs $args) { $currentUser = $this->tokenStorage->getToken()->getUser(); var_dump($currentUser); // prints a UserInterface object } } ?> 
Enter fullscreen mode Exit fullscreen mode

The second one: Fetch the token inside the getCurrentUser method.

//UserService.php <?php namespace App\Service; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class UserService { private $tokenStorage; private $currentUser; public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } public function getCurrentUser(TokenStorageInterface $tokenStorage) { $token = $tokenStorage->getToken(); if ($token && is_null($this->currentUser)) { $this->currentUser = $token->getUser(); } return $this->currentUser; } } ?> 
Enter fullscreen mode Exit fullscreen mode

The hidden trick is that you have to call the getToken method in order to get a fresh token.

That was it, I hope this blog post was helpful.

Cheers

Top comments (0)