- <?php
- declare(strict_types=1);
- namespace Slivki\EventSubscriber;
- use Psr\Log\LoggerInterface;
- use Slivki\Controller\Admin\BePaid\ValidateBePaidCredentialsAction;
- use Slivki\Controller\Api\GiftSubscription\CancelSubscriptionAction;
- use Slivki\Controller\Api\OnlineOrder\Vendor\GetNearestTimeAction;
- use Slivki\Controller\Api\Profile\Balance\BalanceTransferAction;
- use Slivki\Controller\Api\Profile\VirtualWallet\TransferSlivkiPayBalanceAction;
- use Slivki\Controller\MobileApi\V2\GiftCertificate\RefundGiftCertificateAction;
- use Slivki\Controller\Payment\Click\CompletePaymentAction;
- use Slivki\Controller\Payment\Click\PreparePaymentAction;
- use Slivki\Controller\Payment\Oplati\GetStatusOplatiTransactionAction;
- use Slivki\Controller\Subscription\GetChildSubscribersAction;
- use Slivki\Controller\Subscription\ShareSubscriptionAction;
- use Symfony\Component\HttpFoundation\JsonResponse;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\HttpKernel\Event\ExceptionEvent;
- use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
- use Symfony\Component\Messenger\Exception\HandlerFailedException;
- use Throwable;
- use function json_decode;
- use function array_filter;
- use function count;
- use function json_last_error;
- final class ExceptionListener
- {
-     private const API_NAMESPACES_START = [
-         'Api\V2',
-         'UserController::loginAction',
-         'Api\Partner',
-         'Api\Coupon',
-         'Api\Scheduler',
-         'Admin\Api',
-         'OnlineOrder\GiftCertificate\EditGiftCertificateOnlineOrderAction',
-         'MobileApi\Partner',
-         'Api\OnlineOrder\Payment\Method',
-         ValidateBePaidCredentialsAction::class,
-         GetNearestTimeAction::class,
-         ShareSubscriptionAction::class,
-         GetChildSubscribersAction::class,
-         PreparePaymentAction::class,
-         CompletePaymentAction::class,
-         GetStatusOplatiTransactionAction::class,
-         CancelSubscriptionAction::class,
-         BalanceTransferAction::class,
-         TransferSlivkiPayBalanceAction::class,
-         RefundGiftCertificateAction::class,
-     ];
-     private LoggerInterface $logger;
-     public function __construct(LoggerInterface $logger)
-     {
-         $this->logger = $logger;
-     }
-     public function onKernelException(ExceptionEvent $event): void
-     {
-         $exception = $this->getException($event->getThrowable());
-         $exceptionMessage = $exception->getMessage();
-         $controller = $event->getRequest()->attributes->get('_controller');
-         if (null !== $controller && $this->isIncludedToRoute($controller)) {
-             json_decode($exceptionMessage, true);
-             $isJson = json_last_error() === JSON_ERROR_NONE;
-             $this->logger->error(
-                 'Exception occurred in controller',
-                 [
-                     'exception' => $exception,
-                     'isJson' => $isJson,
-                     'controller' => $controller,
-                 ]
-             );
-             $response = new JsonResponse(
-                 $isJson ? $exceptionMessage : ['error' => $exceptionMessage],
-                 $exception->getCode() !== 0 ? $exception->getCode() : Response::HTTP_INTERNAL_SERVER_ERROR,
-                 [],
-                 $isJson
-             );
-             if ($exception instanceof HttpExceptionInterface) {
-                 $response->setStatusCode($exception->getStatusCode());
-                 $response->headers->replace($exception->getHeaders());
-             }
-             $event->setResponse($response);
-         }
-     }
-     private function isIncludedToRoute(string $controller): bool
-     {
-         $matches = array_filter(
-             self::API_NAMESPACES_START,
-             static fn(string $needle): bool => strpos($controller, $needle) !== false,
-         );
-         return count($matches) > 0;
-     }
-     private function getException(Throwable $exception): Throwable
-     {
-         return $exception instanceof HandlerFailedException
-             ? $this->getException($exception->getPrevious())
-             : $exception;
-     }
- }
-