<?php
namespace App\Security\Voter;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class UserVoter extends Voter
{
// these strings are just invented: you can use anything
const LIST = 'list';
const VIEW = 'view';
const EDIT = 'edit';
const ADD = 'add';
const DELETE = 'delete';
protected function supports($attribute, $subject)
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, [self::LIST, self::VIEW, self::EDIT, self::ADD, self::DELETE])) {
return false;
}
// list and add have no subject, so subject cannot be passed
if ($attribute === self::LIST || $attribute === self::ADD) {
return true;
}
// only vote on User objects inside this voter
if (!$subject instanceof User) {
return false;
}
return true;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof User) {
// the user must be logged in; if not, deny access
return false;
}
// you know $subject is a User object, thanks to supports
/** @var User $user */
$userSubject = $subject;
switch ($attribute) {
case self::LIST:
return $this->canList($user);
case self::VIEW:
return $this->canView($userSubject, $user);
case self::ADD:
return $this->canAdd($user);
case self::EDIT:
return $this->canEdit($userSubject, $user);
case self::DELETE:
return $this->canDelete($userSubject, $user);
}
throw new \LogicException('This code should not be reached!');
}
private function canView(User $userSubject, User $user)
{
// if they can edit, they can view
if ($this->canEdit($userSubject, $user)) {
return true;
}
// user can edit self
if ($userSubject->getId() === $user->getId()) {
return true;
}
// admin can edit
if ($user->getIsAdmin() === true) {
return true;
}
return false;
}
private function canEdit(User $userSubject, User $user)
{
// user can edit self
if ($userSubject->getId() === $user->getId()) {
return true;
}
// admin can edit
if ($user->getIsAdmin() === true) {
return true;
}
return false;
}
private function canAdd(User $user)
{
// for now only an Admin can create users
return $user->getIsAdmin();
}
private function canDelete(User $userSubject, User $user)
{
// for now deleting is the same as editing with the exception that a user cannot delete self
if ($userSubject->getId() === $user->getId()) {
return false;
}
return $this->canEdit($userSubject, $user);
}
private function canList(User $user)
{
// only users with isViewer rights can list users
return $user->getIsViewer();
}
}