<?php
namespace App\EventSubscriber;
use App\Service\AgendaReminderService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
/**
* Déclenche l'envoi des rappels agenda à la volée (sans cron),
* avec un throttling global pour éviter d'exécuter la tâche à chaque requête.
*/
class AgendaReminderDispatchSubscriber implements EventSubscriberInterface
{
private const CACHE_KEY = 'agenda_reminders.last_dispatch';
private const DISPATCH_INTERVAL_SECONDS = 60;
private const DISPATCH_LIMIT = 150;
public function __construct(
private readonly AgendaReminderService $agendaReminderService,
private readonly CacheInterface $cache,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER => ['onKernelController', 0],
];
}
public function onKernelController(ControllerEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
if ($this->isStaticAsset($request)) {
return;
}
$now = time();
$last = (int) $this->cache->get(self::CACHE_KEY, static function (ItemInterface $item) {
$item->expiresAfter(3600);
return 0;
});
if ($now - $last < self::DISPATCH_INTERVAL_SECONDS) {
return;
}
$this->cache->delete(self::CACHE_KEY);
$this->cache->get(self::CACHE_KEY, static function (ItemInterface $item) use ($now) {
$item->expiresAfter(3600);
return $now;
});
try {
$this->agendaReminderService->dispatchDueReminders(self::DISPATCH_LIMIT);
} catch (\Throwable $exception) {
// Ne pas bloquer la requête en cas d'erreur d'envoi des rappels.
}
}
private function isStaticAsset(Request $request): bool
{
$path = $request->getPathInfo();
return (bool) preg_match('#^/(build|assets|css|js|fonts|img|images|favicon\\.ico|robots\\.txt|_wdt|_profiler)#', $path);
}
}