<?php
namespace App\EventSubscriber;
use App\Entity\Application\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Twig\Environment;
class ActivitySubscriber implements EventSubscriberInterface {
public function __construct(private EntityManagerInterface $em, private AuthorizationCheckerInterface $authorizationChecker, private Environment $twig, private Security $security)
{
}
public function onController($event) {
$request = $event->getRequest();
$user = $this->security->getUser();
$userConflict = null;
$this->twig->addGlobal("userConflict", null);
if ($user && ($this->authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY') || $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED'))) {
if (!$user->isActiveNow()) {
$user->setLastActivityAt(new \DateTime());
$this->em->persist($user);
$this->em->flush();
}
// TODO: temporarly only checking requisition edit & some other routes, adjust preg for every edit/actions
// TODO: Should we ceate an annotation @UserConflict ??? Or a config to get all routes to handle?
$isConflictCheckedRoute = $this->verifyConflictingRoutes($request->getPathInfo());
if ($isConflictCheckedRoute) {
preg_match("/\/(\d+)$/", $request->getPathInfo(), $matches);
$id = $matches[1];
$routesToValidate = $this->matchingRoutes($request->getPathInfo(), $id);
$userConflict = $this->em->getRepository(User::class)
->findOneWithRoute($routesToValidate, $user->getId());
if ($userConflict) {
$this->twig->addGlobal("userConflict", $userConflict);
}
}
}
}
public function onTerminate($event){
$request = $event->getRequest();
$user = $this->security->getUser();
if ($user && ($this->authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY') || $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED'))) {
$user->setLastActivityAt(new \DateTime());
if(!preg_match("/ajax|error/i", $request->getPathInfo())){
$user->setCurrentRoute($request->getPathInfo());
if($isConflictCheckedRoute = $this->verifyConflictingRoutes($request->getPathInfo())){
preg_match("/\/(\d+)$/", $request->getPathInfo(), $matches);
$id = $matches[1];
$routesToValidate = $this->matchingRoutes($request->getPathInfo(), $id);
$userConflict = $this->em->getRepository(User::class)
->findOneWithRoute($routesToValidate, $user->getId());
if(!$userConflict) { $user->setHasPriority(true); }
}
}
$this->em->persist($user);
$this->em->flush();
}
}
private function verifyConflictingRoutes($pathInfo) {
$routes = [
"/requisition\/edit/i",
"/project-requisition\/transfer\/return/i",
"/project-requisition\/transfer\/release/i",
"/project\/edit/i",
"/project\/transfer\/return/i",
"/project\/transfer\/release/i",
"/location-requisition\/edit/i",
"/location-requisition\/transfer\/return/i",
"/location-requisition\/transfer\/release/i",
];
foreach($routes as $route) {
if(preg_match($route, $pathInfo)) {
return true;
}
}
return false;
}
private function matchingRoutes($pathInfo, $id) {
if (preg_match("/(project)*-*requisition/", $pathInfo) && !preg_match("/location-requisition/", $pathInfo)) {
$routesToValidate = [
"/requisition/edit/".$id,
"/project-requisition/transfer/return/".$id,
"/project-requisition/transfer/release/".$id,
];
} else if (preg_match("/location-requisition/", $pathInfo)) {
$routesToValidate = [
"/location-requisition/edit/".$id,
"/location-requisition/transfer/return/".$id,
"/location-requisition/transfer/release/".$id,
];
} else {
$routesToValidate = [
"/project/edit/".$id,
"/project/transfer/return/".$id,
"/project/transfer/release/".$id,
];
}
return $routesToValidate;
}
public static function getSubscribedEvents() :?array
{
return [
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::CONTROLLER => [['onController', 20]],
KernelEvents::TERMINATE => [['onTerminate', 20]]
];
}
}