src/Security/Voter/CrudVoter.php line 19
<?php
namespace App\Security\Voter;
use App\Entity\Action;
use App\Entity\UserRole;
use App\Entity\EntityName;
use App\Entity\Permission;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* Voter for the operations on CRUD entities
*/
class CrudVoter extends Voter
{
private $security, $actions, $em;
/**
* Constructor. Sets the global variables and creates a list with the names of the actions
*
* @param Security $security Required by Symfony
* @param EntityManagerInterface $em Used to get the list of the actions and the user's permissions from the database
* @return void
*/
public function __construct(Security $security, EntityManagerInterface $em)
{
$actionObjectList = $em->getRepository(Action::class)->findAll();
$this->actions = array(); // [NEW, EDIT, ...]. It was CRUD_*action* but this is better
$this->security = $security;
$this->em = $em;
foreach ($actionObjectList as $action)
{
array_push($this->actions, $action->getName());
}
}
/**
* Checks whether the voter has to vote on the required permission
*
* @param string $attribute The required action (NEW/LIST/VIEW/EDIT/DELETE). The first parameter of denyAccessUnlessGranted
* @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
* @return bool True if the voter is going to vote, false otherwise
*/
protected function supports(string $attribute, $subject): bool
{
// First, $attribute is the authentication role, then it changes to the first parameter of denyAccessUnlessGranted
return in_array($attribute, $this->actions);
}
/**
* Determines whether the user has the permission to perform the required action to a certain entity
*
* @param string $attribute The required action (NEW/LIST/VIEW/EDIT/DELETE). The first parameter of denyAccessUnlessGranted
* @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
* @param TokenInterface $token Used to get the User object of the user who is requesting the permission
* @return bool True if the permission is granted, false otherwise
*/
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
// if the user is anonymous, do not grant access
if (!$user instanceof UserInterface)
return false;
// I want the list of permissions for the entity on which I'm doing the CRUD
// Then I check if there's at least a role the user also has
$totalPermissions = array();
foreach ($user->getRoles() as $role)
{
$roleID = $this->em->getRepository(UserRole::class) ->findOneBy(['name' => $role]);
$entityID = $this->em->getRepository(EntityName::class)->findOneBy(['name' => $subject->getEntityName()]);
$actionID = $this->em->getRepository(Action::class) ->findOneBy(['name' => $attribute]);
// Check in the database if the permission exists (if a user with a role $roleID can perform the action $actionID on the $entityName entities
$permission = $this->em->getRepository(Permission::class)->findOneByAllFields($roleID, $entityID, $actionID);
if ($permission) // Without this check it would put a null object in the array
array_push($totalPermissions, $permission);
}
if (!empty($totalPermissions))
return true; // I just need the user to have one permission
return false;
}
}