Symfony如何返回所有登录的活动用户

时间:2014-01-13 16:45:23

标签: php symfony doctrine symfony-2.3

我想返回应用程序的所有登录用户并在我的信息中心内呈现它。应从会话中检索user_iduser_name(我使用外部LDAP库进行身份验证)

我在数据库中创建了一个名为lastActivity的字段,其中包含上次登录时间,然后我可以在数据库中查询最近2分钟内登录的lastActivity显示用户。

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 }

用户实体

<?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;
    }




}

5 个答案:

答案 0 :(得分:21)

这里有一篇很棒的帖子:List online users

您可以创建一个侦听kernel.controller事件的侦听器,并在每次用户处于活动状态时更新用户字段lastActivity。您可以检查lastActivity < now()- 2 minutes并更新lastActivity时间戳。

另外:Implementing user activity in symfony 2

以下是如何操作

注意:如果您没有使用FOSUserBundle,请参阅下面的编辑。

1 将此添加到您的用户实体

/**
 * 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 创建事件监听器

<?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 将事件监听器声明为服务

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 }

你很高兴去吧!

编辑(不含FOSUserBundle)

1 将此添加到您的用户实体

Same as Step 1 Above

2 创建事件监听器

<?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 将事件监听器声明为服务

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 }

你很高兴去吧!

答案 1 :(得分:9)

由于我无法对帖子发表评论,我仍然希望Mick通过此答案对答案发表评论。

从Symfony 2.6开始,不推荐使用SecurityContext类,在这种情况下,应该使用TokenStorage类。

因此,services.yml如下:

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

而不是

use Symfony\Component\Security\Core\SecurityContext;

应该

use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

(也用TokenStorage类替换类中的SecurityContext)

然后,在第38行,将使用

检查令牌可用性
$this->tokenStorage->getToken()

并且,在第39行,将使用

获取用户实例
$this->tokenStorage->getToken()->getUser()

答案 2 :(得分:0)

Symfony 3.4更新

<强> 1。将其添加到您的用户实体

Same as Step 1 Above

<强> 2。创建事件监听器

<?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 $tokenContext;
    protected $doctrine;

    public function __construct(TokenyContext $tokenContext, $doctrine)
    {
        $this->tokenContext= $tokenContext;
        $this->doctrine= $doctrine;
    }

    /**
    * 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->tokenContext->getToken()) {
            $user = $this->tokenContext->getToken()->getUser();

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

第3。将事件监听器声明为服务

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

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

答案 3 :(得分:0)

对于Symfony3.4(4),我使用 EntityManagerInterface 来更新用户,使用 Security 来获取用户,以下代码为我工作:

应用/配置/ services.yml

AppBundle\Service\ActivityListener:
    tags:
        - { name: 'kernel.event_listener', event: 'kernel.controller', method: onCoreController }

<强>服务/ ActivityListener.php

<?php
namespace AppBundle\Service;

use AppBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\Security\Core\Security;

class ActivityListener
{
    private $em;
    private $security;

  public function __construct(EntityManagerInterface $em, Security $security)
  {
    $this->em = $em;
    $this->security = $security;
  }

  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->security->getToken()) {
        $user = $this->security->getToken()->getUser();

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

答案 4 :(得分:0)

Symfony 4 中,我通过以下方式解决了该问题。

<?php

namespace App\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;

class ActivitySubscriber implements EventSubscriberInterface {

    private $em;
    private $security;

    public function __construct(
    EntityManagerInterface $em, Security $security) {
        $this->em = $em;
        $this->security = $security;
    }

    public function onTerminate() {
        $user = $this->security->getUser();

        if (!$user->isActiveNow()) {
            $user->setLastActivityAt(new \DateTime());
            $this->em->flush($user);
        }
    }

    public static function getSubscribedEvents() {
        return [
            // must be registered before (i.e. with a higher priority than) the default Locale listener
            KernelEvents::TERMINATE => [['onTerminate', 20]],
        ];
    }

}