<?php
namespace App\Security;
use App\Entity\Users;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Doctrine\ORM\EntityManagerInterface;
use App\Service\UserHelper;
class UserVoter extends Voter
{
const ACCESS= [
'user_edit_super_critical_info' => 'user_edit_super_critical_info', //super admins only
'user_allowed_4_profile_editor'
=> 'user_allowed_4_profile_editor', //super admins and profiles editor only
'user_allowed_4_profile_editor_or_self_user_if_only_empty'
=> 'user_allowed_4_profile_editor_or_self_user_if_only_empty', //super admins & profiles editors. And if field is empty then also the user
'user_edit_critical_info' => 'user_edit_critical_info', //all admins
'user_edit_info_if_only_empty' => 'user_edit_info_if_only_empty', //all admins. And if field is empty then also the user
'user_edit_mobile_num_if_only_empty'
=> 'user_edit_mobile_num_if_only_empty' //super admins. and if field is empty then also vehicles admin and profiles admin
];
/**
* @var AccessDecisionManager|null
*/
protected $decisionManager;
/**
* @var EntityManager|null
*/
protected $entityManager;
/**
* @var EntityManager|null
*/
protected $userHelper;
/**
* DelegateVoter constructor.
* @param AccessDecisionManager|null $decisionManager
* @param EntityManager|null $entityManager
*/
public function __construct(AccessDecisionManagerInterface $decisionManager, EntityManagerInterface $entityManager, UserHelper $userHelper)
{
$this->decisionManager = $decisionManager;
$this->entityManager = $entityManager;
$this->userHelper = $userHelper;
}
/**
* determines if your voter should vote on the attribute/subject combination. If you return true,
* voteOnAttribute() will be called. Otherwise, your voter is done: some other voter should process this
*/
protected function supports($attribute, $subject)
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, self::ACCESS)) {
return false;
}
// only vote on Users objects inside this voter
// if ($subject && !$subject instanceof Users) {
// return false;
// }
return true;
}
/**
* If you return true from supports(), then this method is called. Your job is simple: return true to allow access
* and false to deny access
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$loggedinUser = $token->getUser();
if (!$loggedinUser instanceof Users) {
return false; // the user must be logged in; if not, deny access
}
// ROLE_SUPER_ADMIN can do anything! The power! Calling decide() on the AccessDecisionManager is essentially the same
// as calling isGranted() from a controller or other places (it's just a little lower-level, which is necessary for a voter).
if ($this->decisionManager->decide($token, ['ROLE_SUPER_ADMIN'])) {
return true;
}
switch ($attribute) {
case self::ACCESS['user_edit_super_critical_info']:
//no one except super admins can edit
return false;
case self::ACCESS['user_edit_critical_info']:
return $this->decisionManager->decide($token, ['ROLE_ADMIN']); //all admins are allowed
case self::ACCESS['user_allowed_4_profile_editor']:
return $this->decisionManager->decide($token, ['ROLE_PROFILES_EDITOR']); //only profile editors are allowed
case self::ACCESS['user_edit_info_if_only_empty']:
return $this->decisionManager->decide($token, ['ROLE_ADMIN']) || empty($subject); //admin can edit. otherwise, only if field is empty it can be edited
case self::ACCESS['user_allowed_4_profile_editor_or_self_user_if_only_empty']:
return $this->canEditIfRoleProfileEditorOrSelfUserIfEmpty($token, $subject);
case self::ACCESS['user_edit_mobile_num_if_only_empty']:
return ($this->decisionManager->decide($token, ['ROLE_VEHICLES_ADMIN']) && empty($subject))
|| ($this->decisionManager->decide($token, ['ROLE_PROFILES_ADMIN']) && empty($subject)); //vehicles admin and profiles admin can edit only if field is empty
}
throw new \LogicException('This code should not be reached!');
}
/**
* allow if
* 1- the user has ROLE_PROFILES_EDITOR role
* 2- or he is editing his own info if the field is empty
*/
private function canEditIfRoleProfileEditorOrSelfUserIfEmpty($token, $subject)
{
if ($this->decisionManager->decide($token, ['ROLE_PROFILES_EDITOR'])) {
return true;
}else if($subject['user']->getUserId() == $token->getUser()->getUserId()
&& empty($subject['subject']) ){
// echo "caused by form :". $subject['user']->getUserId() . ':'. $token->getUser()->getUserId();
return true;
}
// die("DIED".$subject['subject']);
return false;
}
}