<?php
namespace App\Security\Voter;
use App\Entity\Authorization;
use App\Entity\RealEstate;
use App\Entity\User;
use App\Repository\ContractRepository;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
class RealEstateVoter extends Voter
{
public const CREATE = 'CAN_CREATE';
public const READ = 'CAN_READ';
public const EDIT = 'CAN_EDIT';
public const DELETE = 'CAN_DELETE';
private Security $security;
private ContractRepository $contractRepository;
public function __construct(Security $security, ContractRepository $contractRepository)
{
$this->security = $security;
$this->contractRepository = $contractRepository;
}
protected function supports($attribute, $subject): bool
{
$supportsAttribute = in_array($attribute, [self::CREATE, self::DELETE, self::EDIT, self::READ]);
$supportsSubject = $subject instanceof RealEstate;
return $supportsAttribute && $supportsSubject;
}
/**
* @param mixed $subject
*/
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $this->security->getUser();
if (!$user) {
return false;
}
switch ($attribute) {
case self::CREATE:
return $this->canCreate($subject, $user);
case self::READ:
return $this->canRead($subject, $user);
case self::EDIT:
return $this->canEdit($subject, $user);
case self::DELETE:
return $this->canDelete($subject, $user);
}
return false;
}
private function canCreate(RealEstate $realEstate, User $user): bool
{
if ($this->security->isGranted(Authorization::ROLE_ADMIN)
|| $this->security->isGranted(Authorization::ROLE_OWNER_ADMIN)
) {
return true;
}
return false;
}
private function canRead(RealEstate $realEstate, User $user): bool
{
if ($this->security->isGranted(Authorization::ROLE_ADMIN)) {
return true;
}
// shortcut for all owner
if ($this->security->isGranted(Authorization::ROLE_OWNER_REQUESTER)
&& $user->getCompany()->getId() === $realEstate->getCompany()->getId()) {
// as admin of the owner with same company... all is good :-)
if ($this->security->isGranted(Authorization::ROLE_OWNER_ADMIN)) {
return true;
}
// others owners role
foreach ($user->getGroups() as $userGroup) {
foreach ($realEstate->getGroups() as $realEstateGroup) {
if ($userGroup->getGroup()->getId() === $realEstateGroup->getGroup()->getId()) {
return true;
}
}
}
return false;
}
// in all other case, we must check if the realEstate is in the list of InterventionRequest
// TODO: query for checking if realestate is granted
if ($this->security->isGranted(Authorization::ROLE_SERVICE_PROVIDER)) {
return $this->contractRepository->isValidForCompanyAndRealEstate($user->getCompany()->getId(), $realEstate->getId());
}
return false;
}
/**
* Only owner can edit,
* as owner admin, we need the same company
* as simple owner, the real estate must be in the list of our realestate.
*/
private function canEdit(RealEstate $realEstate, User $user): bool
{
if ($this->security->isGranted(Authorization::ROLE_ADMIN)) {
return true;
}
// as a owner,we must at least have the same company of the realEstate
if ($user->getCompany()->getId() !== $realEstate->getCompany()->getId()) {
return false;
}
// as admin of the owner with same company... all is good :-)
if ($this->security->isGranted(Authorization::ROLE_OWNER_ADMIN)) {
return true;
}
// allow only owners
if (!$this->security->isGranted(Authorization::ROLE_OWNER)) {
return false;
}
// others owners role
foreach ($user->getGroups() as $userGroup) {
foreach ($realEstate->getGroups() as $realEstateGroup) {
if ($userGroup->getGroup()->getId() === $realEstateGroup->getGroup()->getId()) {
return true;
}
}
}
return false;
}
private function canDelete(RealEstate $realEstate, User $user): bool
{
if ($this->security->isGranted(Authorization::ROLE_ADMIN)) {
return true;
}
return false;
}
}