<?php declare(strict_types=1);
namespace App\EventListener;
use App\Annotation\Auth as AuthAnnotation;
use App\ArgumentResolver\AuthValueResolver;
use Doctrine\Common\Annotations\Reader;
use ReflectionClass;
use ReflectionException;
use RuntimeException;
use App\Tartarus;
use Symfony\Component\HttpKernel\Event\{
ControllerEvent,
ControllerArgumentsEvent
};
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
class AuthAnnotationListener {
private $annotationReader;
protected $annotation = null;
public function __construct(Reader $annotationReader) {
$this->annotationReader = $annotationReader;
}
public function onKernelController(ControllerEvent $event): void {
if (!$event->isMainRequest()) {
return;
}
$controllers = $event->getController();
if (!is_array($controllers)) {
return;
}
$this->handleAnnotation($controllers);
}
public function onKernelControllerArguments(ControllerArgumentsEvent $event): void {
if ((!$this->annotation) || (!$event->isMainRequest())) {
return;
}
$auth = null;
foreach ($event->getArguments() as $argument) {
if ($argument instanceof Tartarus\AuthInterface) {
$auth = $argument;
}
}
if (!$auth) {
$argumentResolver = new AuthValueResolver();
$auth = $argumentResolver->resolve(
$event->getRequest(),
new ArgumentMetadata('auth', Tartarus\AuthInterface::class, false, false, null)
)->current();
}
if (!$auth) {
throw new RuntimeException('Auth is required, but missing value to resolve');
}
if ($this->annotation->required) {
$auth->check();
}
return;
}
private function handleAnnotation(iterable $controllers): void {
list($controller, $methodName) = $controllers;
try {
$controllerReflection = new ReflectionClass($controller);
} catch (ReflectionException $e) {
throw new RuntimeException('Failed to read annotation');
}
$this->handleMethodAnnotation($controllerReflection, $methodName);
}
private function handleMethodAnnotation(ReflectionClass $controller, string $methodName): void {
$method = $controller->getMethod($methodName);
/* Get activity annotation */
$annotation = $this->annotationReader->getMethodAnnotation($method, AuthAnnotation::class);
if ($annotation instanceof AuthAnnotation) {
$this->annotation = $annotation;
}
}
}