custom/plugins/RpayPayments/src/Components/Account/Subscriber/AccountSubscriber.php line 87

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * Copyright (c) Ratepay GmbH
  5.  *
  6.  * For the full copyright and license information, please view the LICENSE
  7.  * file that was distributed with this source code.
  8.  */
  9. namespace Ratepay\RpayPayments\Components\Account\Subscriber;
  10. use Ratepay\RpayPayments\Components\Account\Event\PaymentUpdateRequestBagValidatedEvent;
  11. use Ratepay\RpayPayments\Components\Checkout\Model\Extension\OrderExtension;
  12. use Ratepay\RpayPayments\Components\Checkout\Model\RatepayOrderDataEntity;
  13. use Ratepay\RpayPayments\Components\Checkout\Service\ExtensionService;
  14. use Ratepay\RpayPayments\Components\PaymentHandler\AbstractPaymentHandler;
  15. use Ratepay\RpayPayments\Components\RedirectException\Exception\ForwardException;
  16. use Ratepay\RpayPayments\Util\CriteriaHelper;
  17. use Ratepay\RpayPayments\Util\DataValidationHelper;
  18. use Ratepay\RpayPayments\Util\MethodHelper;
  19. use Ratepay\RpayPayments\Util\RequestHelper;
  20. use Shopware\Core\Checkout\Order\OrderEntity;
  21. use Shopware\Core\Checkout\Payment\Cart\PaymentHandler\PaymentHandlerRegistry;
  22. use Shopware\Core\Checkout\Payment\PaymentMethodEntity;
  23. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  24. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  25. use Shopware\Core\Framework\Struct\ArrayStruct;
  26. use Shopware\Core\Framework\Validation\DataBag\DataBag;
  27. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  28. use Shopware\Core\Framework\Validation\DataValidationDefinition;
  29. use Shopware\Core\Framework\Validation\DataValidator;
  30. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  31. use Shopware\Storefront\Event\RouteRequest\HandlePaymentMethodRouteRequestEvent;
  32. use Shopware\Storefront\Event\RouteRequest\SetPaymentOrderRouteRequestEvent;
  33. use Shopware\Storefront\Page\Account\Order\AccountEditOrderPageLoadedEvent;
  34. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  35. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  36. class AccountSubscriber implements EventSubscriberInterface
  37. {
  38.     protected ExtensionService $extensionService;
  39.     private DataValidator $dataValidator;
  40.     /**
  41.      * @var EntityRepository
  42.      * the interface has been deprecated, but shopware is using the Interface in a decorator for the repository.
  43.      * so it will crash, if we are only using EntityRepository, cause an object of the decorator got injected into the constructor.
  44.      * After Shopware has removed the decorator, we can replace this by a normal definition
  45.      * TODO remove comment on Shopware Version 6.5.0.0 & readd type hint & change constructor argument type
  46.      */
  47.     private object $paymentMethodRepository;
  48.     private PaymentHandlerRegistry $paymentHandlerRegistry;
  49.     private EntityRepository $orderRepository;
  50.     private EventDispatcherInterface $eventDispatcher;
  51.     public function __construct(
  52.         ExtensionService $extensionService,
  53.         PaymentHandlerRegistry $paymentHandlerRegistry,
  54.         object $paymentMethodRepository,
  55.         EntityRepository $orderRepository,
  56.         DataValidator $dataValidator,
  57.         EventDispatcherInterface $eventDispatcher
  58.     ) {
  59.         $this->extensionService $extensionService;
  60.         $this->dataValidator $dataValidator;
  61.         $this->paymentMethodRepository $paymentMethodRepository;
  62.         $this->paymentHandlerRegistry $paymentHandlerRegistry;
  63.         $this->orderRepository $orderRepository;
  64.         $this->eventDispatcher $eventDispatcher;
  65.     }
  66.     public static function getSubscribedEvents(): array
  67.     {
  68.         return [
  69.             AccountEditOrderPageLoadedEvent::class => ['addRatepayTemplateData'310],
  70.             HandlePaymentMethodRouteRequestEvent::class => 'onHandlePaymentMethodRouteRequest',
  71.             SetPaymentOrderRouteRequestEvent::class => 'onPaymentOrderRouteRequest',
  72.         ];
  73.     }
  74.     public function addRatepayTemplateData(AccountEditOrderPageLoadedEvent $event): void
  75.     {
  76.         $page $event->getPage();
  77.         $order $page->getOrder();
  78.         /** @var RatepayOrderDataEntity|null $ratepayData */
  79.         $ratepayData $order->getExtension(OrderExtension::EXTENSION_NAME);
  80.         if ($ratepayData && MethodHelper::isRatepayOrder($order) && $ratepayData->isSuccessful()) {
  81.             // You can't change the payment if it is a ratepay order
  82.             $page->setPaymentChangeable(false);
  83.         } else {
  84.             $order $this->orderRepository->search(CriteriaHelper::getCriteriaForOrder($order->getId()), $event->getContext())->first();
  85.             // Payment change is allowed, prepare ratepay payment data if a ratepay payment method is selected
  86.             $paymentMethod $event->getSalesChannelContext()->getPaymentMethod();
  87.             if (MethodHelper::isRatepayMethod($paymentMethod->getHandlerIdentifier()) &&
  88.                 $event->getPage()->getPaymentMethods()->has($paymentMethod->getId())
  89.             ) {
  90.                 $extension $this->extensionService->buildPaymentDataExtension(
  91.                     $event->getSalesChannelContext(),
  92.                     $order,
  93.                     $event->getRequest()
  94.                 );
  95.                 if ($extension instanceof ArrayStruct) {
  96.                     $event->getPage()->addExtension(ExtensionService::PAYMENT_PAGE_EXTENSION_NAME$extension);
  97.                 }
  98.             }
  99.         }
  100.     }
  101.     public function onHandlePaymentMethodRouteRequest(HandlePaymentMethodRouteRequestEvent $event): void
  102.     {
  103.         if ($event->getStorefrontRequest()->request->has('ratepay')) {
  104.             $event->getStoreApiRequest()->request->set(
  105.                 'ratepay',
  106.                 RequestHelper::getArrayBag($event->getStorefrontRequest(), 'ratepay')->all()
  107.             );
  108.         }
  109.     }
  110.     public function onPaymentOrderRouteRequest(SetPaymentOrderRouteRequestEvent $event): void
  111.     {
  112.         if ($event->getStorefrontRequest()->attributes->get('_route') !== 'frontend.account.edit-order.update-order') {
  113.             // make sure that this subscriber only got processed when the order got updated (e.g. switch of payment method or failed payment)
  114.             return;
  115.         }
  116.         $orderId $event->getStoreApiRequest()->get('orderId');
  117.         $orderEntity $this->orderRepository->search(CriteriaHelper::getCriteriaForOrder($orderId), $event->getContext())->first();
  118.         $paymentMethodId $event->getStoreApiRequest()->get('paymentMethodId');
  119.         $paymentMethod $this->paymentMethodRepository->search(new Criteria([$paymentMethodId]), $event->getContext())->first();
  120.         if (!$orderEntity instanceof OrderEntity ||
  121.             !$paymentMethod instanceof PaymentMethodEntity ||
  122.             !MethodHelper::isRatepayMethod($paymentMethod->getHandlerIdentifier())
  123.         ) {
  124.             // not a ratepay method - nothing to do.
  125.             return;
  126.         }
  127.         /** @var AbstractPaymentHandler $paymentHandler */
  128.         $paymentHandler $this->paymentHandlerRegistry->getPaymentMethodHandler($paymentMethod->getId());
  129.         // we need to add some functionality to validate the payment data and the response from the gateway.
  130.         // cause shopware do have the opportunity to output custom messages, we will throw an ForwardException, which
  131.         // got caught in the `RedirectException` component and will be rewritten into forward.
  132.         // we must validate the ratepay data on our own. to prevent errors with other extensions, we will only validate ratepay-data.
  133.         $requestData = new DataBag($event->getStorefrontRequest()->request->all());
  134.         $ratepayData $requestData->get('ratepay');
  135.         $validationDefinitions $paymentHandler->getValidationDefinitions($requestData$orderEntity);
  136.         $definition = new DataValidationDefinition();
  137.         $definition->addSub('ratepay'DataValidationHelper::addSubConstraints(new DataValidationDefinition(), $validationDefinitions));
  138.         try {
  139.             $this->dataValidator->validate([
  140.                 'ratepay' => $ratepayData->all(),
  141.             ], $definition);
  142.         } catch (ConstraintViolationException $constraintViolationException) {
  143.             throw new ForwardException('frontend.account.edit-order.page', [
  144.                 'orderId' => $orderEntity->getId(),
  145.             ], [
  146.                 'formViolations' => $constraintViolationException,
  147.             ], $constraintViolationException);
  148.         }
  149.         $this->eventDispatcher->dispatch(new PaymentUpdateRequestBagValidatedEvent(
  150.             $orderEntity,
  151.             $paymentHandler,
  152.             new RequestDataBag([
  153.                 'ratepay' => $ratepayData,
  154.             ]),
  155.             $event->getSalesChannelContext()
  156.         ));
  157.     }
  158. }