DEV Community

Abdelkarim ELAMEL
Abdelkarim ELAMEL

Posted on

5 3

[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

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay