<?php
namespace App\Security\Voter;
use App\Entity\User;
use App\Entity\UserWorkroom;
use App\Entity\UserWorkroomArena;
use App\Entity\WorkroomArena;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Class WorkroomArenaVoter.
*/
class WorkroomArenaVoter extends Voter
{
// Permissions.
const WORKROOM_ARENA_VIEW = 'workroom__arena_view';
// Full list.
const PERMISSIONS = [
self::WORKROOM_ARENA_VIEW,
];
private EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* {@inheritdoc}
*/
protected function supports($attribute, $subject): bool
{
return in_array($attribute, self::PERMISSIONS) && ($subject instanceof WorkroomArena);
}
/**
* {@inheritdoc}
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
/** @var User $user */
$user = $token->getUser();
// If the user is anonymous, do not grant access.
if (!$user instanceof UserInterface) {
return false;
}
// Check conditions and provide access bases on it.
switch ($attribute) {
case self::WORKROOM_ARENA_VIEW:
return $this->canView($subject, $user);
default:
break;
}
return false;
}
/**
* Vérifie l'accès à une arène de workroom.
*
* Logique :
* 1. Si user explicitement dans `user_workroom_arena` → accès accordé (membre direct)
* 2. Sinon fallback : si user membre du **workroom parent** (`user_workroom`)
* → accès accordé. L'arène est un canal de la workroom — tout membre du
* workroom y a accès par défaut. Cette logique évite que des users importés
* d'une vieille DB (sans `user_workroom_arena` rempli) soient bloqués.
* 3. Sinon refus.
*
* Les ROLE_ADMIN passent toujours (gestion).
*/
public function canView(WorkroomArena $workroomArena, User $user): bool
{
if (in_array('ROLE_ADMIN', $user->getRoles(), true)) return true;
// 1. Membre direct de l'arène
$userWorkroomArena = $this->em->getRepository(UserWorkroomArena::class)->findBy([
'workroomArena' => $workroomArena->getId(),
'user' => $user->getId(),
]);
if (!empty($userWorkroomArena)) return true;
// 2. Fallback : membre du workroom parent
$workroom = $workroomArena->getWorkroom();
if (!$workroom) return false;
$userWorkroom = $this->em->getRepository(UserWorkroom::class)->findBy([
'workroom' => $workroom->getId(),
'user' => $user->getId(),
]);
return !empty($userWorkroom);
}
}