src/Security/Voter/CrudVoter.php line 19

  1. <?php
  2. namespace App\Security\Voter;
  3. use App\Entity\Action;
  4. use App\Entity\UserRole;
  5. use App\Entity\EntityName;
  6. use App\Entity\Permission;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use Symfony\Bundle\SecurityBundle\Security;
  9. use Symfony\Component\Security\Core\User\UserInterface;
  10. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  11. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  12. /**
  13.  * Voter for the operations on CRUD entities
  14.  */
  15. class CrudVoter extends Voter
  16. {
  17.     private $security$actions$em;
  18.     /**
  19.      * Constructor. Sets the global variables and creates a list with the names of the actions
  20.      * 
  21.      * @param Security $security Required by Symfony
  22.      * @param EntityManagerInterface $em Used to get the list of the actions and the user's permissions from the database
  23.      * @return void
  24.      */
  25.     public function __construct(Security $securityEntityManagerInterface $em)
  26.     {
  27.         $actionObjectList $em->getRepository(Action::class)->findAll();
  28.         $this->actions = array();    // [NEW, EDIT, ...]. It was CRUD_*action* but this is better
  29.         $this->security $security;
  30.         $this->em $em;
  31.         foreach ($actionObjectList as $action)
  32.         {
  33.             array_push($this->actions$action->getName());
  34.         }
  35.     }
  36.     
  37.     /**
  38.      * Checks whether the voter has to vote on the required permission
  39.      * 
  40.      * @param string $attribute The required action (NEW/LIST/VIEW/EDIT/DELETE). The first parameter of denyAccessUnlessGranted
  41.      * @param mixed $subject The entity's object which the voter may have to vote on, the second parameter of denyAccessUnlessGranted. Does not play a role in whether or not the voter is going to vote
  42.      * @return bool True if the voter is going to vote, false otherwise
  43.      */
  44.     protected function supports(string $attribute$subject): bool
  45.     {
  46.         // First, $attribute is the authentication role, then it changes to the first parameter of denyAccessUnlessGranted
  47.         return in_array($attribute$this->actions);
  48.     }
  49.     /**
  50.      * Determines whether the user has the permission to perform the required action to a certain entity
  51.      * 
  52.      * @param string $attribute The required action (NEW/LIST/VIEW/EDIT/DELETE). The first parameter of denyAccessUnlessGranted
  53.      * @param mixed $subject The entity on which to perform the requested action, the second parameter of denyAccessUnlessGranted. Used only to get the entity's name
  54.      * @param TokenInterface $token Used to get the User object of the user who is requesting the permission
  55.      * @return bool True if the permission is granted, false otherwise
  56.      */
  57.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  58.     {
  59.         $user $token->getUser();
  60.         // if the user is anonymous, do not grant access
  61.         if (!$user instanceof UserInterface)
  62.             return false;
  63.         // I want the list of permissions for the entity on which I'm doing the CRUD
  64.         // Then I check if there's at least a role the user also has
  65.         $totalPermissions = array();
  66.         foreach ($user->getRoles() as $role)
  67.         {
  68.             $roleID   $this->em->getRepository(UserRole::class)  ->findOneBy(['name' => $role]);
  69.             $entityID $this->em->getRepository(EntityName::class)->findOneBy(['name' => $subject->getEntityName()]);
  70.             $actionID $this->em->getRepository(Action::class)    ->findOneBy(['name' => $attribute]);
  71.             // Check in the database if the permission exists (if a user with a role $roleID can perform the action $actionID on the $entityName entities
  72.             $permission $this->em->getRepository(Permission::class)->findOneByAllFields($roleID$entityID$actionID);
  73.             
  74.             if ($permission)    // Without this check it would put a null object in the array
  75.                 array_push($totalPermissions$permission);
  76.         }
  77.         if (!empty($totalPermissions))
  78.             return true;        // I just need the user to have one permission
  79.         return false;
  80.     }
  81. }