src/Security/Voter/BuildingVoter.php line 12

Open in your IDE?
  1. <?php
  2. namespace App\Security\Voter;
  3. use App\Entity\Building\Building;
  4. use App\Entity\User;
  5. use Doctrine\ORM\EntityManagerInterface;
  6. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  7. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  8. use Symfony\Component\Security\Core\Security;
  9. class BuildingVoter extends Voter
  10. {
  11. // these strings are just invented: you can use anything
  12. const VIEW = 'view';
  13. const EDIT = 'edit';
  14. const DELETE = 'delete';
  15. /**
  16. * @var Security
  17. */
  18. private Security $security;
  19. /**
  20. * @var EntityManagerInterface
  21. */
  22. private EntityManagerInterface $entityManager;
  23. public function __construct(Security $security, EntityManagerInterface $entityManager)
  24. {
  25. $this->security = $security;
  26. $this->entityManager = $entityManager;
  27. }
  28. protected function supports(string $attribute, $subject): bool
  29. {
  30. // if the attribute isn't one we support, return false
  31. if (!in_array($attribute, [self::VIEW, self::EDIT, self::DELETE], true)) {
  32. return false;
  33. }
  34. // only vote on `Building` objects
  35. if (!$subject instanceof Building) {
  36. return false;
  37. }
  38. return true;
  39. }
  40. protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
  41. {
  42. $loggedUser = $token->getUser();
  43. if (!$loggedUser instanceof User) {
  44. // the user must be logged in; if not, deny access
  45. return false;
  46. }
  47. // you know $subject is a Post object, thanks to `supports()`
  48. /** @var Building $targetBuilding */
  49. $targetBuilding = $subject;
  50. switch ($attribute) {
  51. case self::VIEW:
  52. return $this->canSee($targetBuilding, $loggedUser);
  53. case self::EDIT:
  54. case self::DELETE:
  55. return $this->canDealWith($targetBuilding, $loggedUser);
  56. }
  57. throw new \LogicException('This code should not be reached!');
  58. }
  59. /**
  60. * @param Building $targetBuilding
  61. * @param User $loggedUser
  62. * @return bool
  63. */
  64. private function canDealWith(Building $targetBuilding, User $loggedUser): bool
  65. {
  66. if ($this->canSee($targetBuilding, $loggedUser) && $this->security->isGranted('ROLE_CAN_EDIT_BUILDING')) {
  67. return true;
  68. }
  69. return false;
  70. }
  71. /**
  72. * @param Building $targetBuilding
  73. * @param User $loggedUser
  74. * @return bool
  75. */
  76. private function canSee(Building $targetBuilding, User $loggedUser): bool
  77. {
  78. // sanity check (different client than logged user client)
  79. if ($targetBuilding->getClient()->getId() !== $loggedUser->getClient()->getId()) {
  80. return false;
  81. }
  82. // after sanity check - this building is from logged user client
  83. if ($this->security->isGranted('ROLE_CAN_SEE_ALL_BUILDINGS')) {
  84. return true;
  85. }
  86. foreach ($loggedUser->getBuildings() as $building) {
  87. if ($building->getId() === $targetBuilding->getId()) {
  88. return true;
  89. }
  90. }
  91. return false;
  92. }
  93. }