src/Security/UserVoter.php line 11

  1. <?php
  2. namespace App\Security;
  3. use App\Entity\Users;
  4. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  5. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  6. use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use App\Service\UserHelper;
  9. class UserVoter extends Voter
  10. {
  11.     const ACCESS= [ 
  12.         'user_edit_super_critical_info' => 'user_edit_super_critical_info'//super admins only
  13.         'user_allowed_4_profile_editor'
  14.             => 'user_allowed_4_profile_editor'//super admins and profiles editor only
  15.         'user_allowed_4_profile_editor_or_self_user_if_only_empty'
  16.             => 'user_allowed_4_profile_editor_or_self_user_if_only_empty'//super admins & profiles editors. And if field is empty then also the user
  17.         'user_edit_critical_info' => 'user_edit_critical_info'//all admins
  18.         'user_edit_info_if_only_empty' => 'user_edit_info_if_only_empty',  //all admins. And if field is empty then also the user
  19.         'user_edit_mobile_num_if_only_empty'
  20.             => 'user_edit_mobile_num_if_only_empty' //super admins. and if field is empty then also vehicles admin and profiles admin
  21.         ];
  22.     /**
  23.      * @var AccessDecisionManager|null
  24.      */
  25.     protected \Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface $decisionManager;
  26.     /**
  27.      * @var EntityManager|null
  28.      */
  29.     protected \Doctrine\ORM\EntityManagerInterface $entityManager;
  30.     /**
  31.      * @var EntityManager|null
  32.      */
  33.     protected \App\Service\UserHelper $userHelper;
  34.     /**
  35.      * DelegateVoter constructor.
  36.      * @param AccessDecisionManager|null $decisionManager
  37.      * @param EntityManager|null $entityManager
  38.      */
  39.     public function __construct(AccessDecisionManagerInterface $decisionManagerEntityManagerInterface $entityManagerUserHelper $userHelper)
  40.     {
  41.         $this->decisionManager $decisionManager;
  42.         $this->entityManager $entityManager;
  43.         $this->userHelper $userHelper;
  44.     }
  45.     /**
  46.      * determines if your voter should vote on the attribute/subject combination. If you return true,
  47.      * voteOnAttribute() will be called. Otherwise, your voter is done: some other voter should process this
  48.      */
  49.     protected function supports($attribute$subject): bool
  50.     {
  51.         // if the attribute isn't one we support, return false
  52.         // only vote on Users objects inside this voter
  53.         //        if ($subject && !$subject instanceof Users) {
  54.         //            return false;
  55.         //        }
  56.         return in_array($attributeself::ACCESS);
  57.     }
  58.     /**
  59.      * If you return true from supports(), then this method is called. Your job is simple: return true to allow access
  60.      * and false to deny access
  61.      */
  62.     protected function voteOnAttribute($attribute$subjectTokenInterface $token): bool
  63.     {
  64.         $loggedinUser $token->getUser();
  65.         if (!$loggedinUser instanceof Users) {
  66.             return false// the user must be logged in; if not, deny access
  67.         }
  68.         
  69.         // ROLE_SUPER_ADMIN can do anything! The power! Calling decide() on the AccessDecisionManager is essentially the same
  70.         // as calling isGranted() from a controller or other places (it's just a little lower-level, which is necessary for a voter).
  71.         if ($this->decisionManager->decide($token, ['ROLE_SUPER_ADMIN'])) {
  72.             return true;
  73.         }
  74.         switch ($attribute) {
  75.             case self::ACCESS['user_edit_super_critical_info']:
  76.                 //no one except super admins can edit
  77.                 return false;
  78.             case self::ACCESS['user_edit_critical_info']:
  79.                 return $this->decisionManager->decide($token, ['ROLE_ADMIN']); //all admins are allowed
  80.             case self::ACCESS['user_allowed_4_profile_editor']:
  81.                 return $this->decisionManager->decide($token, ['ROLE_PROFILES_EDITOR']); //only profile editors are allowed
  82.             case self::ACCESS['user_edit_info_if_only_empty']:
  83.                 return $this->decisionManager->decide($token, ['ROLE_ADMIN']) || empty($subject); //admin can edit. otherwise, only if field is empty it can be edited
  84.             case self::ACCESS['user_allowed_4_profile_editor_or_self_user_if_only_empty']:
  85.                 return $this->canEditIfRoleProfileEditorOrSelfUserIfEmpty($token$subject);
  86.             case self::ACCESS['user_edit_mobile_num_if_only_empty']:
  87.                 return ($this->decisionManager->decide($token, ['ROLE_VEHICLES_ADMIN']) && empty($subject))
  88.                     || ($this->decisionManager->decide($token, ['ROLE_PROFILES_ADMIN']) && empty($subject)); //vehicles admin and profiles admin can edit only if field is empty
  89.         }
  90.         throw new \LogicException('This code should not be reached!');
  91.     }
  92.     /**
  93.      * allow if
  94.      * 1- the user has ROLE_PROFILES_EDITOR role
  95.      * 2- or he is editing his own info if the field is empty
  96.      */
  97.     private function canEditIfRoleProfileEditorOrSelfUserIfEmpty($token$subject)
  98.     {
  99.         if ($this->decisionManager->decide($token, ['ROLE_PROFILES_EDITOR'])) {
  100.             return true;
  101.         } elseif ($subject['user']->getUserId() == $token->getUser()->getUserId()
  102.                 && empty($subject['subject'])) {
  103.             //            echo "caused by form :". $subject['user']->getUserId() . ':'. $token->getUser()->getUserId();
  104.             return true;
  105.         }
  106. //        die("DIED".$subject['subject']);
  107.         return false;
  108.     }
  109. }