custom/plugins/CkoShopware6/src/Subscriber/PaymentBeforeSendResponseEventSubscriber.php line 56

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Cko\Shopware6\Subscriber;
  3. use Cko\Shopware6\Helper\RequestUtil;
  4. use Cko\Shopware6\Service\Order\AbstractOrderService;
  5. use Cko\Shopware6\Service\Order\OrderService;
  6. use Exception;
  7. use Psr\Log\LoggerInterface;
  8. use Shopware\Core\Framework\Context;
  9. use Shopware\Core\Framework\Event\BeforeSendResponseEvent;
  10. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  11. use Shopware\Core\PlatformRequest;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Component\HttpFoundation\JsonResponse;
  14. use Symfony\Component\HttpFoundation\RedirectResponse;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  17. use Symfony\Component\Routing\RouterInterface;
  18. use Throwable;
  19. class PaymentBeforeSendResponseEventSubscriber implements EventSubscriberInterface
  20. {
  21.     private RouterInterface $router;
  22.     private LoggerInterface $logger;
  23.     private AbstractOrderService $orderService;
  24.     public function __construct(RouterInterface $routerLoggerInterface $loggerAbstractOrderService $orderService)
  25.     {
  26.         $this->router $router;
  27.         $this->logger $logger;
  28.         $this->orderService $orderService;
  29.     }
  30.     public static function getSubscribedEvents(): array
  31.     {
  32.         return [
  33.             BeforeSendResponseEvent::class => 'onBeforeSendResponse',
  34.         ];
  35.     }
  36.     /**
  37.      * Because there are some payment methods required to be sent as an AJAX request,
  38.      * and expect to receive a JsonResponse, we need to convert all responses to JsonResponse,
  39.      * so these payment method handlers will get the payment status (Success/Failure)
  40.      * and handle it on Storefront.
  41.      * Payment Methods:
  42.      *  - Apple Pay
  43.      *  - Google Pay
  44.      *  - ...
  45.      *  All these payment methods need to send a `json` key value to the backend,
  46.      *  so it can be later converted to a JsonResponse
  47.      */
  48.     public function onBeforeSendResponse(BeforeSendResponseEvent $event): void
  49.     {
  50.         $request $event->getRequest();
  51.         $paymentData $this->getPaymentData($request);
  52.         if (!$paymentData instanceof RequestDataBag) {
  53.             return;
  54.         }
  55.         try {
  56.             $orderId $this->getOrderIdFromRequest($request);
  57.             $context $request->attributes->get(PlatformRequest::ATTRIBUTE_CONTEXT_OBJECT);
  58.             if (!$context instanceof Context) {
  59.                 throw new Exception('Missing context when process convert response');
  60.             }
  61.             $order $this->orderService->getOrder($context$orderId);
  62.             $checkoutOrderCustomFields OrderService::getCheckoutOrderCustomFields($order);
  63.             if (!empty($checkoutOrderCustomFields->getCheckoutPaymentId())) {
  64.                 $response $event->getResponse();
  65.                 // If the checkout.com payment ID is set and the response is a redirect
  66.                 // it means that the payment was successful,
  67.                 // so we can get the redirect URL from the response
  68.                 if ($response instanceof RedirectResponse) {
  69.                     $event->setResponse(new JsonResponse([
  70.                         'success' => true,
  71.                         'redirectUrl' => $response->getTargetUrl(),
  72.                     ]));
  73.                     return;
  74.                 }
  75.             }
  76.             $event->setResponse(new JsonResponse([
  77.                 'success' => false,
  78.                 'redirectUrl' => $this->generateUrl('frontend.checkout.finish.page', [
  79.                     'orderId' => $orderId,
  80.                     'changedPayment' => false,
  81.                     'paymentFailed' => true,
  82.                 ]),
  83.             ]));
  84.         } catch (Throwable $e) {
  85.             $this->logger->critical('Unknown error when trying to process convert response', [
  86.                 'paymentData' => $paymentData,
  87.                 'error' => $e->getMessage(),
  88.             ]);
  89.             $event->setResponse(new JsonResponse([
  90.                 'success' => false,
  91.                 'redirectUrl' => $this->generateUrl('frontend.checkout.confirm.page'),
  92.             ]));
  93.         }
  94.     }
  95.     /**
  96.      * Generates a URL from the given parameters.
  97.      *
  98.      * @see UrlGeneratorInterface
  99.      */
  100.     protected function generateUrl(
  101.         string $route,
  102.         array $parameters = [],
  103.         int $referenceType UrlGeneratorInterface::ABSOLUTE_URL
  104.     ): string {
  105.         return $this->router->generate($route$parameters$referenceType);
  106.     }
  107.     /**
  108.      * Get the checkout payment data from the request.
  109.      * This data is our plugin's payment request data
  110.      */
  111.     private function getPaymentData(Request $request): ?RequestDataBag
  112.     {
  113.         $requestBag = new RequestDataBag($request->request->all());
  114.         $paymentData RequestUtil::getPaymentData($requestBag);
  115.         if (!$paymentData instanceof RequestDataBag) {
  116.             // It means that the requested data is not our plugin's request payment data
  117.             return null;
  118.         }
  119.         // Skip if the request does not need JSON response
  120.         if (!$paymentData->get(RequestUtil::DATA_JSON)) {
  121.             return null;
  122.         }
  123.         return $paymentData;
  124.     }
  125.     /**
  126.      * The order ID is coming from the request of edit-order page
  127.      * If the order ID is not found from edit-order page,
  128.      * it means the order ID is created by Shopware Core
  129.      *
  130.      * @throws Exception
  131.      */
  132.     private function getOrderIdFromRequest(Request $request): string
  133.     {
  134.         // Get order ID from the request
  135.         // This case happens for the edit order page
  136.         $orderId $request->get('orderId');
  137.         // In case of create order (empty edit order ID), It needs to get the last order ID
  138.         // This order ID is created by the Shopware Core
  139.         $orderId $orderId ?? $this->orderService->getRequestLastOrderId();
  140.         // The order was not created, return the checkout confirmation page
  141.         if (empty($orderId)) {
  142.             throw new Exception('The order was not created');
  143.         }
  144.         return $orderId;
  145.     }
  146. }