src/EventListener/KernelEventListener.php line 72

  1. <?php
  2. namespace App\EventListener;
  3. use App\Entity\Channel;
  4. use App\Entity\Shop\Shop;
  5. use App\Entity\User;
  6. use App\Filter\ChannelFilter;
  7. use App\Helper\ApiMarker;
  8. use App\PortoContainers\Zapier\Helper\ZapierRequestMarker;
  9. use App\Service\ChannelService;
  10. use App\Service\Logger\RequestLoggerService;
  11. use App\ViewHandler\FormatterHandler;
  12. use Doctrine\ORM\EntityManagerInterface;
  13. use Exception;
  14. use Symfony\Component\HttpFoundation\Request;
  15. use Symfony\Component\HttpFoundation\Response;
  16. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  17. use Symfony\Component\HttpKernel\Event\RequestEvent;
  18. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  19. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  20. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  21. use Symfony\Component\Security\Core\User\UserInterface;
  22. use App\PortoContainers\Zapier\Actions\IsApiRequestForZapierAction;
  23. use App\PortoContainers\Zapier\Actions\ValidateApiKeyInRequestAction;
  24. use App\PortoContainers\Global\DTO\RequestData;
  25. class KernelEventListener
  26. {
  27.     /**
  28.      * @param RequestLoggerService $loggerService
  29.      * @param FormatterHandler $formatterHandler
  30.      * @param TokenStorageInterface $tokenStorage
  31.      * @param ChannelService $channelService
  32.      * @param EntityManagerInterface $em
  33.      * @param IsApiRequestForZapierAction $isApiRequestForZapierAction
  34.      * @param ValidateApiKeyInRequestAction $validateApiKeyInRequestAction
  35.      */
  36.     public function __construct(
  37.         private readonly RequestLoggerService          $loggerService,
  38.         private readonly FormatterHandler              $formatterHandler,
  39.         private readonly TokenStorageInterface         $tokenStorage,
  40.         private readonly ChannelService                $channelService,
  41.         private readonly EntityManagerInterface        $em,
  42.         private readonly IsApiRequestForZapierAction   $isApiRequestForZapierAction,
  43.         private readonly ValidateApiKeyInRequestAction $validateApiKeyInRequestAction
  44.     )
  45.     {
  46.     }
  47.     /**
  48.      * @param RequestEvent $event
  49.      */
  50.     public function onKernelRequest(RequestEvent $event): void
  51.     {
  52.         if (ApiMarker::isApiRequest()) {
  53.             $this->convertApiJsonRequest($event);
  54.         } elseif ($this->isApiRequestForZapierAction->run(
  55.             $requestData = new RequestData($event->getRequest())
  56.         )) {
  57.             $this->validateApiKeyInRequestAction->run($requestData);
  58.         } elseif ($this->getUser() instanceof UserInterface) {
  59.             $this->checkCustomerShopToken($event->getRequest());
  60.         }
  61.     }
  62.     /**
  63.      * @param ResponseEvent $event
  64.      *
  65.      * @throws Exception
  66.      */
  67.     public function onKernelResponse(ResponseEvent $event): void
  68.     {
  69.         if (ApiMarker::isApiRequest() || ZapierRequestMarker::isRequest()) {
  70.             $this->logApiResponse($event);
  71.         }
  72.     }
  73.     /**
  74.      * @param ExceptionEvent $event
  75.      * @return void
  76.      */
  77.     public function onKernelException(ExceptionEvent $event): void
  78.     {
  79.         if (ApiMarker::isApiRequest() || ZapierRequestMarker::isRequest()) {
  80.             $this->formatExceptionResponse($event);
  81.         }
  82.     }
  83.     /**
  84.      * @param RequestEvent $event
  85.      * @return void
  86.      */
  87.     private function convertApiJsonRequest(RequestEvent $event): void
  88.     {
  89.         $request $event->getRequest();
  90.         if (=== strpos($request->headers->get('content-type'), 'application/json')) {
  91.             $data json_decode($request->getContent(), true);
  92.             $request->request->replace(is_array($data) ? $data : []);
  93.         }
  94.     }
  95.     /**
  96.      * @param ResponseEvent $event
  97.      *
  98.      * @throws Exception
  99.      */
  100.     private function logApiResponse(ResponseEvent $event): void
  101.     {
  102.         $this->loggerService->addLog($event);
  103.         //try {
  104.         //    $this->loggerService->addLog($event);
  105.         //} catch (Exception $ex) {
  106.         //    # TODO send log to telegram
  107.         //}
  108.     }
  109.     /**
  110.      * @param ExceptionEvent $event
  111.      */
  112.     private function formatExceptionResponse(ExceptionEvent $event): void
  113.     {
  114.         $exception $event->getThrowable();
  115.         if ($exception instanceof HttpExceptionInterface) {
  116.             $status $exception->getStatusCode();
  117.         } else {
  118.             $status $exception->getCode() ?: Response::HTTP_BAD_REQUEST;
  119.         }
  120.         $event->setResponse($this->formatterHandler->createResponse($exception$status));
  121.     }
  122.     /**
  123.      * @return User|null
  124.      */
  125.     private function getUser(): ?UserInterface
  126.     {
  127.         $user $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
  128.         return $user instanceof UserInterface $user null;
  129.     }
  130.     /**
  131.      * @param Request $request
  132.      */
  133.     private function checkCustomerShopToken(Request $request): void
  134.     {
  135.         /** @var ChannelFilter $filter */
  136.         $filters $this->em->getFilters();
  137.         $filter $filters->getFilter('channelable');
  138.         $channel $this->channelService->getCustomerChannel($this->getUser());
  139.         if ($channel instanceof Channel) {
  140.             $request->headers->set('authorization''bearer ' $channel->getToken());
  141.             /**
  142.              * Parameter is setting for making queries unique,
  143.              * without this for client side with many shops queries will be load from previous shop
  144.              */
  145.             $filter->setParameter('shop_id'$channel->getShop()->getId());
  146.             $filter->setShop($channel->getShop());
  147.             $filter->disableForEntity(Shop::class);
  148.         } elseif ($request->getPathInfo() === '/shop/') {
  149.             $filter->setParameter('shop_id''unknown_shop');
  150.         } else {
  151.             /**
  152.              * For 'prod' environment with cache pools:
  153.              * Without this dashboard statistic won't work after switching to shop side and back
  154.              */
  155.             $filter->setParameter('shop_id''admin');
  156.         }
  157.     }
  158. }