<?php
/**
* Tru voter check access tru
*
* @package RMCS
* @author Vlad Shashkov <vlad.s@zimalab.com>
* @copyright 2014 - 2019 The Zimalab
*/
declare(strict_types=1);
namespace App\Security;
use App\Entity\Main\{Permission, User};
use Doctrine\Persistence\{ManagerRegistry, ObjectManager};
use Symfony\Component\HttpFoundation\{Request, RequestStack};
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class TruVoter extends Voter
{
/**
* @var array const
*/
private const FLAGS = [
'CheckReadTru' => 'ROLE_R',
'CheckReadWriteTru' => 'ROLE_RW',
'CheckAdminTru' => 'ROLE_ADMIN',
'CheckOwnerTRu' => 'ROLE_OWNER'
];
/**
* @var array const
*/
public const ROLES = [
'r' => 'ROLE_R',
'rw' => 'ROLE_RW',
'admin' => 'ROLE_ADMIN',
'root' => 'ROLE_OWNER'
];
/**
* @var array
*/
private const WEIGHTS = [
'ROLE_R' => 1,
'ROLE_RW' => 2,
'ROLE_ADMIN' => 3,
'ROLE_OWNER' => 4
];
/**
* @var ObjectManager
*/
private $em;
/**
* @var Request|null
*/
private $request;
/**
* TruVoter constructor.
*
* @param ManagerRegistry $registry
* @param RequestStack $requestStack
*/
public function __construct(ManagerRegistry $registry, RequestStack $requestStack)
{
$this->em = $registry->getManager('default');
$this->request = $requestStack->getCurrentRequest();
}
/**
* Determines if the attribute and subject are supported by this voter.
*
* @param string $attribute An attribute
* @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type
*
* @return bool True if the attribute and subject are supported, false otherwise
*/
protected function supports($attribute, $subject):bool
{
return in_array($attribute, array_keys(self::FLAGS));
}
/**
* Perform a single access check operation on a given attribute, subject and token.
* It is safe to assume that $attribute and $subject already passed the "supports()" method check.
*
* @param string $attribute
* @param mixed $subject
*
* @param TokenInterface $token
* @return bool
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token):bool
{
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
$userRoleWeight = $this->getUserRoleWeight($user);
$accessWeight = $this->getAccessWeight($attribute);
return $userRoleWeight >= $accessWeight;
}
/**
* @param User $user
* @return bool
*/
private function getUserRoleWeight(User $user): bool
{
// Get user role weight
$roleUserWeight = $this->getRoleWeight(current($user->getRoles()));
// Get site role weight
$client = $user->getClient()->getId();
$idTru = intval($this->request->get('id_tru'));
$siteRole = $this->em->getRepository(Permission::class)
->findPermissionByClient($client, $idTru);
$siteRoleWeight = $this->getRoleWeight($siteRole);
// Which role weight we should use for get access ?
return $roleUserWeight > $siteRoleWeight ?
$siteRoleWeight :
$roleUserWeight;
}
/**
* @param $attribute
* @return false|int|string
*/
private function getAccessWeight(string $attribute)
{
$accessRole = self::FLAGS[$attribute];
return $this->getRoleWeight($accessRole);
}
/**
* @param $role
* @return false|int|string
*/
private function getRoleWeight(string $role)
{
return array_search($role, self::WEIGHTS);
}
/**
* @return array|false
*/
public static function getRoles()
{
return array_combine(range(1, count(self::ROLES)), array_values(self::ROLES));
}
}