<?php
/*
* This file is part of the drosalys/api-bundle package.
*
* (c) Benjamin Georgeault
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drosalys\Bundle\ApiBundle\EventSubscriber;
use Drosalys\Bundle\ApiBundle\Action\Action;
use Drosalys\Bundle\ApiBundle\Action\Info\EventInfo;
use Drosalys\Bundle\ApiBundle\Event\AbstractViewEvent;
use Drosalys\Bundle\ApiBundle\Event\PostPersistEvent;
use Drosalys\Bundle\ApiBundle\Event\PostBuildResponseEvent;
use Drosalys\Bundle\ApiBundle\Event\PrePersistEvent;
use Drosalys\Bundle\ApiBundle\Event\PreBuildResponseEvent;
use Drosalys\Bundle\ApiBundle\Event\ReplaceBuildResponseEvent;
use Drosalys\Bundle\ApiBundle\Event\ReplacePersistEvent;
use Drosalys\Bundle\ApiBundle\Persister\PersisterHandler\PersisterHandlerInterface;
use Drosalys\Bundle\ApiBundle\Request\ActionRequestTrait;
use Drosalys\Bundle\ApiBundle\Response\ResponseHandler\ResponseHandlerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
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 ActionResponseSubscriber
*
* @author Benjamin Georgeault
*/
class ActionResponseSubscriber implements EventSubscriberInterface
{
use ActionRequestTrait;
/**
* ActionResponseSubscriber constructor.
* @param ResponseHandlerInterface[] $responseHandlers
* @param PersisterHandlerInterface[] $persisterHandlers
*/
public function __construct(
private EventDispatcherInterface $dispatcher,
private iterable $responseHandlers,
private iterable $persisterHandlers,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ['__invoke', 63],
];
}
public function __invoke(ViewEvent $event): void
{
if (null === $action = $this->retrieveActionFromRequest($request = $event->getRequest())) {
return;
}
$this->applyPersister($action, $request, $data = $event->getControllerResult());
if (null !== $response = $this->buildResponse($action, $request, $data)) {
$event->setResponse($response);
}
}
private function buildResponse(Action $action, Request $request, mixed $data): ?Response
{
if ((null !== $info = $action->getBuildResponseInfo()) && ($info->hasReplace())) {
return ($info->getReplace())(new ReplaceBuildResponseEvent($action, $request, $data));
}
foreach ($this->responseHandlers as $handler) {
if ($handler->support($action, $request, $data)) {
if ((null !== $info = $action->getBuildResponseInfo()) && ($info->hasPre())) {
($info->getPre())(new PreBuildResponseEvent($action, $request, $data));
}
$this->dispatcher->dispatch(new PreBuildResponseEvent($action, $request, $data));
$response = $handler->buildResponse($action, $request, $data);
if ((null !== $info) && ($info->hasPost())) {
($info->getPost())(new PostBuildResponseEvent($action, $request, $data, $response));
}
$this->dispatcher->dispatch(new PostBuildResponseEvent($action, $request, $data, $response));
return $response;
}
}
return null;
}
private function applyPersister(Action $action, Request $request, mixed $data): void
{
if ($request->attributes->has(DeserializeActionControllerSubscriber::REQUEST_ERROR_KEY)) {
return;
}
if ((null !== $info = $action->getPersistInfo()) && ($info->hasReplace())) {
($info->getReplace())(new ReplacePersistEvent($action, $request, $data));
return;
}
if (null === $action->getDeserializeInfo() && $action->getMethod() !== 'DELETE') {
return;
}
foreach ($this->persisterHandlers as $handler) {
if ($handler->support($action, $request, $data)) {
if ((null !== $info) && ($info->hasPre())) {
($info->getPre())(new PrePersistEvent($action, $request, $data));
}
$this->dispatcher->dispatch(new PrePersistEvent($action, $request, $data));
$handler->persist($action, $request, $data);
if ((null !== $info) && ($info->hasPost())) {
($info->getPost())(new PostPersistEvent($action, $request, $data));
}
$this->dispatcher->dispatch(new PostPersistEvent($action, $request, $data));
break;
}
}
}
}