Symfony How to Return All Logged in Active Users

Symfony how to return all logged in Active Users

There is a great post here: List online users.

You can create a Listener that listens on the kernel.controller event and updates a user field lastActivity every time a user is active. You can check lastActivity < now()- 2 minutes and update lastActivity timestamp.

Also: Implementing user activity in symfony 2

Here is how to do it

Note: If you're not using FOSUserBundle, see Edit below.

1 Add this to your User Entity

/**
* Date/Time of the last activity
*
* @var \Datetime
* @ORM\Column(name="last_activity_at", type="datetime")
*/
protected $lastActivityAt;

/**
* @param \Datetime $lastActivityAt
*/
public function setLastActivityAt($lastActivityAt)
{
$this->lastActivityAt = $lastActivityAt;
}

/**
* @return \Datetime
*/
public function getLastActivityAt()
{
return $this->lastActivityAt;
}

/**
* @return Bool Whether the user is active or not
*/
public function isActiveNow()
{
// Delay during wich the user will be considered as still active
$delay = new \DateTime('2 minutes ago');

return ( $this->getLastActivityAt() > $delay );
}

2 Create Event Listener

<?php
namespace Acme\UserBundle\EventListener;

use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Model\UserInterface;

/**
* Listener that updates the last activity of the authenticated user
*/
class ActivityListener
{
protected $securityContext;
protected $userManager;

public function __construct(SecurityContext $securityContext, UserManagerInterface $userManager)
{
$this->securityContext = $securityContext;
$this->userManager = $userManager;
}

/**
* Update the user "lastActivity" on each request
* @param FilterControllerEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}

// Check token authentication availability
if ($this->securityContext->getToken()) {
$user = $this->securityContext->getToken()->getUser();

if ( ($user instanceof UserInterface) && !($user->isActiveNow()) ) {
$user->setLastActivityAt(new \DateTime());
$this->userManager->updateUser($user);
}
}
}
}

3 Declare event Listener as a service

parameters:
acme_user.activity_listener.class: Acme\UserBundle\EventListener\ActivityListener

services:
acme_user.activity_listener:
class: %acme_user.activity_listener.class%
arguments: [@security.context, @fos_user.user_manager]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }

And you're good to go!

Edit (without FOSUserBundle)

1 Add this to your User Entity

Same as Step 1 Above

2 Create Event Listener

<?php
namespace Acme\UserBundle\EventListener;

use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Doctrine\ORM\EntityManager;
use Acme\UserBundle\Entity\User;

/**
* Listener that updates the last activity of the authenticated user
*/
class ActivityListener
{
protected $securityContext;
protected $entityManager;

public function __construct(SecurityContext $securityContext, EntityManager $entityManager)
{
$this->securityContext = $securityContext;
$this->entityManager = $entityManager;
}

/**
* Update the user "lastActivity" on each request
* @param FilterControllerEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}

// Check token authentication availability
if ($this->securityContext->getToken()) {
$user = $this->securityContext->getToken()->getUser();

if ( ($user instanceof User) && !($user->isActiveNow()) ) {
$user->setLastActivityAt(new \DateTime());
$this->entityManager->flush($user);
}
}
}
}

3 Declare event Listener as a service

parameters:
acme_user.activity_listener.class: Acme\UserBundle\EventListener\ActivityListener

services:
acme_user.activity_listener:
class: %acme_user.activity_listener.class%
arguments: [@security.context, @doctrine.orm.entity_manager]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }

And you're good to go!

How to get the current logged User in a service

Inject security.token_storage service into your service, and then use:

$this->token_storage->getToken()->getUser();

as described here: http://symfony.com/doc/current/book/security.html#retrieving-the-user-object and here: http://symfony.com/doc/current/book/service_container.html#referencing-injecting-services

Symfony getting logged in user's id

Current Symfony versions (Symfony 4, Symfony >=3.2)

Since Symfony >=3.2 you can simply expect a UserInterface implementation to be injected to your controller action directly. You can then call getId() to retrieve user's identifier:

class DefaultController extends Controller
{
// when the user is mandatory (e.g. behind a firewall)
public function fooAction(UserInterface $user)
{
$userId = $user->getId();
}

// when the user is optional (e.g. can be anonymous)
public function barAction(UserInterface $user = null)
{
$userId = null !== $user ? $user->getId() : null;
}
}

You can still use the security token storage as in all Symfony versions since 2.6. For example, in your controller:

$user = $this->get('security.token_storage')->getToken()->getUser();

Note that the Controller::getUser() shortcut mentioned in the next part of this answer is no longer encouraged.

Legacy Symfony versions

The easiest way to access the user used to be to extend the base controller, and use the shortcut getUser() method:

$user = $this->getUser();

Since Symfony 2.6 you can retrieve a user from the security token storage:

$user = $this->get('security.token_storage')->getToken()->getUser();

Before Symfony 2.6, the token was accessible from the security context service instead:

$user = $this->get('security.context')->getToken()->getUser();

Note that the security context service is deprecated in Symfony 2 and was removed in Symfony 3.0.

Load list of active users from database with symfony without using a controller

As Cerad mentioned, you can embed a Controller in your templates : https://symfony.com/doc/current/templates.html#embedding-controllers

Instead of doing {% include 'base/navbar.html.twig' %} you will do

In your template :

{{ render(controller('App\\Controller\\BaseController::renderNavbar')) }}

In BaseController

public function renderNavbar(UserRepository $userRepository) {
return $this->render('base/navbar.html.twig', [
'activeUsers' => $userRepository->findActiveUsers(),
]);
}

It's not a route, it's simply a function that renders html, so you don't need to add annotations.

Get current logged in user in entity

You can implement a method in the Achievement entity and pass the current authenticated user into it from your controller of twig template.

use Doctrine\Common\Collections\Criteria;

// ...

/**
* @return Collection
*/
public function getAchievementUsers(User $user)
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('user', $user));

return $this->achievementUsers->matching($criteria);
}

In case of using a JMS serializer, you can add a virtual field and fill it with data using getAchievementUsers method by defining a serialization listener and injecting the TokenStorage to retrieve the current authenticated user.

<?php

namespace AppBundle\Listener\Serializer;

...
use JMS\Serializer\GenericSerializationVisitor;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

class AchievementSerializerListener
{
/**
* @var User
*/
protected $currentUser;

/**
* @param TokenStorage $tokenStorage
*/
public function __construct(TokenStorage $tokenStorage)
{
$this->currentUser = $tokenStorage->getToken()->getUser();
}

/**
* @param ObjectEvent $event
*/
public function onAchievementSerialize(ObjectEvent $event)
{
if (!$this->currentUser) {
return;
}

/** @var Achievement $achievement */
$achievement = $event->getObject();

/** @var GenericSerializationVisitor $visitor */
$visitor = $event->getVisitor();

$visitor->setData(
'achievement_users',
$achievement->getAchievementUsers($this->currentUser)
);
}
}

services.yml

  app.listener.serializer.achievement:
class: AppBundle\Listener\Serializer\AchievementSerializerListener
arguments:
- '@security.token_storage'
tags: [ { name: jms_serializer.event_listener, event: serializer.post_serialize, class: AppBundle\Entity\Achievement, method: onAchievementSerialize } ]


Related Topics



Leave a reply



Submit