mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
[API] Decorate base write state processor to catch messenger exceptions
This commit is contained in:
parent
b9d2bac821
commit
517affc078
7 changed files with 92 additions and 129 deletions
|
|
@ -575,31 +575,6 @@ parameters:
|
||||||
count: 1
|
count: 1
|
||||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/CountryDataPersister.php
|
path: src/Sylius/Bundle/ApiBundle/DataPersister/CountryDataPersister.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\MessengerDataPersister\\:\\:persist\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/MessengerDataPersister.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\MessengerDataPersister\\:\\:remove\\(\\) has no return type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/MessengerDataPersister.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\MessengerDataPersister\\:\\:remove\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/MessengerDataPersister.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\MessengerDataPersister\\:\\:supports\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/MessengerDataPersister.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\MessengerDataPersister\\:\\:supports\\(\\) has parameter \\$data with no type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Sylius/Bundle/ApiBundle/DataPersister/MessengerDataPersister.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\ProductDataPersister\\:\\:persist\\(\\) has parameter \\$data with no type specified\\.$#"
|
message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\DataPersister\\\\ProductDataPersister\\:\\:persist\\(\\) has parameter \\$data with no type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,6 @@
|
||||||
<services>
|
<services>
|
||||||
<defaults public="true" />
|
<defaults public="true" />
|
||||||
|
|
||||||
<service id="Sylius\Bundle\ApiBundle\DataPersister\MessengerDataPersister">
|
|
||||||
<argument type="service" id="api_platform.messenger.data_persister" />
|
|
||||||
<tag name="api_platform.data_persister" />
|
|
||||||
</service>
|
|
||||||
|
|
||||||
<service id="Sylius\Bundle\ApiBundle\DataPersister\CountryDataPersister">
|
<service id="Sylius\Bundle\ApiBundle\DataPersister\CountryDataPersister">
|
||||||
<argument type="service" id="api_platform.doctrine.orm.data_persister" />
|
<argument type="service" id="api_platform.doctrine.orm.data_persister" />
|
||||||
<argument type="service" id="Sylius\Component\Addressing\Checker\CountryProvincesDeletionCheckerInterface" />
|
<argument type="service" id="Sylius\Component\Addressing\Checker\CountryProvincesDeletionCheckerInterface" />
|
||||||
|
|
|
||||||
|
|
@ -112,5 +112,14 @@
|
||||||
<argument type="service" id="sylius_api.creator.taxon_image" />
|
<argument type="service" id="sylius_api.creator.taxon_image" />
|
||||||
<tag name="api_platform.state_processor" />
|
<tag name="api_platform.state_processor" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
id="sylius_api.state_processor.shop.messenger.persist"
|
||||||
|
class="Sylius\Bundle\ApiBundle\StateProcessor\Common\MessengerPersistProcessor"
|
||||||
|
decorates="api_platform.state_processor.write"
|
||||||
|
>
|
||||||
|
<argument type="service" id=".inner" />
|
||||||
|
<tag name="api_platform.state_processor" />
|
||||||
|
</service>
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
|
|
||||||
|
|
@ -19,19 +19,19 @@ use ApiPlatform\State\ProcessorInterface;
|
||||||
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||||
use Sylius\Bundle\ApiBundle\Exception\PaymentMethodCannotBeRemoved;
|
use Sylius\Bundle\ApiBundle\Exception\PaymentMethodCannotBeRemoved;
|
||||||
use Sylius\Component\Core\Model\PaymentMethodInterface;
|
use Sylius\Component\Core\Model\PaymentMethodInterface;
|
||||||
use Sylius\Component\Core\Model\ProductInterface;
|
|
||||||
use Webmozart\Assert\Assert;
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
/** @implements ProcessorInterface<PaymentMethodInterface> */
|
/** @implements ProcessorInterface<PaymentMethodInterface, void> */
|
||||||
final readonly class RemoveProcessor implements ProcessorInterface
|
final readonly class RemoveProcessor implements ProcessorInterface
|
||||||
{
|
{
|
||||||
|
/** @param ProcessorInterface<PaymentMethodInterface, void> $removeProcessor */
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private ProcessorInterface $removeProcessor,
|
private ProcessorInterface $removeProcessor,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ProductInterface $data
|
* @param PaymentMethodInterface $data
|
||||||
*/
|
*/
|
||||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): void
|
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,27 +11,26 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Sylius\Bundle\ApiBundle\DataPersister;
|
namespace Sylius\Bundle\ApiBundle\StateProcessor\Common;
|
||||||
|
|
||||||
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
|
use ApiPlatform\Metadata\Operation;
|
||||||
|
use ApiPlatform\State\ProcessorInterface;
|
||||||
use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException;
|
use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException;
|
||||||
use Symfony\Component\Messenger\Exception\HandlerFailedException;
|
use Symfony\Component\Messenger\Exception\HandlerFailedException;
|
||||||
|
|
||||||
final class MessengerDataPersister implements ContextAwareDataPersisterInterface
|
/** @implements ProcessorInterface<object, mixed> */
|
||||||
|
final readonly class MessengerPersistProcessor implements ProcessorInterface
|
||||||
{
|
{
|
||||||
public function __construct(private ContextAwareDataPersisterInterface $decoratedDataPersister)
|
/** @param ProcessorInterface<object, mixed> $decoratedProcessor */
|
||||||
|
public function __construct(private ProcessorInterface $decoratedProcessor)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function supports($data, array $context = []): bool
|
/** @throws \Throwable */
|
||||||
{
|
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
|
||||||
return $this->decoratedDataPersister->supports($data, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function persist($data, array $context = [])
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $this->decoratedDataPersister->persist($data, $context);
|
return $this->decoratedProcessor->process($data, $operation, $uriVariables, $context);
|
||||||
} catch (DelayedMessageHandlingException|HandlerFailedException $e) {
|
} catch (DelayedMessageHandlingException|HandlerFailedException $e) {
|
||||||
while ($e instanceof DelayedMessageHandlingException) {
|
while ($e instanceof DelayedMessageHandlingException) {
|
||||||
/** @var \Throwable $e */
|
/** @var \Throwable $e */
|
||||||
|
|
@ -45,9 +44,4 @@ final class MessengerDataPersister implements ContextAwareDataPersisterInterface
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function remove($data, array $context = [])
|
|
||||||
{
|
|
||||||
$this->decoratedDataPersister->remove($data, $context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace spec\Sylius\Bundle\ApiBundle\DataPersister;
|
|
||||||
|
|
||||||
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
|
|
||||||
use PhpSpec\ObjectBehavior;
|
|
||||||
use Prophecy\Argument;
|
|
||||||
use Sylius\Bundle\ApiBundle\Command\Checkout\CompleteOrder;
|
|
||||||
use Symfony\Component\HttpKernel\Kernel;
|
|
||||||
use Symfony\Component\Messenger\Envelope;
|
|
||||||
use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException;
|
|
||||||
use Symfony\Component\Messenger\Exception\HandlerFailedException;
|
|
||||||
|
|
||||||
final class MessengerDataPersisterSpec extends ObjectBehavior
|
|
||||||
{
|
|
||||||
function let(ContextAwareDataPersisterInterface $decoratedDataPersister)
|
|
||||||
{
|
|
||||||
$this->beConstructedWith($decoratedDataPersister);
|
|
||||||
}
|
|
||||||
|
|
||||||
function it_calls_supports_method_from_decorated_data_presister(
|
|
||||||
ContextAwareDataPersisterInterface $decoratedDataPersister,
|
|
||||||
): void {
|
|
||||||
$decoratedDataPersister->supports(Argument::any(), [])->shouldBeCalled();
|
|
||||||
|
|
||||||
$this->supports(Argument::any(), []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function it_unwraps_delayed_message_handling_exception(ContextAwareDataPersisterInterface $decoratedDataPersister): void
|
|
||||||
{
|
|
||||||
$completeOrder = new CompleteOrder('ThankYou');
|
|
||||||
$completeOrder->setOrderTokenValue('ORDERTOKEN');
|
|
||||||
$envelope = new Envelope($completeOrder);
|
|
||||||
|
|
||||||
if (version_compare(Kernel::VERSION, '6.3.5', '>=')) {
|
|
||||||
$exception = new DelayedMessageHandlingException([new \RuntimeException('Delayed message exception')], $envelope);
|
|
||||||
} else {
|
|
||||||
$exception = new DelayedMessageHandlingException([new \RuntimeException('Delayed message exception')]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$decoratedDataPersister->persist($envelope, [])->willThrow($exception);
|
|
||||||
|
|
||||||
$this->shouldThrow(new \RuntimeException('Delayed message exception'))->during('persist', [$envelope, []]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function it_unwraps_handler_failed_exception(ContextAwareDataPersisterInterface $decoratedDataPersister): void
|
|
||||||
{
|
|
||||||
$completeOrder = new CompleteOrder('ThankYou');
|
|
||||||
$completeOrder->setOrderTokenValue('ORDERTOKEN');
|
|
||||||
$envelope = new Envelope($completeOrder);
|
|
||||||
|
|
||||||
$decoratedDataPersister->persist($envelope, [])->willThrow(
|
|
||||||
new HandlerFailedException(
|
|
||||||
$envelope,
|
|
||||||
[new \RuntimeException('Delayed message exception')],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->shouldThrow(new \RuntimeException('Delayed message exception'))->during('persist', [$envelope, []]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function it_calls_remove_method_from_decorated_data_presister(
|
|
||||||
ContextAwareDataPersisterInterface $decoratedDataPersister,
|
|
||||||
): void {
|
|
||||||
$decoratedDataPersister->remove(Argument::any(), [])->shouldBeCalled();
|
|
||||||
|
|
||||||
$this->remove(Argument::any(), []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace spec\Sylius\Bundle\ApiBundle\StateProcessor\Common;
|
||||||
|
|
||||||
|
use ApiPlatform\Metadata\Post;
|
||||||
|
use ApiPlatform\State\ProcessorInterface;
|
||||||
|
use PhpSpec\ObjectBehavior;
|
||||||
|
use Sylius\Bundle\ApiBundle\Command\Checkout\CompleteOrder;
|
||||||
|
use Symfony\Component\Messenger\Envelope;
|
||||||
|
use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException;
|
||||||
|
use Symfony\Component\Messenger\Exception\HandlerFailedException;
|
||||||
|
|
||||||
|
final class MessengerPersistProcessorSpec extends ObjectBehavior
|
||||||
|
{
|
||||||
|
function let(ProcessorInterface $decoratedProcessor): void
|
||||||
|
{
|
||||||
|
$this->beConstructedWith($decoratedProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function it_implements_processor_interface(): void
|
||||||
|
{
|
||||||
|
$this->shouldImplement(ProcessorInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
function it_unwraps_delayed_message_handling_exception(ProcessorInterface $decoratedProcessor): void
|
||||||
|
{
|
||||||
|
$command = new CompleteOrder('ThankYou', 'token');
|
||||||
|
$envelope = new Envelope($command);
|
||||||
|
$operation = new Post();
|
||||||
|
|
||||||
|
$exception = new DelayedMessageHandlingException([new \RuntimeException('Delayed message exception')], $envelope);
|
||||||
|
|
||||||
|
$decoratedProcessor->process($envelope, $operation, [], [])->willThrow($exception);
|
||||||
|
|
||||||
|
$this
|
||||||
|
->shouldThrow(new \RuntimeException('Delayed message exception'))
|
||||||
|
->during('process', [$envelope, $operation, [], []])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
function it_unwraps_handler_failed_exception(ProcessorInterface $decoratedProcessor): void
|
||||||
|
{
|
||||||
|
$command = new CompleteOrder('ThankYou', 'token');
|
||||||
|
$envelope = new Envelope($command);
|
||||||
|
$operation = new Post();
|
||||||
|
|
||||||
|
$decoratedProcessor->process($envelope, $operation, [], [])->willThrow(
|
||||||
|
new HandlerFailedException(
|
||||||
|
$envelope,
|
||||||
|
[new \RuntimeException('Delayed message exception')],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this
|
||||||
|
->shouldThrow(new \RuntimeException('Delayed message exception'))
|
||||||
|
->during('process', [$envelope, $operation, [], []])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue