src/Security/LotVoter.php line 26

Open in your IDE?
  1. <?php
  2. /**
  3.  * This file is part of Synapse.
  4.  *
  5.  * Copyright (C) 2020-2021 Daniel Ménard
  6.  *
  7.  * For copyright and license information, please view the
  8.  * LICENSE file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace App\Security;
  12. use App\Entity\Company;
  13. use App\Entity\Lot;
  14. use App\Entity\Tender;
  15. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  16. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  17. use Symfony\Component\Security\Core\User\UserInterface;
  18. /**
  19.  * LotVoter : sécurité des lots.
  20.  *
  21.  * @author Daniel Ménard <daniel.menard.35@gmail.com>
  22.  */
  23. final class LotVoter extends Voter
  24. {
  25.     /**
  26.      * L'attribut à utiliser pour déterminer si l'utilisateur peut consulter un lot.
  27.      */
  28.     public const VIEW 'view';
  29.     /**
  30.      * L'attribut à utiliser pour déterminer si l'utilisateur peut modifier un lot.
  31.      */
  32.     public const EDIT 'edit';
  33.     /**
  34.      * L'attribut à utiliser pour déterminer si l'utilisateur peut voir le budget d'un lot.
  35.      */
  36.     public const VIEW_BUDGET 'view_budget';
  37.     /**
  38.      * Liste des attributs que l'on gère.
  39.      */
  40.     private const ATTRIBUTES = [
  41.         self::VIEW => 'canView',
  42.         self::EDIT => 'canEdit',
  43.         self::VIEW_BUDGET => 'canViewBudget',
  44.     ];
  45.     /**
  46.      * {@inheritdoc}
  47.      */
  48.     final protected function supports(string $attribute$subject): bool
  49.     {
  50.         // On ne s'occupe que des objets de type Lot et des attributs qu'on connaît
  51.         return ($subject instanceof Lot) && isset(self::ATTRIBUTES[$attribute]);
  52.     }
  53.     /**
  54.      * {@inheritdoc}
  55.      */
  56.     final protected function voteOnAttribute(string $attribute$lotTokenInterface $token): bool
  57.     {
  58.         // L'utilisateur doit être connecté
  59.         $user $token->getUser();
  60.         if (!$user instanceof UserInterface) {
  61.             return false;
  62.         }
  63.         // Un administrateur a tous les droits, quelle que soit la permission demandée
  64.         if (in_array('ROLE_ADMIN', (array) $user->getRoles())) {
  65.             return true// mauvaise pratique mais isGranted ne fonctionne pas dans les tests
  66.         }
  67.         // Teste la permission demandée
  68.         $method = [$thisself::ATTRIBUTES[$attribute]];
  69.         return $method($lot$user);
  70.     }
  71.     /**
  72.      * Teste si un utilisateur peut voir un lot.
  73.      *
  74.      * Retourne true si l'une des conditions suivantes est vraie :
  75.      * - l'utilisateur est le DDO ou le GROUPE du projet dont fait partie le lot
  76.      * - l'utilisateur est le projet dont fait partie le lot (accès de la forme AOxxx)
  77.      */
  78.     final protected function canView(Lot $lotUserInterface $user): bool
  79.     {
  80.         // L'utilisateur est le DDO ou le GROUPE du projet dont fait partie le lot
  81.         if ($user instanceof Company) {
  82.             // Récupère le projet dont fait partie le lot
  83.             $tender $lot->getTender();
  84.             if (is_null($tender)) {
  85.                 return false;
  86.             }
  87.             // Ok si l'utilisateur est le DDO ou le GROUPE du projet
  88.             return $user === $tender->getDdo() || $user->getId() === $tender->getGroupId();
  89.         }
  90.         // L'utilisateur est le projet dont fait partie le lot (accès de la forme AOxxx)
  91.         if ($user instanceof Tender) {
  92.             return $user === $lot->getTender();
  93.         }
  94.         // Type d'utilisateur inconnu
  95.         return false;
  96.     }
  97.     /**
  98.      * Teste si un utilisateur peut modifier un lot.
  99.      *
  100.      * Retourne true si l'une des conditions suivantes est vraie :
  101.      * - l'utilisateur est le DDO ou le GROUPE du projet dont fait partie le lot
  102.      * - l'utilisateur est le projet dont fait partie le lot (accès de la forme AOxxx)
  103.      */
  104.     final protected function canEdit(Lot $lotUserInterface $user): bool
  105.     {
  106.         return $this->canView($lot$user);
  107.     }
  108.     /**
  109.      * Teste si un utilisateur peut voir le budget d'un lot.
  110.      *
  111.      * Retourne true si l'une des conditions suivantes est vraie :
  112.      * - l'utilisateur est le DDO ou le GROUPE du projet dont fait partie le lot
  113.      * - l'utilisateur est le projet dont fait partie le lot (accès de la forme AOxxx)
  114.      *   ET la propriété budgetIsHidden du projet est à false.
  115.      */
  116.     final protected function canViewBudget(Lot $lotUserInterface $user): bool
  117.     {
  118.         if ($user instanceof Tender) {
  119.             $tender $lot->getTender();
  120.             if (is_null($tender) || $tender->getBudgetIsHidden()) {
  121.                 return false;
  122.             }
  123.         }
  124.         return $this->canView($lot$user);
  125.     }
  126. }