<?phpnamespace App\Listener;use App\Entity\User;use App\Entity\UserTracking;use App\Entity\UserTrackingDetail;use App\Entity\UserTrackingDuration;use App\Repository\UserTrackingDurationRepository;use App\Repository\UserTrackingRepository;use Doctrine\ORM\EntityManagerInterface;use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpKernel\Event\TerminateEvent;use Symfony\Component\HttpKernel\KernelEvents;use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;class UserTrackingListener implements EventSubscriberInterface{ protected $authChecker; protected $tokenStorage; protected $entityManager; protected $userTrackingRepository; protected $userTrackingDurationRepository; public function __construct(TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authChecker, EntityManagerInterface $entityManager, UserTrackingRepository $userTrackingRepository, UserTrackingDurationRepository $userTrackingDurationRepository) { $this->authChecker = $authChecker; $this->tokenStorage = $tokenStorage; $this->entityManager = $entityManager; $this->userTrackingRepository = $userTrackingRepository; $this->userTrackingDurationRepository = $userTrackingDurationRepository; } public static function getSubscribedEvents() { return [ KernelEvents::TERMINATE => 'onKernelTerminate', ]; } public function onKernelTerminate(TerminateEvent $event) { $token = $this->tokenStorage->getToken(); $request = $event->getRequest(); $sessionId = null; //session could be null (API) if($request->hasSession()){ $sessionId = $request->getSession()->getId(); } if ($token != null && $sessionId && $event->isMasterRequest()) { $user = $token->getUser(); if ($user instanceof User) { $action = $request->attributes->get('_controller'); $method = $request->getMethod(); $ip = $request->getClientIp(); $statusCode = $event->getResponse()->getStatusCode(); // Exclude redirections & technical requests (ex: Liip\ImagineBundle) if ($statusCode === 200 && substr($action, 0, 4) === 'App\\') { // Check if this session is already tracked $userTracking = $this->userTrackingRepository->findOneBy(['sessionId' => $sessionId]); $duration = 0; if (!$userTracking) { // Create tracking $userTracking = new UserTracking(); $userTracking->setUser($user); $userTracking->setUserRole($user->getMainRole()); $userTracking->setSessionId($sessionId); $userTracking->setStartedAt(new \Datetime()); } else { // Update tracking $userTracking->setEndedAt(new \Datetime()); // Calculate duration $duration = $userTracking->getEndedAt()->getTimestamp() - $userTracking->getStartedAt()->getTimestamp(); $userTracking->setDuration($duration); } // Details tracking $userTrackingDetail = new UserTrackingDetail(); $userTrackingDetail->setUserTracking($userTracking); $userTrackingDetail->setDate(new \Datetime()); $userTrackingDetail->setPath($request->getPathInfo()); $userTrackingDetail->setAction($action); if ($request->request && $method === 'POST') { $userTrackingDetail->setData(json_encode($request->request->all())); } $userTrackingDetail->setMethod($method); $userTrackingDetail->setIp($ip); // Save $this->entityManager->persist($userTracking); $this->entityManager->persist($userTrackingDetail); $this->entityManager->flush(); /* Calculate average duration */ $averageDuration = 0; $nbLogsWithDuration = 0; $userTrackingLogs = $this->userTrackingRepository->findBy(['user' => $user]); foreach ($userTrackingLogs as $userTrackingLog) { if ($userTrackingLog->getDuration()) { $averageDuration += $userTrackingLog->getDuration(); ++$nbLogsWithDuration; } } if ($nbLogsWithDuration) { $averageDuration = round($averageDuration / $nbLogsWithDuration); } $userTrackingDuration = $user->getUserTrackingDuration(); if (!$userTrackingDuration) { $userTrackingDuration = new UserTrackingDuration(); $userTrackingDuration->setUser($user); $userTrackingDuration->setUserRole($user->getMainRole()); } $userTrackingDuration->setAverageDuration($averageDuration); $userTrackingDuration->setUpdatedAt(new \Datetime()); // Save $this->entityManager->persist($userTrackingDuration); $this->entityManager->flush(); } } } }}