I have an object from inside a Symfony2 project. Here follows the code.
namespace Acme\UserBundle\Form\Model;
use Symfony\Component\Validator\Constraints as Assert;
use Acme\UserBundle\Entity\User;
class Registration
{
/**
* #Assert\Type(type="Acme\UserBundle\Entity\User")
*/
protected $user;
...
public function setUser(User $user)
{
//Get the EntityManager here!!!!
$group = $em
->getRepository('AcmeUserBundle:Group')
->findOneByName('Customers');
$this->user->addGroup($group);
}
....
}
So, as highlighted in the code, how to get the EntityManager to retrieve an entity with Doctrine?
Thanks in advance
Ok, solved!
I only have to pass the EntityManager to the constructor of the Registration class within the controller.
use Symfony\Component\Validator\Constraints as Assert;
use Acme\UserBundle\Entity\User;
class Registration
{
/**
* #Assert\Type(type="Acme\UserBundle\Entity\User")
*/
protected $user;
...
protected $em;
public function __construct($em) {
$this->em = $em;
}
public function setUser(User $user)
{
$this->user = $user;
$group = $this->em->getRepository('AcmeUserBundle:Group')
->findOneByName('Customers');
$this->user->addGroup($group);
}
...
}
Thanks a lot anyway.
Related
I want to recover the date of the last time a user logged in my Symfony 5 website, I created a LoginListener and did the right settings (So-think-I ?) to make it work but in the class Login Listener :
namespace App\Event;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class LoginListener
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
// Get the User entity.
$user = $event->getAuthenticationToken()->getUser();
// Update your field here.
$user->setLastLogin(new \DateTime());
// Persist the data to database.
$this->em->persist($user);
$this->em->flush();
}
}
The setLastLogin(new \DateTime()) is described as an undefined method. Yet this method is in the entity User.php and it is properly called in the loginlistener. And the "use App\Entity\User :
/**
* {#inheritdoc}
*/
public function setLastLogin(\DateTime $time = null)
{
$this->lastLogin = $time;
return $this;
}
/**
* Gets the last login time.
*
* #return \DateTime|null
*/
public function getLastLogin()
{
return $this->lastLogin;
}
/**
* #var \DateTime $lastLogin
*
* #ORM\Column(type="datetime")
*/
private $lastLogin;
And when I try to make a exit(var_dump($user), nothing appears. Here is my services.yaml :
App\EventListener\LoginListener:
- tags:
- { name: 'kernel.event_listener', event: 'security.interactive_login', entity: 'App\Entity\User' }
Can someone help me please ? Thank you.
Because I have many controllers, after the user is logged in, I want to transfer some user settings to Twig. But I don't want to make it in each controller:
Eg:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DefaultController extends Controller
{
public function indexAction()
{
$user = $this->getUser();
$settings = $user->getSettings();
// ...
}
}
Is there a possibility to make it at a higher level from the call of the DefaultController?
Solution 1
Use app.user variable in Twig which is globally accessible:
{{ app.user.username }}
More info: https://symfony.com/doc/current/templates.html#the-app-global-variable
Solution 2
Write custom Twig function:
// src/Twig/UserExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Symfony\Component\Security\Core\Security;
class UserExtension extends AbstractExtension
{
Security $security
public function __construct(Security $security)
{
// Avoid calling getUser() in the constructor: auth may not
// be complete yet. Instead, store the entire Security object.
$this->security = $security;
}
public function getFunctions()
{
return [
new TwigFunction('get_user_settings', [$this, 'getUserSettings']),
];
}
public function getUserSettings()
{
$user = $this->security->getUser();
return $user->getSettings();
}
}
Usage in Twig:
{{ get_user_settings().setting1 }}
More info: https://symfony.com/doc/current/templating/twig_extension.html
How to inject current logged user: https://symfony.com/doc/current/security.html#b-fetching-the-user-from-a-service
Ok, maybe I don't describe it clearly. This is the solution I have searched for:
<?php
namespace AppBundle\Subscriber;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class ControllerSubscriber implements EventSubscriberInterface
{
/**
* #var TokenStorageInterface
*/
private $tokenStorage;
/**
* #var EntityManagerInterface
*/
private $em;
/**
* ControllerSubscriber constructor.
*
* #param TokenStorageInterface $tokenStorage
* #param EntityManagerInterface $em
*/
public function __construct(TokenStorageInterface $tokenStorage, EntityManagerInterface $em)
{
$this->tokenStorage = $tokenStorage;
$this->em = $em;
}
/**
* #param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
if (!$token = $this->tokenStorage->getToken()) {
return;
}
if (!$user = $token->getUser()) {
return;
}
// if no user
if (!$user instanceof UserInterface) {
return;
} else {
// .... do something
}
}
/**
* #return array
*/
public static function getSubscribedEvents()
{
return array(
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::CONTROLLER => array(array('onKernelController', 1)),
);
}
}
services.yml
app.controller.subscriber:
class: AppBundle\Subscriber\ControllerSubscriber
arguments: ["#security.token_storage","#doctrine.orm.default_entity_manager"]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
i am developing a symfony restful api with tools like
FosRestBundle, FosUserBundle and Lexik JWT for api authentication.
I need to save each successful login in my app. So i created a Login entity
(user_id,loginDate) , but i don't know how to use it because the login in handled from Lexik.
Does anyone know how can i do this?
Thanks
You can use security.interactive_login event for that. More information can be found from the official documentation:
https://symfony.com/doc/current/components/security/authentication.html#authentication-events
Create the listener and register it:
namespace App\EventListener;
use App\Component\EntityManagerAwareTrait;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
/**
* #package App\EventListener
*/
class SecuritySubscriber implements EventSubscriberInterface
{
/**
* #param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* #return array
*/
public static function getSubscribedEvents(): array
{
return [
SecurityEvents::INTERACTIVE_LOGIN => 'onSecurityInteractiveLogin',
];
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event): void
{
$user = $event->getAuthenticationToken()->getUser();
if ($user instanceof User) {
$user->setLoginDate(new \DateTime());
$this->em->persist($user);
$this->em->flush();
}
}
}
I have extended the DefaultAuthenticationFailureHandler in order to redirect users to register page if the username is not in the database. it works fine for the first part.
If the username exists in the database I want from the Controller the default behavior i.e. to redirect to the login page with the login error message. Why it is not issuing a redirect?
namespace UserBundle\Redirection;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
use UserBundle\Controller\SecurityController;
class AfterLoginFailureRedirection extends DefaultAuthenticationFailureHandler
{
/**
* #var \Symfony\Component\Routing\RouterInterface
*/
private $router;
/**
* #var \Symfony\Component\DependencyInjection\ContainerInterface
*/
private $container;
public function setRouter(RouterInterface $router)
{
$this->router = $router;
}
public function setContainer(ContainerInterface $container)
{
$this->container=$container;
}
/**
* #param Request $request
* #param AuthenticationException $token
* #return RedirectResponse
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
//$request = $this->container->get('request');
$token=$exception->getToken();
$username=$token->getUsername();
//$username = $request->request->get('email');
$user = $this->container->get('fos_user.user_manager')->findUserByUsername($username);
if(!$user) {
$url=$this->container->get('router')->generate('fos_user_registration_register');
return new RedirectResponse($url);
}
else
{
parent::onAuthenticationFailure($request,$exception);
}
}}
You don't return anything in your else case
correct code should be :
else {
return parent::onAuthenticationFailure($request,$exception);
}
I have a problem in redirect path according to role in FOSuserBndle.The problem is in :
FatalErrorException: Error: Call to a member function generate() on a
non-object in.....
This is the event listener
namespace Register\UserBundle\EventListener;
///////////////////////////////
//////////////////////////////
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Doctrine\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.1.0+
// use Symfony\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.0.x
/**
* Custom login listener.
*/
class LoginListener
{
protected $router;
/** #var \Symfony\Component\Security\Core\SecurityContext */
private $securityContext;
/** #var \Doctrine\ORM\EntityManager */
private $em;
/**
* Constructor
*
* #param SecurityContext $securityContext
* #param Doctrine $doctrine
*/
public function __construct( SecurityContext $securityContext, Doctrine $doctrine )
{
$this->securityContext = $securityContext;
$this->em = $doctrine->getEntityManager();
}
/**
* Do the magic.
*
* #param InteractiveLoginEvent $event
*/
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
if ($this->securityContext->isGranted('ROLE_PATIENT')) {
$response = new RedirectResponse($this->router->generate('demands'));
//this->redirect($this->generateUrl('home'));
}
if ($this->securityContext->isGranted('ROLE_THERAPIST')) {
// user has logged in using remember_me cookie
print_r("FFFFFFFFFFFFFTHERAPIST");
die;
}
// do some other magic here
$user = $event->getAuthenticationToken()->getUser();
$type = $user->getType()->getId();
print_r( $type);
die;
// ...
}
}
It seems that the router is not injected in your listener/service.
Listener class :
...
use Symfony\Component\Routing\Router;
class LoginListener
{
protected $container;
protected $em;
protected $router;
public function __construct(ContainerInterface $container, EntityManager $em, Router $router)
{
$this->container = $container;
$this->em = $em;
$this->router = $router;
}
...
}
Service declaration :
my_bundle.my_listener:
class: %my_bundle.my_listener.class%
arguments: [ #service_container, #doctrine.orm.entity_manager, #router ]