Refactor to minimize payment requests command handlers

This commit is contained in:
Francis Hilaire 2024-02-23 18:48:09 +01:00 committed by Grzegorz Sadowski
parent f3c438a531
commit dec0b4d86c
No known key found for this signature in database
GPG key ID: EF87FF4E6E3BD364
18 changed files with 160 additions and 76 deletions

View file

@ -155,6 +155,7 @@
<service id="Sylius\Bundle\ApiBundle\Validator\Constraints\ChosenPaymentRequestActionEligibilityValidator">
<argument type="service" id="sylius.repository.payment_method" />
<argument type="service" id="sylius.payment_request.command_provider.gateway_factory" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Provider\GatewayFactoryNameProviderInterface" />
<tag name="validator.constraint_validator" alias="sylius_api_chosen_payment_request_action_eligibility" />
</service>

View file

@ -16,6 +16,7 @@ namespace Sylius\Bundle\ApiBundle\Validator\Constraints;
use Sylius\Bundle\ApiBundle\Command\Payment\AddPaymentRequest;
use Sylius\Bundle\CoreBundle\PaymentRequest\CommandProvider\PaymentRequestCommandProviderInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\CommandProvider\ServiceProviderAwareCommandProviderInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Provider\GatewayFactoryNameProviderInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
use Symfony\Component\Validator\Constraint;
@ -28,6 +29,7 @@ final class ChosenPaymentRequestActionEligibilityValidator extends ConstraintVal
public function __construct(
private PaymentMethodRepositoryInterface $paymentMethodRepository,
private ServiceProviderAwareCommandProviderInterface $gatewayFactoryCommandProvider,
private GatewayFactoryNameProviderInterface $gatewayFactoryNameProvider,
) {
}
public function validate(mixed $value, Constraint $constraint): void
@ -65,7 +67,6 @@ final class ChosenPaymentRequestActionEligibilityValidator extends ConstraintVal
$paymentMethod = $this->paymentMethodRepository->findOneBy(['code' => $addPaymentRequest->getPaymentMethodCode()]);
if ($paymentMethod === null) {
return null;
}
@ -74,7 +75,7 @@ final class ChosenPaymentRequestActionEligibilityValidator extends ConstraintVal
return null;
}
$factoryName = $gatewayConfig->getConfig()['factory'] ?? $gatewayConfig->getFactoryName();
$factoryName = $this->gatewayFactoryNameProvider->provide($paymentMethod);
$commandProvider = $this->gatewayFactoryCommandProvider->getCommandProvider($factoryName);
return $commandProvider ?? null;
}

View file

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Checker;
use Sylius\Bundle\CoreBundle\PaymentRequest\Command\PaymentRequestHashAwareInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
use Sylius\Component\Payment\Repository\PaymentRequestRepositoryInterface;
use Webmozart\Assert\Assert;
final class PaymentRequestIntegrityChecker implements PaymentRequestIntegrityCheckerInterface
{
public function __construct(
private PaymentRequestRepositoryInterface $paymentRequestRepository,
) {
}
public function check(PaymentRequestHashAwareInterface $command): PaymentRequestInterface
{
$hash = $command->getHash();
Assert::notNull($hash, 'Payment request hash cannot be null.');
$paymentRequest = $this->paymentRequestRepository->findOneByHash($hash);
Assert::notNull($paymentRequest, sprintf('Payment request (hash "%s") not found.', $hash));
/** @var PaymentMethodInterface|null $paymentMethod */
$paymentMethod = $paymentRequest->getMethod();
Assert::notNull($paymentMethod, 'Payment cannot be null.');
$gatewayConfig = $paymentMethod->getGatewayConfig();
Assert::notNull($gatewayConfig, 'Payment method cannot be null.');
$payment = $paymentRequest->getPayment();
Assert::notNull($payment, 'Payment cannot be null.');
return $paymentRequest;
}
}

View file

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Checker;
use Sylius\Bundle\CoreBundle\PaymentRequest\Command\PaymentRequestHashAwareInterface;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
interface PaymentRequestIntegrityCheckerInterface
{
public function check(PaymentRequestHashAwareInterface $command): PaymentRequestInterface;
}

View file

@ -13,45 +13,26 @@ declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\CommandHandler\Offline;
use Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Command\Offline\CapturePaymentRequest;
use Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Offline\AfterCaptureProcessorInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Offline\CaptureProcessorInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Payment\Repository\PaymentRequestRepositoryInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Webmozart\Assert\Assert;
/** @experimental */
final class CapturePaymentRequestHandler implements MessageHandlerInterface
{
public const FACTORY_NAME = 'offline';
public function __construct(
private PaymentRequestRepositoryInterface $paymentRequestRepository,
private CaptureProcessorInterface $offlineCaptureProcessor,
private AfterCaptureProcessorInterface $afterOfflineCaptureProcessor,
private PaymentRequestIntegrityCheckerInterface $paymentRequestIntegrityChecker,
private CaptureProcessorInterface $offlineCaptureProcessor,
private AfterCaptureProcessorInterface $afterOfflineCaptureProcessor,
) {
}
public function __invoke(CapturePaymentRequest $capturePaymentRequest): void
{
$hash = $capturePaymentRequest->getHash();
Assert::notNull($hash, 'Payment request hash cannot be null.');
$paymentRequest = $this->paymentRequestRepository->findOneByHash($hash);
Assert::notNull($paymentRequest, sprintf('Payment request (hash "%s") not found.', $hash));
/** @var PaymentMethodInterface|null $paymentMethod */
$paymentMethod = $paymentRequest->getMethod();
Assert::notNull($paymentMethod, 'Payment cannot be null.');
$gatewayConfig = $paymentMethod->getGatewayConfig();
Assert::notNull($gatewayConfig, 'Payment method cannot be null.');
$factoryName = $gatewayConfig->getConfig()['factory'] ?? $gatewayConfig->getFactoryName();
Assert::eq($factoryName, self::FACTORY_NAME, 'Expected a factory name equal to %2$s. Got: %s');
$payment = $paymentRequest->getPayment();
Assert::notNull($payment);
$paymentRequest = $this->paymentRequestIntegrityChecker->check($capturePaymentRequest);
$this->offlineCaptureProcessor->process($paymentRequest);
$this->afterOfflineCaptureProcessor->process($paymentRequest);

View file

@ -13,18 +13,21 @@ declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\CommandHandler\Payum;
use Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Command\PaymentRequestHashAwareInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider\PaymentRequestProviderInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker\PayumRequirementsCheckerInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Payum\RequestProcessorInterface;
use Sylius\Bundle\PayumBundle\Factory\GetStatusFactoryInterface;
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Webmozart\Assert\Assert;
final class ModelPaymentRequestHandler implements MessageHandlerInterface
{
public function __construct(
private PaymentRequestProviderInterface $paymentRequestProvider,
private PaymentRequestIntegrityCheckerInterface $paymentRequestIntegrityChecker,
private PayumRequirementsCheckerInterface $payumRequirementsChecker,
private RequestProcessorInterface $requestProcessor,
private GetStatusFactoryInterface $factory,
) {
@ -32,26 +35,19 @@ final class ModelPaymentRequestHandler implements MessageHandlerInterface
public function __invoke(PaymentRequestHashAwareInterface $command): void
{
$hash = $command->getHash();
Assert::notNull($hash, 'Payment request hash cannot be null.');
$paymentRequest = $this->paymentRequestProvider->provideFromHash($hash);
Assert::notNull($paymentRequest, sprintf('Payment request (hash "%s") not found.', $hash));
$paymentRequest = $this->paymentRequestIntegrityChecker->check($command);
$this->payumRequirementsChecker->check($paymentRequest);
/** @var PaymentInterface $payment */
$payment = $paymentRequest->getPayment();
Assert::notNull($payment, 'Payment cannot be null.');
$request = $this->factory->createNewWithModel($payment);
/** @var PaymentMethodInterface|null $paymentMethod */
/** @var PaymentMethodInterface $paymentMethod */
$paymentMethod = $paymentRequest->getMethod();
Assert::notNull($paymentMethod, 'Payment method cannot be null.');
/** @var GatewayConfigInterface $gatewayConfig */
$gatewayConfig = $paymentMethod->getGatewayConfig();
Assert::notNull($gatewayConfig, 'Gateway config cannot be null.');
$gatewayName = $gatewayConfig->getGatewayName();
$this->requestProcessor->process($paymentRequest, $request, $gatewayName);
$this->requestProcessor->process($paymentRequest, $request, $gatewayConfig->getGatewayName());
}
}

View file

@ -13,9 +13,10 @@ declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\CommandHandler\Payum;
use Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Command\PaymentRequestHashAwareInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Factory\PayumTokenFactoryInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider\PaymentRequestProviderInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker\PayumRequirementsCheckerInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Payum\AfterTokenRequestProcessorInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Payum\RequestProcessorInterface;
use Sylius\Bundle\PayumBundle\Factory\TokenAggregateRequestFactoryInterface;
@ -25,7 +26,8 @@ use Webmozart\Assert\Assert;
final class TokenPaymentRequestHandler implements MessageHandlerInterface
{
public function __construct(
private PaymentRequestProviderInterface $paymentRequestProvider,
private PaymentRequestIntegrityCheckerInterface $paymentRequestIntegrityChecker,
private PayumRequirementsCheckerInterface $payumRequirementsChecker,
private PayumTokenFactoryInterface $payumTokenFactory,
private RequestProcessorInterface $requestProcessor,
private AfterTokenRequestProcessorInterface $afterTokenRequestProcessor,
@ -35,21 +37,16 @@ final class TokenPaymentRequestHandler implements MessageHandlerInterface
public function __invoke(PaymentRequestHashAwareInterface $command): void
{
$hash = $command->getHash();
Assert::notNull($hash, 'The payment request hash cannot be null.');
$paymentRequest = $this->paymentRequestProvider->provideFromHash($hash);
Assert::notNull($paymentRequest);
$paymentRequest = $this->paymentRequestIntegrityChecker->check($command);
$this->payumRequirementsChecker->check($paymentRequest);
$token = $this->payumTokenFactory->createNew($paymentRequest);
$request = $this->payumRequestFactory->createNewWithToken($token);
$token = $request->getToken();
Assert::notNull($token);
Assert::notNull($token, 'A Payum token cannot be null.');
$this->requestProcessor->process($paymentRequest, $request, $token->getGatewayName());
$this->afterTokenRequestProcessor->process($paymentRequest, $token);
}
}

View file

@ -14,6 +14,7 @@ declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\CommandProvider;
use Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestDuplicationCheckerInterface;
use Sylius\Bundle\CoreBundle\PaymentRequest\Provider\GatewayFactoryNameProviderInterface;
use Sylius\Bundle\PaymentBundle\Exception\PaymentRequestNotSupportedException;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
@ -24,6 +25,7 @@ final class GatewayFactoryCommandProvider implements ServiceProviderAwareCommand
{
public function __construct(
private PaymentRequestDuplicationCheckerInterface $paymentRequestDuplicationChecker,
private GatewayFactoryNameProviderInterface $gatewayFactoryNameProvider,
private ServiceProviderInterface $locator,
) {
}
@ -72,8 +74,9 @@ final class GatewayFactoryCommandProvider implements ServiceProviderAwareCommand
$paymentMethod = $paymentRequest->getMethod();
Assert::notNull($paymentMethod, 'Payment method cannot be null.');
$gatewayConfig = $paymentMethod->getGatewayConfig();
Assert::notNull($gatewayConfig, 'Gateway config cannot be null.');
return $gatewayConfig->getConfig()['factory'] ?? $gatewayConfig->getFactoryName();
$factoryName = $this->gatewayFactoryNameProvider->provide($paymentMethod);
Assert::notNull($factoryName, 'Gateway config cannot be null.');
return $factoryName;
}
}

View file

@ -11,30 +11,22 @@
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider;
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\Proxy;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
use Sylius\Component\Payment\Repository\PaymentRequestRepositoryInterface;
final class PaymentRequestProvider implements PaymentRequestProviderInterface
final class PayumRequirementsChecker implements PayumRequirementsCheckerInterface
{
public function __construct(
private PaymentRequestRepositoryInterface $paymentRequestRepository,
private EntityManagerInterface $entityManager,
) {
}
public function provideFromHash(string $hash): ?PaymentRequestInterface
public function check(PaymentRequestInterface $paymentRequest): void
{
$paymentRequest = $this->paymentRequestRepository->findOneByHash($hash);
if (null === $paymentRequest) {
return null;
}
// Needed to get a real object to give to Payum which is not handling
// Proxy class from Doctrine when a token is created for ex.
$payment = $paymentRequest->getPayment();
@ -43,7 +35,5 @@ final class PaymentRequestProvider implements PaymentRequestProviderInterface
$payment = $this->entityManager->find(PaymentInterface::class, $payment->getId());
$paymentRequest->setPayment($payment);
}
return $paymentRequest;
}
}

View file

@ -11,11 +11,11 @@
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider;
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
interface PaymentRequestProviderInterface
interface PayumRequirementsCheckerInterface
{
public function provideFromHash(string $hash): ?PaymentRequestInterface;
public function check(PaymentRequestInterface $paymentRequest): void;
}

View file

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Provider;
use Sylius\Component\Core\Model\PaymentMethodInterface;
final class GatewayFactoryNameProvider implements GatewayFactoryNameProviderInterface
{
public function provide(PaymentMethodInterface $paymentMethod): ?string
{
$gatewayConfig = $paymentMethod->getGatewayConfig();
if (null === $gatewayConfig) {
return null;
}
return $gatewayConfig->getConfig()['factory'] ?? $gatewayConfig->getFactoryName();
}
}

View file

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\PaymentRequest\Provider;
use Sylius\Component\Core\Model\PaymentMethodInterface;
interface GatewayFactoryNameProviderInterface
{
public function provide(PaymentMethodInterface $paymentMethod): ?string;
}

View file

@ -22,5 +22,9 @@
<argument type="service" id="sylius.repository.payment_request" />
</service>
<service id="Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface" class="Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityChecker">
<argument type="service" id="sylius.repository.payment_request" />
</service>
</services>
</container>

View file

@ -20,6 +20,7 @@
<service id="sylius.payment_request.command_provider.gateway_factory" class="Sylius\Bundle\CoreBundle\PaymentRequest\CommandProvider\GatewayFactoryCommandProvider">
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestDuplicationCheckerInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Provider\GatewayFactoryNameProviderInterface" />
<argument type="tagged_locator" tag="sylius.payment_request.command_provider" index-by="gateway-factory" />
</service>

View file

@ -19,7 +19,7 @@
<defaults public="true" />
<service id="sylius.payment_request.offline.capture" class="Sylius\Bundle\CoreBundle\PaymentRequest\CommandHandler\Offline\CapturePaymentRequestHandler">
<argument type="service" id="sylius.repository.payment_request" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Offline\CaptureProcessorInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Offline\AfterCaptureProcessorInterface" />
<tag name="messenger.message_handler" bus="sylius.command_bus" />

View file

@ -18,8 +18,7 @@
<services>
<defaults public="true" />
<service id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider\PaymentRequestProviderInterface" class="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider\PaymentRequestProvider">
<argument type="service" id="sylius.repository.payment_request" />
<service id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker\PayumRequirementsCheckerInterface" class="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker\PayumRequirementsChecker">
<argument type="service" id="doctrine.orm.entity_manager" />
</service>

View file

@ -19,7 +19,8 @@
<defaults public="true" />
<service id="Sylius\Bundle\CoreBundle\PaymentRequest\CommandHandler\Payum\TokenPaymentRequestHandler" abstract="true">
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider\PaymentRequestProviderInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker\PayumRequirementsCheckerInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Factory\PayumTokenFactoryInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Payum\RequestProcessorInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Payum\AfterTokenRequestProcessorInterface" />
@ -38,7 +39,8 @@
</service>
<service id="Sylius\Bundle\CoreBundle\PaymentRequest\CommandHandler\Payum\ModelPaymentRequestHandler" abstract="true">
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Provider\PaymentRequestProviderInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Checker\PaymentRequestIntegrityCheckerInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Payum\Checker\PayumRequirementsCheckerInterface" />
<argument type="service" id="Sylius\Bundle\CoreBundle\PaymentRequest\Processor\Payum\RequestProcessorInterface" />
</service>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is part of the Sylius package.
(c) Sylius Sp. z o.o.
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
-->
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<defaults public="true" />
<service id="Sylius\Bundle\CoreBundle\PaymentRequest\Provider\GatewayFactoryNameProviderInterface" class="Sylius\Bundle\CoreBundle\PaymentRequest\Provider\GatewayFactoryNameProvider" />
</services>
</container>