<?php
namespace App\Security;
use App\Entity\ApiUser;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
class UserVoter extends Voter
{
// these strings are just invented: you can use anything
const VIEW = 'view';
const EDIT = 'edit';
private $decisionManager;
/**
* UserVoter constructor.
* @param AccessDecisionManagerInterface $decisionManager
*/
public function __construct(AccessDecisionManagerInterface $decisionManager)
{
$this->decisionManager = $decisionManager;
}
/**
* @param string $attribute
* @param mixed $subject
* @return bool
*/
protected function supports($attribute, $subject)
{
// if the attribute isn't one we support, return false
if (!in_array(
$attribute,
array(
self::VIEW,
self::EDIT,
)
)) {
return false;
}
// only vote on User objects inside this voter
if (!$subject instanceof ApiUser) {
return false;
}
return true;
}
/**
* @param string $attribute
* @param mixed $subject
* @param TokenInterface $token
* @return bool
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof ApiUser) {
// the user must be logged in; if not, deny access
return false;
}
// ROLE_SUPER_ADMIN can do anything! The power!
if ($this->decisionManager->decide(
$token,
array('ROLE_ADMIN')
)) {
return true;
}
// you know $subject is a User object, thanks to supports
/** @var ApiUser $userSubject */
$userSubject = $subject;
switch ($attribute) {
case self::VIEW:
return $this->canView(
$userSubject,
$user
);
case self::EDIT:
return $this->canEdit(
$userSubject,
$user
);
}
throw new \LogicException('This code should not be reached!');
}
/**
* @param ApiUser $userSubject
* @param ApiUser $user
* @return bool
*/
private function canView(ApiUser $userSubject, ApiUser $user)
{
// if they can edit, they can view
if ($this->canEdit(
$userSubject,
$user
)) {
return true;
}
// the User object could have, for example, a method isPrivate()
// that checks a boolean $private property
return $user === $userSubject;
}
/**
* @param ApiUser $userSubject
* @param ApiUser $user
* @return bool
*/
private function canEdit(ApiUser $userSubject, ApiUser $user)
{
// this assumes that the data object has a getOwner() method
// to get the entity of the user who owns this data object
return $user === $userSubject;
}
}