My website is running Symfony 3.4 and I made my own user member system. My User entity contains a Datetime field 'lastLogin' and I can't find a solution to update it every time a user logged in.
I created a custom UserChecker then I tried to update the field in it :
<?php
namespace CoreBundle\Security;
use CoreBundle\Entity\User as AppUser;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class UserChecker implements UserCheckerInterface
{
public function checkPreAuth(UserInterface $user)
{
if (!$user instanceof AppUser) {
return;
}
if ( $user->getDeleted() || !$user->getEnabled() )
{
throw new AuthenticationException();
}
else
{
// BELOW IS WHAT I TRY, BUT FAIL.
$entityManager = $this->get('doctrine')->getManager();
$user->setLastLogin(new \DateTime());
$entityManager->persist($user);
$entityManager->flush();
}
}
public function checkPostAuth(UserInterface $user)
{
if (!$user instanceof AppUser) {
return;
}
}
}
But it doesn't work. Maybe I can't use the doctrine entity manager in this file ?
If I use $this->get('doctrine')->getManager();
I get :
Fatal Error: Call to undefined method CoreBundle\Security\UserChecker::get()
Dunno why @doncallisto removed his post. It was (IMHO) the right thing.
Take a look at http://symfony.com/doc/current/components/security/authentication.html#authentication-success-and-failure-events
So you have several options.
SecurityEvents::INTERACTIVE_LOGIN
- triggers every time the user
full out the login form and submit credentials. Will work, but you
won't get last_login updates if you have remember_me
cookie or similar
AuthenticationEvents::AUTHENTICATION_SUCCESS
- triggers each time
(every request) when authentication was successful. It means your last_login
will be updated each time on every request unless user logged out
so you'll need a EventSubscriber. Take a look at this article. https://thisdata.com/blog/subscribing-to-symfonys-security-events/
MAybe you'll need a simplified version.
public static function getSubscribedEvents()
{
return array(
// AuthenticationEvents::AUTHENTICATION_FAILURE => 'onAuthenticationFailure', // no need for this at that moment
SecurityEvents::INTERACTIVE_LOGIN => 'onSecurityInteractiveLogin', // this ist what you want
);
}
and then the onSecurityInteractiveLogin
method itself.
public function onSecurityInteractiveLogin( InteractiveLoginEvent $event )
{
$user = $this->tokenStorage->getToken()->getUser();
if( $user instanceof User )
{
$user->setLastLogin( new \DateTime() );
$this->entityManager->flush();
}
}
P.S. FosUserBundle uses interactive_login and a custom event to set last_login on entity look at: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/EventListener/LastLoginListener.php#L63