订阅的事件,如果我需要记录用户的上次活动时间?

时间:2017-08-18 13:27:06

标签: symfony

我需要记录最后一个用户的活动时间,每个页面加载或ajax呼叫计数。

我想我需要订阅一些活动,但我不知道哪一个。

this answer中提到的InteractiveLoginEvent,我的理解仅在交互式登录时触发。但是,如果一个会话可能持续一周或更长时间,它将使记录方式过于不准确。所以我需要另一个活动,但是哪一个?

或者,是否有开箱即用的功能?

2 个答案:

答案 0 :(得分:1)

解决方案可以是KernelEvents::RESPONSE事件的监听器,确保用户通过身份验证。

namespace AppBundle\Subscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class LastActivityListener implements EventSubscriberInterface
{
    private $tokenStorage;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    public function onResponse(FilterResponseEvent $event)
    {
        $token = $this->tokenStorage->getToken();

        if ($token->isAuthenticated()) {
            // save last activity for $token->getUser(); in some place.
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::RESPONSE => 'onResponse',
        ];
    }
}

此外,您可能需要注入存储服务以保存此记录(例如,如果Doctrine可用,则为EntityManager。)

答案 1 :(得分:1)

执行此操作的最简单方法是订阅kernel.controller事件,该事件将在每个控制器操作之前运行,无论是正常还是通过AJAX。它看起来像这样:

namespace AppBundle\EventSubscriber;

use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class UserActivityLogSubscriber implements EventSubscriberInterface
{
    /** @var TokenStorageInterface **/
    private $tokenStorage;

    /** @var LoggerInterface **/
    private $logger;

    /**
     * @param TokenStorageInterface $tokenStorage
     * @param LoggerInterface $logger
     */
    public function __construct(
        TokenStorageInterface $tokenStorage,
        LoggerInterface $logger
    ) {
        $this->tokenStorage = $tokenStorage;
        $this->logger       = $logger;
    }

    public function onKernelController(FilterControllerEvent $event)
    {
        $actionTime = new \DateTime();
        $controller = $event->getController();

        if (!is_array($controller) {
            return;
        }

        $action = get_class($controller[0]).'::'.$controller[1];

        $token = $this->tokenStorage->getToken();
        $user  = $token->getUser();

        if ($user) {
            $logger->info('User: '.$user->getId().' Action: '.$action.' at: '.$now->format('Y-m-d g:i:s');
        }
    }

    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::CONTROLLER => 'onKernelController',
        );
    }
}

这只是将控制器操作记录到标准记录器的简单示例。您可以注入 EntityManager ,而不是仅输出到日志,而是将事件时间记录到数据库中的last_activity列。

您还可以执行类似于创建 UserLoggableController 控制器接口的操作,并且只有在您的控制器实现该接口时才执行此操作:

<强>接口

namespace AppBundle\Controller;

interface UserLoggableController
{
    // ...
}

<强>控制器:

class MyController extends Controller implements UserLoggableController

修改后的UserActivityLogSubscriber:

if (!$controller[0] instanceof UserActivityLogSubscriber) {
    return;
}

Symfony在setting up controller before/after filters上也提供了一些很好的文档。