<?php
namespace App\EventSubscriber;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\Request;
/**
* Désactive l'abonnement premium à la volée (sans cron) dès qu'une requête arrive
* et que la date d'expiration est dépassée.
*/
class PremiumExpirationSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly Security $security,
private readonly EntityManagerInterface $em,
private readonly bool $premiumFemaleDefault
) {
}
public static function getSubscribedEvents(): array
{
return [
// Après le firewall (token déjà résolu), avant l’exécution du contrôleur.
KernelEvents::CONTROLLER => ['onKernelController', 0],
];
}
public function onKernelController(ControllerEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
if ($this->isStaticAsset($request)) {
return;
}
/** @var User|null $user */
$user = $this->security->getUser();
if (!$user) {
return;
}
$isFemale = \in_array('ROLE_FEMALE', $user->getRoles(), true);
if ($this->premiumFemaleDefault && $isFemale) {
if (!$user->isPremium()) {
$this->updatePremiumStatus($user, true);
}
return;
}
if (!$user->isPremium()) {
return;
}
// payData peut être stocké en array (doctrine json) ou en JSON string :
$payDataRaw = $user->getPayData();
$payData = \is_array($payDataRaw) ? $payDataRaw : json_decode((string) $payDataRaw, true);
if (!\is_array($payData)) {
// Donnée corrompue ou absente : désactive par sécurité
$this->updatePremiumStatus($user, false);
return;
}
$nowTs = time();
$endTs = isset($payData['dateAbonnementEnd']) ? (int) $payData['dateAbonnementEnd'] : 0;
$isPaid = filter_var($payData['isPaid'] ?? false, FILTER_VALIDATE_BOOL);
$shouldBePremium = $isPaid && $endTs !== 0 && $nowTs < $endTs;
if (!$user->isPremium() && $shouldBePremium) {
$this->updatePremiumStatus($user, true);
}
$shouldBeDeniedPremium = $endTs === 0 || $endTs < $nowTs;
if ($user->isPremium() && $shouldBeDeniedPremium) {
$this->updatePremiumStatus($user, false);
}
}
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);
}
private function updatePremiumStatus(User $user, bool $isPremium): void
{
$user->setIsPremium($isPremium);
$this->em->persist($user);
$this->em->flush();
$this->em->refresh($user);
}
}