<?php
namespace App\EventSubscriber;
use App\Annotation\NeedsPermission;
use App\Security\PermissionsService;
use Doctrine\Common\Annotations\Reader;
use Psr\Cache\InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
class NeedsPermissionSubscriber implements EventSubscriberInterface
{
protected $annotationReader;
protected $permissionsService;
public function __construct(Reader $annotationReader, PermissionsService $permissionsService)
{
$this->annotationReader = $annotationReader;
$this->permissionsService = $permissionsService;
}
public static function getSubscribedEvents()
{
// return the subscribed events, their methods and priorities
return [
KernelEvents::CONTROLLER => [
['checkPermission', 10],
],
];
}
/**
* @param ControllerEvent $event
* @throws InvalidArgumentException
* @throws ReflectionException
*/
public function checkPermission(ControllerEvent $event)
{
$controller = $event->getController();
if (!is_array($controller)) {
return;
}
$action = new ReflectionMethod($controller[0], $controller[1]);
$class = new ReflectionClass($controller[0]);
$annotation = $this
->annotationReader
->getMethodAnnotation($action, NeedsPermission::class);
if (!$annotation) {
$annotation = $this
->annotationReader
->getClassAnnotation($class, NeedsPermission::class);
}
if (!($annotation instanceof NeedsPermission)) {
return;
}
$permission = $annotation->permission;
$hasPermission = $this->permissionsService->check($permission);
if (!$hasPermission) {
throw new AccessDeniedHttpException();
}
}
}