<?php
namespace App\Security;
use App\Entity\Companies;
use App\Entity\Users;
use App\Entity\ClientsDelegation;
use App\Entity\VehicleClients;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Doctrine\ORM\EntityManagerInterface;
use App\Service\UserHelper;
class CompanyVoter extends Voter
{
const ACCESS= [
'company_view_summary' => 'company_view_summary',
'company_edit_info' => 'company_edit_info',
'company_docs' => 'company_docs',
'company_bank_accounts' => 'company_bank_accounts'];
/**
* @var AccessDecisionManager|null
*/
protected $decisionManager;
/**
* @var EntityManager|null
*/
protected $entityManager;
/**
* @var EntityManager|null
*/
protected $userHelper;
/**
* DelegateVoter constructor.
* @param AccessDecisionManager|null $decisionManager
* @param EntityManager|null $entityManager
*/
public function __construct(AccessDecisionManagerInterface $decisionManager, EntityManagerInterface $entityManager, UserHelper $userHelper)
{
$this->decisionManager = $decisionManager;
$this->entityManager = $entityManager;
$this->userHelper = $userHelper;
}
/**
* determines if your voter should vote on the attribute/subject combination. If you return true,
* voteOnAttribute() will be called. Otherwise, your voter is done: some other voter should process this
*/
protected function supports($attribute, $subject)
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, self::ACCESS)) {
return false;
}
// only vote on Companies objects inside this voter
if (!$subject instanceof Companies) {
return false;
}
return true;
}
/**
* If you return true from supports(), then this method is called. Your job is simple: return true to allow access
* and false to deny access
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof Users) {
return false; // the user must be logged in; if not, deny access
}
// ROLE_SUPER_ADMIN can do anything! The power! Calling decide() on the AccessDecisionManager is essentially the same
// as calling isGranted() from a controller or other places (it's just a little lower-level, which is necessary for a voter).
if ($this->decisionManager->decide($token, ['ROLE_SUPER_ADMIN'])) {
return true;
}
// you know $subject is a VehicleClient object, thanks to supports
/** @var VehicleClients $vehicleClient */
$vehicleClient = $subject;
switch ($attribute) {
case self::ACCESS['company_view_summary']:
//Admins and delegated users can view
return $this->isDelegated($vehicleClient, $user) || $this->decisionManager->decide($token, ['ROLE_ADMIN']);
case self::ACCESS['company_edit_info']:
case self::ACCESS['company_docs']:
return $this->decisionManager->decide($token, ['ROLE_ADMIN']); //only admins are allowed
case self::ACCESS['company_bank_accounts']:
return $this->isDelegated($vehicleClient, $user) || $this->decisionManager->decide($token, ['ROLE_ADMIN']);
}
throw new \LogicException('This code should not be reached!');
}
/**
*/
private function isDelegated(Companies $delegator, Users $user)
{
// $em = $this->entityManager;
// $delegations = $em->getRepository(ClientsDelegation::class)->findByDelegated($user->getUserId());
$delegations= $this->userHelper->getUserDelegators($user);
foreach($delegations as $delegation){
if($delegation->getDelegator() &&
$delegation->getDelegator()->getCompany() == $delegator){
return true;
}
}
return false;
}
/**
*/
private function canView(Post $post, User $user)
{
// if they can edit, they can view
if ($this->canEdit($post, $user)) {
return true;
}
// the Post object could have, for example, a method isPrivate()
// that checks a boolean $private property
return !$post->isPrivate();
}
}