<?php
namespace App\EventSubscriber;
use App\Security\ModulesResolver;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
class SessionModulesSubscriber implements EventSubscriberInterface
{
private ModulesResolver $modulesResolver;
private CacheInterface $cache;
private Security $security;
public function __construct(ModulesResolver $modulesResolver, CacheInterface $cache, Security $security)
{
$this->modulesResolver = $modulesResolver;
$this->cache = $cache;
$this->security = $security;
}
public static function getSubscribedEvents(): array
{
return [
// Escuchamos el request. Prioridad 0 se ejecuta DESPUÉS del SessionListener y del Firewall
// asegurando que el Token de seguridad esté cargado si el usuario está logueado.
KernelEvents::REQUEST => 'onKernelRequest',
];
}
public function onKernelRequest(RequestEvent $event): void
{
// Solo nos interesa la petición principal (evitar sub-requests en twig)
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
// Si no hay sesión, no hay nada que comprobar
if (!$request->hasSession()) {
return;
}
$session = $request->getSession();
// Solo actuamos si el usuario ya está logueado y tiene módulos inicializados en esta sesión
if (!$session->has('_modules')) {
return;
}
// Obtener la versión global de los módulos desde la caché.
// Si no existe (ej. recién borrada por el ConfigurationController), se genera con el timestamp actual.
// Nota: cache.app suele venir configurada por defecto en Symfony.
$globalVersion = $this->cache->get('global_modules_version', function (ItemInterface $item) {
$item->expiresAfter(31536000); // 1 Año de tiempo de vida
return time();
});
// Obtener la versión que tiene almacenada la sesión actual del usuario (por defecto 0 si acaba de loguearse)
$sessionVersion = $session->get('session_modules_version', 0);
// Si la versión de la sesión es anterior a la global, significa que la configuración global ha cambiado
if ($sessionVersion < $globalVersion) {
$user = $this->security->getUser();
if ($user !== null) {
// Recalculamos los permisos del usuario (que hace una llamada a la BD y verifica global y rol)
$mods = $this->modulesResolver->resolveForUser($user);
// Actualizamos la sesión en caliente
$session->set('_modules', (object) $mods);
$session->set('_config', $this->modulesResolver->getGlobalConfiguration());
}
// Actualizamos la versión de la sesión para que la comprobación if ($sessionVersion < $globalVersion)
// devuelva false la próxima vez, ahorrando llamadas a base de datos.
$session->set('session_modules_version', $globalVersion);
}
}
}