<?php
namespace App\Component\ViewLayer;
use App\Twig\ViewLayerGlobal;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Class ViewLayerService
* @package App\Component\ViewLayer
*/
final class ViewLayerService implements EventSubscriberInterface
{
/**
* @var ViewLayerGlobal
*/
protected ViewLayerGlobal $global;
/**
* @var array|AbstractViewHandler[]
*/
protected array $handlers = [];
/**
* @param ViewLayerGlobal $global
*/
public function __construct(ViewLayerGlobal $global)
{
$this->global = $global;
}
/**
* @param AbstractViewHandler $handler
* @return $this
*/
public function registerHandler(AbstractViewHandler $handler): self
{
if ( ! in_array($handler, $this->handlers, true)) {
$this->handlers[] = $handler;
}
return $this;
}
/**
* @param AbstractView $view
* @return AbstractViewHandler
*/
protected function determineHandler(AbstractView $view): AbstractViewHandler
{
foreach ($this->handlers as $handler) {
if ($handler->supports($view)) {
return $handler;
}
}
throw new \Exception();
}
/**
* {@inheritDoc}
*/
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => [
['onKernelView', PHP_INT_MIN],
],
];
}
/**
* @param AbstractView $view
* @param Request|null $request
* @return Response
*/
public function handle(AbstractView $view, ?Request $request = null): Response
{
// set up the globals
$this->global->setup($view);
// attach the request
if ($request) {
$view->setRequest($request);
}
if ( ! $view->getRequest()) {
throw new \Exception();
}
// find the handler for this type
$handler = $this->determineHandler($view);
// do prepare
$handler->prepare($view);
// handle the view
$content = $handler->handle($view);
// generate the content for the response and finish the response
$view->getResponse()
->setContent($content);
$view->getResponse()->headers->add([
'Content-Type' => $view->getHttpContentType(),
]);
// finalize
$handler->finalize($view);
// clear the globals
$this->global->dismantle();
return $view->getResponse();
}
/**
* @param ViewEvent $event
*/
public function onKernelView(ViewEvent $event): void
{
// obtain the view
$view = $event->getControllerResult();
// make sure it is of proper type, return early if not there is nothing to do
if ( ! $view instanceof AbstractView) {
return;
}
// set the response on the event
$event->setResponse($this->handle(
$view,
$event->getRequest()
));
}
}