diff --git a/src/Controller/Shop/ProcessNotificationsAction.php b/src/Controller/Shop/ProcessNotificationsAction.php index e2cd8a52..22b6c70b 100644 --- a/src/Controller/Shop/ProcessNotificationsAction.php +++ b/src/Controller/Shop/ProcessNotificationsAction.php @@ -12,24 +12,25 @@ namespace BitBag\SyliusAdyenPlugin\Controller\Shop; use BitBag\SyliusAdyenPlugin\Bus\DispatcherInterface; -use BitBag\SyliusAdyenPlugin\Resolver\Notification\NotificationResolver; +use BitBag\SyliusAdyenPlugin\Exception\NotificationItemsEmptyException; use BitBag\SyliusAdyenPlugin\Resolver\Notification\NotificationResolver\NoCommandResolvedException; -use BitBag\SyliusAdyenPlugin\Resolver\Notification\NotificationToCommandResolver; +use BitBag\SyliusAdyenPlugin\Resolver\Notification\NotificationResolverInterface; +use BitBag\SyliusAdyenPlugin\Resolver\Notification\NotificationToCommandResolverInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; class ProcessNotificationsAction { - public const EXPECTED_ADYEN_RESPONSE = '[accepted]'; + private const EXPECTED_ADYEN_RESPONSE = '[accepted]'; /** @var DispatcherInterface */ private $dispatcher; - /** @var NotificationToCommandResolver */ + /** @var NotificationToCommandResolverInterface */ private $notificationCommandResolver; - /** @var NotificationResolver */ + /** @var NotificationResolverInterface */ private $notificationResolver; /** @var LoggerInterface */ @@ -37,8 +38,8 @@ class ProcessNotificationsAction public function __construct( DispatcherInterface $dispatcher, - NotificationToCommandResolver $notificationCommandResolver, - NotificationResolver $notificationResolver, + NotificationToCommandResolverInterface $notificationCommandResolver, + NotificationResolverInterface $notificationResolver, LoggerInterface $logger, ) { $this->dispatcher = $dispatcher; @@ -49,7 +50,14 @@ public function __construct( public function __invoke(string $code, Request $request): Response { - foreach ($this->notificationResolver->resolve($code, $request) as $notificationItem) { + try { + $notifications = $this->notificationResolver->resolve($code, $request); + } catch (NotificationItemsEmptyException) { + $this->logger->error('Request payload did not contain any notification items'); + $notifications = []; + } + + foreach ($notifications as $notificationItem) { if (null === $notificationItem || false === $notificationItem->success) { $this->logger->error(\sprintf( 'Payment with pspReference [%s] did not return success', diff --git a/src/Exception/NotificationItemsEmptyException.php b/src/Exception/NotificationItemsEmptyException.php index 497ee912..63be03ed 100644 --- a/src/Exception/NotificationItemsEmptyException.php +++ b/src/Exception/NotificationItemsEmptyException.php @@ -11,6 +11,6 @@ namespace BitBag\SyliusAdyenPlugin\Exception; -class NotificationItemsEmptyException extends \InvalidArgumentException +final class NotificationItemsEmptyException extends \InvalidArgumentException { } diff --git a/src/Resolver/Notification/NotificationResolver.php b/src/Resolver/Notification/NotificationResolver.php index d44bd50b..8b41ad9e 100644 --- a/src/Resolver/Notification/NotificationResolver.php +++ b/src/Resolver/Notification/NotificationResolver.php @@ -11,6 +11,7 @@ namespace BitBag\SyliusAdyenPlugin\Resolver\Notification; +use BitBag\SyliusAdyenPlugin\Exception\NotificationItemsEmptyException; use BitBag\SyliusAdyenPlugin\Resolver\Notification\Struct\NotificationItemData; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -48,11 +49,12 @@ public function __construct( */ private function denormalizeRequestData(Request $request): array { + $result = []; $payload = $request->request->all(); /** @var array $notificationItems */ - $notificationItems = $payload['notificationItems']; - $result = []; + $notificationItems = $payload['notificationItems'] + ?? throw new NotificationItemsEmptyException(); /** @var array $notificationItem */ foreach ($notificationItems as $notificationItem) { @@ -70,7 +72,7 @@ private function denormalizeRequestData(Request $request): array } /** - * @return NotificationItemData[] + * @inheritDoc */ public function resolve(string $paymentCode, Request $request): array { diff --git a/src/Resolver/Notification/NotificationResolverInterface.php b/src/Resolver/Notification/NotificationResolverInterface.php index 064db7d9..8087884a 100644 --- a/src/Resolver/Notification/NotificationResolverInterface.php +++ b/src/Resolver/Notification/NotificationResolverInterface.php @@ -11,6 +11,7 @@ namespace BitBag\SyliusAdyenPlugin\Resolver\Notification; +use BitBag\SyliusAdyenPlugin\Exception\NotificationItemsEmptyException; use BitBag\SyliusAdyenPlugin\Resolver\Notification\Struct\NotificationItemData; use Symfony\Component\HttpFoundation\Request; @@ -18,6 +19,8 @@ interface NotificationResolverInterface { /** * @return NotificationItemData[] + * + * @throws NotificationItemsEmptyException */ public function resolve(string $paymentCode, Request $request): array; } diff --git a/src/Resolver/Notification/Struct/NotificationRequest.php b/src/Resolver/Notification/Struct/NotificationRequest.php index 7816539a..67677337 100644 --- a/src/Resolver/Notification/Struct/NotificationRequest.php +++ b/src/Resolver/Notification/Struct/NotificationRequest.php @@ -16,6 +16,6 @@ class NotificationRequest /** @var ?bool */ public $live; - /** @var ?NotificationItem[] */ - public $notificationItems; + /** @var NotificationItem[] */ + public $notificationItems = []; } diff --git a/tests/Unit/Controller/Shop/ProcessNotificationsActionTest.php b/tests/Unit/Controller/Shop/ProcessNotificationsActionTest.php new file mode 100644 index 00000000..5e302f22 --- /dev/null +++ b/tests/Unit/Controller/Shop/ProcessNotificationsActionTest.php @@ -0,0 +1,38 @@ +createMock(DispatcherInterface::class), + $this->createMock(NotificationToCommandResolverInterface::class), + $this->createMock(NotificationResolverInterface::class), + new NullLogger(), + ); + + $response = $action('dummy-code', RequestMother::createDummy()); + + self::assertSame(200, $response->getStatusCode()); + self::assertSame('[accepted]', $response->getContent()); + } +} diff --git a/tests/Unit/Mock/RequestMother.php b/tests/Unit/Mock/RequestMother.php index 02ef4bde..2d8e7040 100644 --- a/tests/Unit/Mock/RequestMother.php +++ b/tests/Unit/Mock/RequestMother.php @@ -18,14 +18,21 @@ final class RequestMother { - public const TEST_LOCALE = 'pl_PL'; + private const ROOT_PATH = '/'; + + private const TEST_LOCALE = 'pl_PL'; public const WHERE_YOUR_HOME_IS = '127.0.0.1'; + public static function createDummy(): Request + { + return Request::create(self::ROOT_PATH); + } + public static function createWithSession(): Request { $session = new Session(new MockArraySessionStorage()); - $request = Request::create('/'); + $request = Request::create(self::ROOT_PATH); $request->setSession($session); return $request; @@ -49,7 +56,7 @@ public static function createWithSessionForSpecifiedQueryToken(): Request public static function createWithLocaleSet(): Request { - $result = Request::create('/', 'GET', [], [], [], ['REMOTE_ADDR' => self::WHERE_YOUR_HOME_IS]); + $result = Request::create(self::ROOT_PATH, 'GET', [], [], [], ['REMOTE_ADDR' => self::WHERE_YOUR_HOME_IS]); $result->setLocale(self::TEST_LOCALE); return $result; diff --git a/tests/Unit/Resolver/Notification/NotificationResolverTest.php b/tests/Unit/Resolver/Notification/NotificationResolverTest.php new file mode 100644 index 00000000..e8bc42e1 --- /dev/null +++ b/tests/Unit/Resolver/Notification/NotificationResolverTest.php @@ -0,0 +1,36 @@ +createMock(DenormalizerInterface::class), + $this->createMock(ValidatorInterface::class), + new NullLogger(), + ); + + $this->expectException(NotificationItemsEmptyException::class); + + $resolver->resolve('dummy-payment-code', RequestMother::createDummy()); + } +}