Search code examples
phpsymfonydoctrinesymfony-2.3

Symfony how to return all logged in Active Users


I want to return all Logged in users of my application and render it in my Dashboard. The user_id and user_name should be retrieved from the session (I am using an external LDAP Library for authentication)

I have created a field in the database called lastActivity which will contain the last login time and then I can query the database for lastActivity display users logged in in the last 2 minutes.

ActivityListener.php

     <?php

namespace Bnpp\SecurityBundle\EventListener;

use Doctrine\ORM\EntityManager;
//use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Acme\SecurityBundle\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Registry;


/**
 * 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->setLastActivity(new \DateTime('now'));
                $this->entityManager->flush($user);
            }
        }

    }

}

Services.yml

services:
    activity_listener:
        class: Bnpp\SecurityBundle\EventListener\ActivityListener
        arguments: [@security.context, @doctrine.orm.entity_manager]
        tags:
         - { name: kernel.event_listener, event: kernel.controller, method: onCoreController }

User Entity

<?php

namespace Acme\SecurityBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * User
 *
 * @ORM\Table(name="users")
 * @ORM\Entity(repositoryClass="Acme\SecurityBundle\Entity\UserRepository")
 */
class User implements UserInterface
{

/**
     * @var \DateTime
     * @ORM\Column(name="LASTACTIVITY", type="datetime")
     */
    private $lastActivity;


    /**
     * @return bool whether the user is active or not
     */

    public function isActiveNow()
     {

    $delay = new\DateTime('2 minutes ago');

    return($this->getlastActivity()>$delay);

       }

/**
     * Set lastActivity
     *
     * @param\Datetime $lastActivity
     * @return User
     */


    public function setlastActivity($lastActivity)
    {
        $this->lastActivity = $lastActivity;

        return $this;
    }


    /**
     * Get lastActivity
     *
     * @return \DateTime
     */
    public function getlastActivity()
    {
        return $this->lastActivity;
    }




}

Solution

  • 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!