src/App/Api/Security/Voter/UserPermissionVoter.php line 19

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Api\Security\Voter;
  4. use App\Api\Entity\UserAbstract;
  5. use Doctrine\Common\Collections\Collection;
  6. use Symfony\Component\HttpFoundation\Request;
  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 Symfony\Component\Security\Core\User\UserInterface;
  11. /**
  12.  * Action and entityVoterName set in attribute to create permission type and check it in user permissions.
  13.  * Example: attributes="create, dues" => convert to 'can_create_dues' in permission type.
  14.  */
  15. class UserPermissionVoter extends Voter
  16. {
  17.     // actions
  18.     const VIEW 'view';
  19.     const CREATE 'create';
  20.     const UPDATE 'update';
  21.     const EDIT 'edit';
  22.     const MAKE 'make';
  23.     // entityVoterName
  24.     private const DUE 'due';
  25.     private const DUES 'dues';
  26.     private const ENTERPRISE 'enterprise';
  27.     private const EXEMPTIONS 'exemptions';
  28.     private const ANALYTICS 'analytics';
  29.     private const DELIMITER ', ';
  30.     private $requestStack;
  31.     public function __construct(RequestStack $requestStack)
  32.     {
  33.         $this->requestStack $requestStack;
  34.     }
  35.     protected function supports($attribute$subject): bool
  36.     {
  37.         if (!$this->resolveRoute($this->requestStack->getCurrentRequest())) {
  38.             return false;
  39.         }
  40.         if (!$this->isValidAttribute($attribute)) {
  41.             return false;
  42.         }
  43.         list($action$entityVoterName) = explode(', '$attribute);
  44.         if ($this->isValidAction($action) || $this->isValidEntityVoterName($entityVoterName)) {
  45.             return false;
  46.         }
  47.         return true;
  48.     }
  49.     protected function voteOnAttribute($attribute$subjectTokenInterface $token): bool
  50.     {
  51.         $user $token->getUser();
  52.         if ($this->resolveTdc1CompanyDueRoute($user)) {
  53.             return true;
  54.         }
  55.         if (!$user instanceof UserAbstract || !$permissions $user->getPermissions()) {
  56.             return false;
  57.         }
  58.         list($action$entityVoterName) = explode(', '$attribute);
  59.         switch ($action) {
  60.             case self::VIEW:
  61.             case self::CREATE:
  62.             case self::EDIT:
  63.             case self::UPDATE:
  64.                 return $this->canAction($permissions$action$entityVoterName);
  65.             case self::MAKE:
  66.                 return $this->canAction($permissions$action$entityVoterNametrue);
  67.             default:
  68.                 return false;
  69.         }
  70.     }
  71.     private function resolveRoute(Request $request): bool
  72.     {
  73.         return strpos($request->getRequestUri(), 'admin') === false;
  74.     }
  75.     private function isValidAttribute($attribute): bool
  76.     {
  77.         if (!is_string($attribute)) {
  78.             return false;
  79.         }
  80.         $position strpos($attributeself::DELIMITER);
  81.         return !($position === false || $position === 0);
  82.     }
  83.     private function isValidAction(string $action): bool
  84.     {
  85.         return !in_array($action, [self::VIEWself::CREATEself::UPDATEself::EDITself::MAKE]);
  86.     }
  87.     private function isValidEntityVoterName(string $entityVoterName): bool
  88.     {
  89.         return !in_array($entityVoterName, [self::DUEself::DUESself::ENTERPRISEself::EXEMPTIONSself::ANALYTICS]);
  90.     }
  91.     private function resolveTdc1CompanyDueRoute(UserInterface $user): bool
  92.     {
  93.         $request $this->requestStack->getCurrentRequest();
  94.         return $user->isTdc1Company()
  95.             && str_contains($request->getRequestUri(), '/api/v1/due')
  96.             && $request->isMethod(Request::METHOD_GET)
  97.         ;
  98.     }
  99.     private function canAction(
  100.         Collection $permissions,
  101.         string $action,
  102.         string $entityVoterName,
  103.         bool $isMake false
  104.     ): bool {
  105.         $permissionType $this->createPermissionType($action$entityVoterName$isMake);
  106.         $userPermissionValues $permissions->map(
  107.             function ($permission) {
  108.                return $permission->getType();
  109.             })
  110.         ;
  111.         return in_array($permissionType$userPermissionValues->toArray());
  112.     }
  113.     private function createPermissionType(string $actionstring $entityVoterNamebool $isMake false): string
  114.     {
  115.         return $isMake
  116.             sprintf('can_%s_%s_effective'$action$entityVoterName)
  117.             : sprintf('can_%s_%s'$action$entityVoterName);
  118.     }
  119. }