<?php
namespace App\Security;
use App\Entity\Salarie;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
/**
* Verrouille l'accès aux routes pour un Salarié connecté selon une liste
* blanche stricte. Le patron (User) n'est jamais concerné par ce filtre.
*
* Objectif : garantir qu'aucune interface hors périmètre (Devis, Bon de
* commande, Bon de livraison, Facture, Entreprise, gestion des salariés...)
* ne devienne accessible à un salarié, même par oubli dans un contrôleur.
*/
class SalarieAccessSubscriber implements EventSubscriberInterface
{
private $security;
private $urlGenerator;
public function __construct(Security $security, UrlGeneratorInterface $urlGenerator)
{
$this->security = $security;
$this->urlGenerator = $urlGenerator;
}
public static function getSubscribedEvents(): array
{
return [
// priorité négative : s'exécute après le RouterListener (route déjà résolue)
KernelEvents::REQUEST => ['onKernelRequest', -10],
];
}
public function onKernelRequest(RequestEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$user = $this->security->getUser();
if (!$user instanceof Salarie) {
return;
}
$route = $event->getRequest()->attributes->get('_route');
if (!$route) {
return;
}
// Toujours autorisé : la caisse elle-même et les créations rapides depuis la caisse
$alwaysAllowed = [
'app_logout',
'app_login',
'app_categorie_new_from_caisse',
'app_produit_new_from_caisse',
'client_new_modal',
];
if (in_array($route, $alwaysAllowed, true) || 0 === strpos($route, 'point_vente_')) {
return;
}
if (0 === strpos($route, 'app_produit_')) {
if ($user->isAccesProduits()) {
return;
}
$this->deny($event);
return;
}
if (0 === strpos($route, 'reparation_')) {
if ($user->isAccesReparations()) {
return;
}
$this->deny($event);
return;
}
if (0 === strpos($route, 'client_')) {
if ($user->isAccesClients()) {
return;
}
$this->deny($event);
return;
}
if (0 === strpos($route, 'caisse_rapports_')) {
if ($user->isAccesRapports()) {
return;
}
$this->deny($event);
return;
}
if (0 === strpos($route, 'caisse_cloture_')) {
// L'ouverture d'une session est toujours libre ; seule la fermeture
// et l'administration des clôtures nécessitent le droit dédié.
if (in_array($route, ['caisse_cloture_ouvrir'], true)) {
return;
}
if ($user->isAccesCloture() && in_array($route, ['caisse_cloture_fermer'], true)) {
return;
}
$this->deny($event);
return;
}
// Tout le reste (Devis, BonCommande, BonLivraison, Facture, Entreprise,
// Salariés, Dashboard admin...) est refusé par défaut.
$this->deny($event);
}
private function deny(RequestEvent $event): void
{
$event->getRequest()->getSession()->getFlashBag()->add('error', 'Accès non autorisé.');
$event->setResponse(new RedirectResponse($this->urlGenerator->generate('point_vente_index')));
}
}