src/Security/Core/SessionAccessVoter.php line 22

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Security\Core;
  4. use App\Entity\Core\ActivitySessionInterface;
  5. use App\Entity\User\User;
  6. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  7. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  8. /**
  9. * Controls read and edit access to activity sessions (QuizSession, DictateSession, ReadingTestSession).
  10. *
  11. * A teacher may view or edit a session if:
  12. * - they created the session (createdBy), OR
  13. * - they are listed as a teacher in the session's classroom (classroom_teacher).
  14. *
  15. * This allows supervisors to create folders/sessions and assign them to classrooms
  16. * without blocking the classroom's teachers from viewing results or updating sessions.
  17. */
  18. class SessionAccessVoter extends Voter
  19. {
  20. public const string SESSION_VIEW = 'SESSION_VIEW';
  21. public const string SESSION_EDIT = 'SESSION_EDIT';
  22. private const array SUPPORTED_ATTRIBUTES = [self::SESSION_VIEW, self::SESSION_EDIT];
  23. /**
  24. *
  25. * @param string $attribute
  26. * @param mixed $subject
  27. *
  28. * @return bool
  29. */
  30. protected function supports(string $attribute, mixed $subject): bool
  31. {
  32. return in_array($attribute, self::SUPPORTED_ATTRIBUTES, true)
  33. && $subject instanceof ActivitySessionInterface;
  34. }
  35. /**
  36. * Perform a single access check operation on a given attribute, subject and token.
  37. * It is safe to assume that $attribute and $subject already passed the "supports()" method check.
  38. *
  39. * @param string $attribute
  40. * @param mixed $subject
  41. * @param TokenInterface $token
  42. * @return bool
  43. */
  44. protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
  45. {
  46. $user = $token->getUser();
  47. if (!$user instanceof User) {
  48. return false;
  49. }
  50. /** @var ActivitySessionInterface $subject */
  51. // The session creator always has access.
  52. if ($subject->getCreatedBy()?->getId() === $user->getId()) {
  53. return true;
  54. }
  55. // Any teacher associated with the session's classroom also has access.
  56. // Classroom::hasTeacher() checks the classroom_teacher join table by user ID.
  57. $classroom = $subject->getClassroom();
  58. return $classroom !== null && $classroom->hasTeacher($user);
  59. }
  60. }