TokenStorageInterface return always null - symfony

I'm injecting "TokenStorageInterface" class in a service.Service is also injecting from a subscriber."TokenStorageInterface" always returning false.I tried inject Security but still returning null.
class RestaurantService
{
private TokenStorageInterface $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function getRestaurantId():int{
if($this->tokenStorage->getToken() instanceof User){ // always false
....
Usage of RestaurantService
class OverridesSubscriber implements EventSubscriberInterface
{
private $restaurantId;
public function __construct(RestaurantService $restaurantService)
{
$this->restaurantId = $restaurantService->getRestaurantId();

Related

Why is EasyAdmin 4 function configureMenuItems() in DashboardController not working?

I am currently using EasyAdmin 4 with Symfony to create a backend admin page to manage users.
I did all the step that was in the documentation but yet it still giving me an error:
"Unable to find the controller related to the "App\Controller\Admin\User" Entity; did you forget to extend "EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController"?"
Here is the code in DashboardController:
<?php
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DashboardController extends AbstractDashboardController
{
#[Route('/admin', name: 'admin')]
public function index(): Response
{
return $this->render('admin/dashboard.html.twig');
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('Symfony Melody')
->renderContentMaximized();
}
public function configureMenuItems(): iterable
{
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
yield MenuItem::linkToCrud('User', 'fas fa-user', User::class);
}
}
Here is the code in UserCrudController:
<?php
namespace App\Controller\Admin;
use App\Entity\User;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
class UserCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return User::class;
}
public function configureCrud(Crud $crud): Crud
{
return $crud;
}
/*
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id'),
TextField::new('title'),
TextEditorField::new('description'),
];
}
*/
}
Here is the code in the User class:
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 180, unique: true)]
private ?string $email = null;
#[ORM\Column]
private array $roles = [];
/**
* #var string The hashed password
*/
#[ORM\Column]
private ?string $password = null;
#[ORM\Column(length: 255)]
private ?string $nom = null;
#[ORM\Column(length: 255)]
private ?string $prenom = null;
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
public function getPrenom(): ?string
{
return $this->prenom;
}
public function setPrenom(string $prenom): self
{
$this->prenom = $prenom;
return $this;
}
}
I tried reading the documentation again but i can't find any answers.
Can someone help please? it would be great, thank you.
You are Missing the use of App\Entity\User
In your DashboardController try to add this line :
use App\Entity\User;
On the top of your class file
Happy coding 🙂

Token Storage Problems Symfony 5 Custom Login Authenticator

When the user logs in to the system, I need to fill a class variable (Login-> testInfo) with information, but in the controller the variable always returns null.
Here is a generic example.
The Login class
class Login extends UserInterface
{
private $testInfo = null;
public function setTestInfo(string $testInfo)
{
$this->testInfo = $testInfo;
}
public function getTestInfo() : ?string
{
return $this->testInfo;
}
}
The Authenticator:
class FormAuthenticator extends AbstractFormLoginAuthenticator
{
...
public function getUser($credentials, UserProviderInterface $userProvider)
{
$user = $this->entityManager->getRepository(Login::class)->findByUsername(credentials['username']);
if (!$user)
{
throw new CustomUserMessageAuthenticationException('Username could not be found.');
}
//this prints NULL
dd($user->getTestInfo());
$user->setTestInfo('testing the string');
//this prints 'testing the string'
dd($user->getTestInfo());
return $user;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
//this prints 'testing the string'
dd($token->getUser()->getTestInfo());
}
...
}
The Controller Class:
class MyController extends AbstractController
{
private $login = null;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->login = $tokenStorage->getToken() ? $tokenStorage->getToken()->getUser() : null;
}
public function home()
{
//this prints null
dd($this->login->getTestInfo());
}
}
If $user goes to the tokenStorage with the new value ('testing the string'), why, when I try to use it on the controller, does the variable always return null? what am I doing wrong?
Is testInfo a transient variable? Because you gotta know that there is UserProvider that tries to refresh user from token (maybe it could be "changed" somehow between requests). I'm pretty sure you're losing those infos right in this process.
Are you sure your controller constructor isn't being executed too soon, prior to the authentication success event writing the token to the token storage service? I'd dd() the token in the constructor to verify if the token and Login instance are present at that point.
You may need to use setContainer() instead of __construct() in your controller to retrieve the authenticated token, which would look something like this:
private $tokenStorage = null;
private $login = null;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
/**
* #param ContainerInterface $container Symfony service container interface
* #return ContainerInterface|null
*/
public function setContainer(\Psr\Container\ContainerInterface $container): ?\Psr\Container\ContainerInterface
{
if ($this->tokenStorage instanceof TokenStorageInterface && $this->tokenStorage->getToken() instanceof TokenInterface && $this->tokenStorage->getToken()->getUser() instanceof Login) {
$this->login = $this->tokenStorage->getToken()->getUser();
}
return $container;
}

Symfony Worker - Consume Messages - EntityManager

I use Symfony 4 with messenger and I use a worker who consumes my messages as a long-running process.
I have a bug with doctrine if I delete my post and recreate a new one and I dispatch my message. $post have the old data and not the new one.
I have tried a lot of things and nothing work, it works when I restart my worker.
class ChannelMessageHandler implements MessageHandlerInterface
{
private $channel;
private $bus;
public function __construct(ChannelService $channel, MessageBusInterface $commandBus)
{
$this->channel = $channel;
$this->bus = $commandBus;
}
public function __invoke(ChannelMessage $channelMessage)
{
$error = $this->channel->handleChannel($channelMessage->getUser(), $channelMessage->getService());
if ($error) {
throw new Exception($error[0]);
}
$this->bus->dispatch(new FeedMessage($channelMessage->getUser(), $channelMessage->getService()));
}
}
}
My MessageHandler call a service :
class ChannelService implements ContainerAwareInterface
{
use ContainerTrait;
protected $em;
protected $logger;
public function __construct(EntityManagerInterface $entityManager, LoggerInterface $logger)
{
$this->em = $entityManager;
$this->logger = $logger;
}
public function handleChannel($userId, $serviceName)
{
$user = $this->em->getRepository('App:User\Authentication\User')->findOneById($userId);
$post = $user->getPost();
return $this->getUserAnalyticBy($post, $serviceName);
}
thanks a lot

Symfony Service Configurator: getToken with security.context is NULL

I'm using Symfony Service Configurator in my project to configure a service after its instantiation (Docs),
in Configure method I need the current user logged so I inject the container and I tried to get the token form Security.context service but I got always NULL.
I tried also to inject only Security.context in my Configurator construct but I got same result.
Any ideas pls
Thanks.
class MyConfigurator
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function configure()
{
$user = $this->container->get('security.context')->getToken();
var_dump($user); // = NULL
}
}
I resolve the problem by getting the UserId from the session and fetch the current User from Database.
The UserId is set previously by a AuthenticationListener in my project.
So I modify my Configurator construct to be like this:
/**
* #param EntityManager $em
* #param Session $session
*/
public function __construct(EntityManager $em, Session $session)
{
$this->em = $em;
$this->session = $session;
}
A better way should be:
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
class MyConfigurator
{
private $tokenStorage;
public function __construct(EntityManager $em, TokenStorage $tokenStorage)
{
$this->em = $em;
$this->tokenStorage= $tokenStorage;
}
public function configure()
{
$user = $this->tokenStorage->getToken()->getUser();
}
....

Depedendency Injection on base Controller / Service

i'm very new in Symfony. I began my first project in symfony 2.3 LTS. At this time i have created many controllers in different bundles. My question relates to a correct procedure. I use in my controllers different services, like 'translator', 'form factory', 'session', 'router', 'entitymanager', 'templating'.
I create in my "service.yml" a base service
myapp.controller.base:
class: "%myapp.controller.base.class%"
arguments: ["#doctrine.orm.entity_manager", , "#templating", "#session", "#translator", "#router", "#form.factory"]
and inject the base service in my controller, which is also a service.
myapp.controller.locales:
class: "%myapp.controller.locales.class%"
arguments: ["#myapp.controller.base"]
My base service look like this.
namespace MyApp\<BundleName>\Controller;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Session\Session;
class BaseController
{
protected $formErrorService;
protected $entityManager;
protected $templating;
protected $session;
protected $translator;
protected $router;
protected $formFactory;
public function __construct($entityManager, EngineInterface $templating, Session $session, $translator, $router, $formFactory)
{
$this->setEntityManager($entityManager);
$this->setTemplating($templating);
$this->setSession($session);
$this->setTranslator($translator);
$this->setRouter($router);
$this->setFormFactory($formFactory);
}
public function setEntityManager($em)
{
$this->entityManager = $em;
}
public function getEntityManager()
{
return $this->entityManager;
}
public function setTemplating($templating)
{
$this->templating = $templating;
}
public function getTemplating()
{
return $this->templating;
}
public function setSession($session)
{
$this->session = $session;
}
public function getSession()
{
return $this->session;
}
public function setTranslator($translator)
{
$this->translator = $translator;
}
public function getTranslator()
{
return $this->translator;
}
public function setRouter($router)
{
$this->router = $router;
}
public function getRouter()
{
return $this->router;
}
public function setFormFactory($formFactory)
{
$this->formFactory = $formFactory;
}
public function getFormFactory()
{
return $this->formFactory;
}
}
And i call in my locales controller look like this
namespace MyApp\<Bundlename>\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Session;
class LocalesController extends BaseController
{
protected $baseService;
public function __construct($baseService)
{
$this->baseService = $baseService;
}
public function indexAction(Request $request)
{
$locales=$this->baseService->getEntityManager()->getRepository('<reponame>')->findAll();
return $this->baseService->getTemplating()->renderResponse('<templatename>', array('locales' => $locales));
}
Is this a correct procedure? Should i use this procedure in ervery controller which i need this services?
I hope i get useful hints, many thanks
It's an incorrect way to inject one controller to another. You should use parent for your child controllers.
Example:
myapp.controller.base:
class: "%myapp.controller.base.class%"
arguments: ["#doctrine.orm.entity_manager", , "#templating", "#session", "#translator", "#router", "#form.factory"]
myapp.controller.locales:
class: "%myapp.controller.locales.class%"
parent: myapp.controller.base
More docs about parent services and overriding parent dependecies: http://symfony.com/doc/current/components/dependency_injection/parentservices.html

Resources