src/Security/CustomerVoter.php line 16

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Security;
  4. use App\Entity\Customer\Customer;
  5. use App\Entity\User\AdminUser;
  6. use LogicException;
  7. use Symfony\Component\HttpFoundation\RequestStack;
  8. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  9. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  10. use function in_array;
  11. class CustomerVoter extends Voter
  12. {
  13.     public const SHOW = 'show';
  14.     public const UPDATE = 'update';
  15.     public const ARCHIVE = 'archive';
  16.     public function __construct(
  17.         private readonly RequestStack $requestStack,
  18.     ) {
  19.     }
  20.     protected function supports(string $attribute, mixed $subject): bool
  21.     {
  22.         // if the attribute isn't one we support, return false
  23.         if (! in_array($attribute, [self::SHOW, self::UPDATE, self::ARCHIVE], true)) {
  24.             return false;
  25.         }
  26.         return $subject instanceof Customer;
  27.     }
  28.     protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
  29.     {
  30.         $adminUser = $token->getUser();
  31.         if (! $adminUser instanceof AdminUser) {
  32.             // the user must be logged in; if not, deny access
  33.             return false;
  34.         }
  35.         /** @var Customer $customer */
  36.         $customer = $subject;
  37.         return match ($attribute) {
  38.             self::SHOW => $this->canShow($customer, $adminUser),
  39.             self::UPDATE => $this->canUpdate($customer, $adminUser),
  40.             self::ARCHIVE => $this->canArchive($customer, $adminUser),
  41.             default => throw new LogicException('This code should not be reached!')
  42.         };
  43.     }
  44.     private function canShow(Customer $customer, AdminUser $adminUser): bool
  45.     {
  46.         return $this->checkAccess($customer, $adminUser, self::SHOW);
  47.     }
  48.     private function canUpdate(Customer $customer, AdminUser $adminUser): bool
  49.     {
  50.         return $this->checkAccess($customer, $adminUser, self::UPDATE);
  51.     }
  52.     private function canArchive(Customer $customer, AdminUser $adminUser): bool
  53.     {
  54.         $loggedClinicalManager = $adminUser->getCustomer()?->getClinicalManager();
  55.         return $loggedClinicalManager === null ||
  56.             $customer->getDoctor() === null ||
  57.             $customer->getDoctor()->getAttachedClinicalManager()?->getId() === $loggedClinicalManager->getId();
  58.     }
  59.     public function checkAccess(Customer $customer, AdminUser $adminUser, string $attribute): bool
  60.     {
  61.         $loggedClinicalManager = $adminUser->getCustomer()?->getClinicalManager();
  62.         $request = $this->requestStack->getCurrentRequest();
  63.         if ($request === null) {
  64.             return false;
  65.         }
  66.         if ($this->isDoctorAccessRoute((string) $request->get('_route'), $attribute) && $customer->getDoctor() !== null) { // @phpstan-ignore-line
  67.             if ($loggedClinicalManager === null) {
  68.                 return true;
  69.             }
  70.             return $customer->getDoctor()->getAttachedClinicalManager()?->getId() === $loggedClinicalManager->getId();
  71.         }
  72.         return $request->get('_route') === 'app_admin_distributor_' . $attribute && $customer->getDistributor() !== null;
  73.     }
  74.     private function isDoctorAccessRoute(string $route, string $attribute): bool
  75.     {
  76.         if ($route === 'app_admin_doctor_' . $attribute) {
  77.             return true;
  78.         }
  79.         return $attribute === self::UPDATE && in_array($route, [
  80.             'app_admin_doctor_address_upsert',
  81.             'app_admin_doctor_address_modal',
  82.         ], true);
  83.     }
  84. }