<?php
namespace App\Security;
use App\Entity\Course;
use App\Entity\User;
use App\Service\InstructorService;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
* Checks if a user instructs any courses and can therefore access instructor controllers.
*/
class InstructorVoter extends Voter
{
private AdminVoter $adminVoter;
private InstructorService $instructorService;
public function __construct(AdminVoter $adminVoter, InstructorService $instructorService)
{
$this->adminVoter = $adminVoter;
$this->instructorService = $instructorService;
}
protected function supports(string $attribute, $subject): bool
{
if ($attribute != 'INSTRUCTOR') {
return false;
}
if ($subject !== null && !$subject instanceof Course) {
return false;
}
return true;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) {
// must be logged in
return false;
}
if ($this->adminVoter->isAdmin($user)) {
// admin has implicit instructor privileges
return true;
}
if ($subject == null) {
// no specific course, check if they instruct _any_ course
return !empty($this->instructorService->fetchInstructorCourses($user));
}
return self::canSeeCourse($user, $subject);
}
public static function canSeeCourse(User $instructor, Course $course): bool
{
return !empty(array_intersect($instructor->getRoles(), $course->getInstructorPositions()));
}
}