src/Security/Voter/ProcesVervalVoter.php line 11

Open in your IDE?
  1. <?php
  2. namespace App\Security\Voter;
  3. use App\Entity\ProcesVerval;
  4. use App\Entity\User;
  5. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  6. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  7. use Symfony\Component\Security\Core\Security;
  8. class ProcesVervalVoter extends Voter
  9. {
  10.     const VIEW 'view';
  11.     const EDIT 'edit';
  12.     const DELETE 'delete';
  13.     private Security $security;
  14.     public function __construct(Security $security)
  15.     {
  16.         $this->security $security;
  17.     }
  18.     protected function supports(string $attribute$subject): bool
  19.     {
  20.         return in_array($attribute, [self::VIEWself::EDITself::DELETE])
  21.             && $subject instanceof ProcesVerval;
  22.     }
  23.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  24.     {
  25.         $user $token->getUser();
  26.         // User must be logged in
  27.         if (!$user instanceof User) {
  28.             return false;
  29.         }
  30.         // Admin can do everything
  31.         if ($this->security->isGranted('ROLE_ADMIN')) {
  32.             return true;
  33.         }
  34.         /** @var ProcesVerval $procesVerval */
  35.         $procesVerval $subject;
  36.         switch ($attribute) {
  37.             case self::VIEW:
  38.                 return $this->canView($procesVerval$user);
  39.             case self::EDIT:
  40.                 return $this->canEdit($procesVerval$user);
  41.             case self::DELETE:
  42.                 return $this->canDelete($procesVerval$user);
  43.         }
  44.         return false;
  45.     }
  46.     /**
  47.      * User can view if:
  48.      * - They are the owner (created the PV)
  49.      * - They belong to the same client organization
  50.      * - Legacy mode: PV has no owner set (created before migration)
  51.      */
  52.     private function canView(ProcesVerval $procesVervalUser $user): bool
  53.     {
  54.         // Legacy mode: if PV has no user/client set, allow access
  55.         // This handles records created before the migration was run
  56.         if ($procesVerval->getUser() === null && $procesVerval->getClient() === null) {
  57.             return true;
  58.         }
  59.         // Owner can always view
  60.         if ($procesVerval->getUser() === $user) {
  61.             return true;
  62.         }
  63.         // User from same client can view
  64.         $pvClient $procesVerval->getClient();
  65.         $userClient $user->getClient();
  66.         if ($pvClient !== null && $userClient !== null && $pvClient === $userClient) {
  67.             return true;
  68.         }
  69.         return false;
  70.     }
  71.     /**
  72.      * User can edit if:
  73.      * - They can view it
  74.      * - The PV is editable (draft or in_progress)
  75.      */
  76.     private function canEdit(ProcesVerval $procesVervalUser $user): bool
  77.     {
  78.         // Must be able to view first
  79.         if (!$this->canView($procesVerval$user)) {
  80.             return false;
  81.         }
  82.         // PV must be editable (not completed)
  83.         return $procesVerval->isEditable();
  84.     }
  85.     /**
  86.      * User can delete if:
  87.      * - They are the owner (or legacy mode: no owner set)
  88.      * - The PV is not completed
  89.      */
  90.     private function canDelete(ProcesVerval $procesVervalUser $user): bool
  91.     {
  92.         // Legacy mode: if PV has no owner, allow delete
  93.         $pvUser $procesVerval->getUser();
  94.         if ($pvUser !== null && $pvUser !== $user) {
  95.             return false;
  96.         }
  97.         // Can't delete completed PVs
  98.         return $procesVerval->isEditable();
  99.     }
  100. }