From f80d609bef7dcc6c41f5acb8243a638ee1841a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Chru=C5=9Bciel?= Date: Wed, 24 Jul 2019 10:18:40 +0200 Subject: [PATCH 1/3] [Customer] Refactor customer assignment to command --- src/EventListener/CartBlamerListener.php | 54 +++++++++++------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/EventListener/CartBlamerListener.php b/src/EventListener/CartBlamerListener.php index d2389f57e..3b97999a9 100644 --- a/src/EventListener/CartBlamerListener.php +++ b/src/EventListener/CartBlamerListener.php @@ -6,12 +6,12 @@ use Doctrine\Common\Persistence\ObjectManager; use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent; -use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\ShopUserInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; -use Sylius\Component\Order\Context\CartContextInterface; -use Sylius\Component\Order\Context\CartNotFoundException; +use Sylius\Component\Order\Processor\OrderProcessorInterface; +use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Messenger\MessageBusInterface; use Webmozart\Assert\Assert; final class CartBlamerListener @@ -19,24 +19,29 @@ final class CartBlamerListener /** @var ObjectManager */ private $cartManager; - /** @var CartContextInterface */ - private $cartContext; - /** @var OrderRepositoryInterface */ private $cartRepository; + /** @var MessageBusInterface */ + private $bus; + + /** @var OrderProcessorInterface */ + private $orderProcessor; + /** @var RequestStack */ private $requestStack; public function __construct( ObjectManager $cartManager, - CartContextInterface $cartContext, OrderRepositoryInterface $cartRepository, + MessageBusInterface $bus, + OrderProcessorInterface $orderProcessor, RequestStack $requestStack ) { $this->cartManager = $cartManager; - $this->cartContext = $cartContext; $this->cartRepository = $cartRepository; + $this->bus = $bus; + $this->orderProcessor = $orderProcessor; $this->requestStack = $requestStack; } @@ -51,33 +56,24 @@ public function onJwtLogin(JWTCreatedEvent $interactiveLoginEvent): void return; } - $cart = $this->getCart($request->request->get('token')); + $token = $request->request->get('token'); + + $cart = $this->cartRepository->findOneBy(['tokenValue' => $token]); if (null === $cart) { return; } - $cart->setCustomer($user->getCustomer()); - $this->cartManager->persist($cart); - $this->cartManager->flush(); - } - - private function getCart(?string $token): ?OrderInterface - { - if (null !== $token) { - /** @var OrderInterface $cart */ - $cart = $this->cartRepository->findOneBy(['tokenValue' => $token]); - - return $cart; - } + $this->bus->dispatch( + new AssignCustomerToCart( + $token, + $user->getCustomer()->getEmail() + ) + ); - try { - /** @var OrderInterface $cart */ - $cart = $this->cartContext->getCart(); + $this->orderProcessor->process($cart); - return $cart; - } catch (CartNotFoundException $exception) { - return null; - } + $this->cartManager->persist($cart); + $this->cartManager->flush(); } } From bf722788d45e8553960e33e22459e7dcc2a3893d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Chru=C5=9Bciel?= Date: Wed, 24 Jul 2019 11:02:55 +0200 Subject: [PATCH 2/3] [Cart] Simplify cart recalculation after customer cart assignment --- .../Cart/AssignCustomerToCartHandlerSpec.php | 27 ++++++---- src/EventListener/CartBlamerListener.php | 17 ------- .../UserCartRecalculationListener.php | 49 ------------------- .../Cart/AssignCustomerToCartHandler.php | 26 +++++++--- src/Resources/config/services.xml | 10 +--- .../config/services/handler/cart.xml | 1 + 6 files changed, 37 insertions(+), 93 deletions(-) delete mode 100644 src/EventListener/UserCartRecalculationListener.php diff --git a/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php b/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php index 8ff41b3f9..1e6d03ece 100644 --- a/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php +++ b/spec/Handler/Cart/AssignCustomerToCartHandlerSpec.php @@ -8,35 +8,42 @@ use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; +use Sylius\Component\Order\Processor\OrderProcessorInterface; use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Sylius\ShopApiPlugin\Provider\CustomerProviderInterface; final class AssignCustomerToCartHandlerSpec extends ObjectBehavior { - function let(OrderRepositoryInterface $orderRepository, CustomerProviderInterface $customerProvider): void - { - $this->beConstructedWith($orderRepository, $customerProvider); + function let( + OrderRepositoryInterface $cartRepository, + OrderProcessorInterface $orderProcessor, + CustomerProviderInterface $customerProvider + ): void { + $this->beConstructedWith($cartRepository, $orderProcessor, $customerProvider); } function it_handles_assigning_customer_to_cart( - CustomerInterface $customer, + OrderRepositoryInterface $cartRepository, + OrderProcessorInterface $orderProcessor, CustomerProviderInterface $customerProvider, - OrderInterface $order, - OrderRepositoryInterface $orderRepository + CustomerInterface $customer, + OrderInterface $cart ): void { - $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($cart); $customerProvider->provide('example@customer.com')->willReturn($customer); - $order->setCustomer($customer)->shouldBeCalled(); + $cart->setCustomer($customer)->shouldBeCalled(); + + $orderProcessor->process($cart); $this(new AssignCustomerToCart('ORDERTOKEN', 'example@customer.com')); } function it_throws_an_exception_if_order_does_not_exist( - OrderRepositoryInterface $orderRepository + OrderRepositoryInterface $cartRepository ): void { - $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn(null); + $cartRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn(null); $this ->shouldThrow(\InvalidArgumentException::class) diff --git a/src/EventListener/CartBlamerListener.php b/src/EventListener/CartBlamerListener.php index 3b97999a9..9520ce632 100644 --- a/src/EventListener/CartBlamerListener.php +++ b/src/EventListener/CartBlamerListener.php @@ -4,11 +4,9 @@ namespace Sylius\ShopApiPlugin\EventListener; -use Doctrine\Common\Persistence\ObjectManager; use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent; use Sylius\Component\Core\Model\ShopUserInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; -use Sylius\Component\Order\Processor\OrderProcessorInterface; use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Messenger\MessageBusInterface; @@ -16,32 +14,22 @@ final class CartBlamerListener { - /** @var ObjectManager */ - private $cartManager; - /** @var OrderRepositoryInterface */ private $cartRepository; /** @var MessageBusInterface */ private $bus; - /** @var OrderProcessorInterface */ - private $orderProcessor; - /** @var RequestStack */ private $requestStack; public function __construct( - ObjectManager $cartManager, OrderRepositoryInterface $cartRepository, MessageBusInterface $bus, - OrderProcessorInterface $orderProcessor, RequestStack $requestStack ) { - $this->cartManager = $cartManager; $this->cartRepository = $cartRepository; $this->bus = $bus; - $this->orderProcessor = $orderProcessor; $this->requestStack = $requestStack; } @@ -70,10 +58,5 @@ public function onJwtLogin(JWTCreatedEvent $interactiveLoginEvent): void $user->getCustomer()->getEmail() ) ); - - $this->orderProcessor->process($cart); - - $this->cartManager->persist($cart); - $this->cartManager->flush(); } } diff --git a/src/EventListener/UserCartRecalculationListener.php b/src/EventListener/UserCartRecalculationListener.php deleted file mode 100644 index acf8dead9..000000000 --- a/src/EventListener/UserCartRecalculationListener.php +++ /dev/null @@ -1,49 +0,0 @@ -cartContext = $cartContext; - $this->orderProcessor = $orderProcessor; - $this->cartManager = $cartManager; - } - - public function recalculateCartWhileLogin(): void - { - try { - $cart = $this->cartContext->getCart(); - } catch (CartNotFoundException $exception) { - return; - } - - Assert::isInstanceOf($cart, OrderInterface::class); - - $this->orderProcessor->process($cart); - - $this->cartManager->flush(); - } -} diff --git a/src/Handler/Cart/AssignCustomerToCartHandler.php b/src/Handler/Cart/AssignCustomerToCartHandler.php index d5ce5f6f5..0a8ab0170 100644 --- a/src/Handler/Cart/AssignCustomerToCartHandler.php +++ b/src/Handler/Cart/AssignCustomerToCartHandler.php @@ -6,6 +6,7 @@ use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; +use Sylius\Component\Order\Processor\OrderProcessorInterface; use Sylius\ShopApiPlugin\Command\Cart\AssignCustomerToCart; use Sylius\ShopApiPlugin\Provider\CustomerProviderInterface; use Webmozart\Assert\Assert; @@ -13,26 +14,35 @@ final class AssignCustomerToCartHandler { /** @var OrderRepositoryInterface */ - private $orderRepository; + private $cartRepository; + + /** @var OrderProcessorInterface */ + private $orderProcessor; /** @var CustomerProviderInterface */ private $customerProvider; - public function __construct(OrderRepositoryInterface $orderRepository, CustomerProviderInterface $customerProvider) - { - $this->orderRepository = $orderRepository; + public function __construct( + OrderRepositoryInterface $cartRepository, + OrderProcessorInterface $orderProcessor, + CustomerProviderInterface $customerProvider + ) { + $this->cartRepository = $cartRepository; $this->customerProvider = $customerProvider; + $this->orderProcessor = $orderProcessor; } public function __invoke(AssignCustomerToCart $assignOrderToCustomer): void { - /** @var OrderInterface $order */ - $order = $this->orderRepository->findOneBy(['tokenValue' => $assignOrderToCustomer->orderToken()]); + /** @var OrderInterface $cart */ + $cart = $this->cartRepository->findOneBy(['tokenValue' => $assignOrderToCustomer->orderToken()]); - Assert::notNull($order, sprintf('Order with %s token has not been found.', $assignOrderToCustomer->orderToken())); + Assert::notNull($cart, sprintf('Order with %s token has not been found.', $assignOrderToCustomer->orderToken())); $customer = $this->customerProvider->provide($assignOrderToCustomer->email()); - $order->setCustomer($customer); + $cart->setCustomer($customer); + + $this->orderProcessor->process($cart); } } diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index d1bfa6d5e..4cad85691 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -77,20 +77,12 @@ id="sylius.listener.cart_blamer" class="Sylius\ShopApiPlugin\EventListener\CartBlamerListener" > - - + - - - - - - - diff --git a/src/Resources/config/services/handler/cart.xml b/src/Resources/config/services/handler/cart.xml index 51296e239..6b7392530 100644 --- a/src/Resources/config/services/handler/cart.xml +++ b/src/Resources/config/services/handler/cart.xml @@ -101,6 +101,7 @@ + From e97cd65eceaea10839675646164eec82fc28472e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Chru=C5=9Bciel?= Date: Wed, 24 Jul 2019 12:03:57 +0200 Subject: [PATCH 3/3] [Cart] Auto assign customer to cart during cart pick up --- spec/Event/CartPickedUpSpec.php | 20 +++++++ .../Messenger/CartPickedUpListenerSpec.php | 53 +++++++++++++++++++ spec/Handler/Cart/PickupCartHandlerSpec.php | 16 ++++-- src/Event/CartPickedUp.php | 21 ++++++++ src/EventListener/CartBlamerListener.php | 7 +-- .../Messenger/CartPickedUpListener.php | 37 +++++++++++++ src/Handler/Cart/PickupCartHandler.php | 11 +++- src/Resources/config/app/config.yml | 3 ++ src/Resources/config/services.xml | 10 ++-- .../config/services/handler/cart.xml | 1 + tests/Controller/Cart/CartPickupApiTest.php | 6 +++ 11 files changed, 172 insertions(+), 13 deletions(-) create mode 100644 spec/Event/CartPickedUpSpec.php create mode 100644 spec/EventListener/Messenger/CartPickedUpListenerSpec.php create mode 100644 src/Event/CartPickedUp.php create mode 100644 src/EventListener/Messenger/CartPickedUpListener.php diff --git a/spec/Event/CartPickedUpSpec.php b/spec/Event/CartPickedUpSpec.php new file mode 100644 index 000000000..c27034905 --- /dev/null +++ b/spec/Event/CartPickedUpSpec.php @@ -0,0 +1,20 @@ +beConstructedWith('ORDERTOKEN'); + } + + function it_has_order_token(): void + { + $this->orderToken()->shouldReturn('ORDERTOKEN'); + } +} diff --git a/spec/EventListener/Messenger/CartPickedUpListenerSpec.php b/spec/EventListener/Messenger/CartPickedUpListenerSpec.php new file mode 100644 index 000000000..d0b703d6b --- /dev/null +++ b/spec/EventListener/Messenger/CartPickedUpListenerSpec.php @@ -0,0 +1,53 @@ +beConstructedWith($loggedInShopUserProvider, $bus); + } + + function it_assigns_customer_to_cart_when_user_is_logged_in( + LoggedInShopUserProviderInterface $loggedInShopUserProvider, + MessageBusInterface $bus, + ShopUserInterface $shopUser, + CustomerInterface $customer + ): void { + $loggedInShopUserProvider->isUserLoggedIn()->willReturn(true); + + $loggedInShopUserProvider->provide()->willReturn($shopUser); + $shopUser->getCustomer()->willReturn($customer); + $customer->getEmail()->willReturn('peter@parker.com'); + + $assignCustomerToCart = new AssignCustomerToCart('ORDERTOKEN', 'peter@parker.com'); + + $bus->dispatch($assignCustomerToCart)->willReturn(new Envelope($assignCustomerToCart))->shouldBeCalled(); + + $this(new CartPickedUp('ORDERTOKEN')); + } + + function it_does_nothing_if_user_is_not_logged_in( + LoggedInShopUserProviderInterface $loggedInShopUserProvider, + MessageBusInterface $bus + ): void { + $loggedInShopUserProvider->isUserLoggedIn()->willReturn(false); + + $bus->dispatch(Argument::any())->shouldNotBeCalled(); + + $this(new CartPickedUp('ORDERTOKEN')); + } +} diff --git a/spec/Handler/Cart/PickupCartHandlerSpec.php b/spec/Handler/Cart/PickupCartHandlerSpec.php index 750ad5ce0..3a3cb33c1 100644 --- a/spec/Handler/Cart/PickupCartHandlerSpec.php +++ b/spec/Handler/Cart/PickupCartHandlerSpec.php @@ -13,19 +13,24 @@ use Sylius\Component\Locale\Model\LocaleInterface; use Sylius\Component\Resource\Factory\FactoryInterface; use Sylius\ShopApiPlugin\Command\Cart\PickupCart; +use Sylius\ShopApiPlugin\Event\CartPickedUp; use Sylius\ShopApiPlugin\Handler\Cart\PickupCartHandler; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\MessageBusInterface; final class PickupCartHandlerSpec extends ObjectBehavior { function let( FactoryInterface $cartFactory, OrderRepositoryInterface $cartRepository, - ChannelRepositoryInterface $channelRepository + ChannelRepositoryInterface $channelRepository, + MessageBusInterface $eventBus ): void { $this->beConstructedWith( $cartFactory, $cartRepository, - $channelRepository + $channelRepository, + $eventBus ); } @@ -41,7 +46,8 @@ function it_handles_cart_pickup_for_not_logged_in_user( FactoryInterface $cartFactory, LocaleInterface $locale, OrderInterface $cart, - OrderRepositoryInterface $cartRepository + OrderRepositoryInterface $cartRepository, + MessageBusInterface $eventBus ): void { $channelRepository->findOneByCode('CHANNEL_CODE')->willReturn($channel); $channel->getBaseCurrency()->willReturn($currency); @@ -58,6 +64,10 @@ function it_handles_cart_pickup_for_not_logged_in_user( $cartRepository->add($cart)->shouldBeCalledOnce(); + $cartPickedUp = new CartPickedUp('ORDERTOKEN'); + + $eventBus->dispatch($cartPickedUp)->willReturn(new Envelope($cartPickedUp))->shouldBeCalled(); + $this(new PickupCart('ORDERTOKEN', 'CHANNEL_CODE')); } diff --git a/src/Event/CartPickedUp.php b/src/Event/CartPickedUp.php new file mode 100644 index 000000000..70a3baba2 --- /dev/null +++ b/src/Event/CartPickedUp.php @@ -0,0 +1,21 @@ +orderToken = $orderToken; + } + + public function orderToken(): string + { + return $this->orderToken; + } +} diff --git a/src/EventListener/CartBlamerListener.php b/src/EventListener/CartBlamerListener.php index 9520ce632..5222a8e0d 100644 --- a/src/EventListener/CartBlamerListener.php +++ b/src/EventListener/CartBlamerListener.php @@ -52,11 +52,6 @@ public function onJwtLogin(JWTCreatedEvent $interactiveLoginEvent): void return; } - $this->bus->dispatch( - new AssignCustomerToCart( - $token, - $user->getCustomer()->getEmail() - ) - ); + $this->bus->dispatch(new AssignCustomerToCart($token, $user->getCustomer()->getEmail())); } } diff --git a/src/EventListener/Messenger/CartPickedUpListener.php b/src/EventListener/Messenger/CartPickedUpListener.php new file mode 100644 index 000000000..ea18b0299 --- /dev/null +++ b/src/EventListener/Messenger/CartPickedUpListener.php @@ -0,0 +1,37 @@ +loggedInShopUserProvider = $loggedInShopUserProvider; + $this->bus = $bus; + } + + public function __invoke(CartPickedUp $cartPickedUp): void + { + if (!$this->loggedInShopUserProvider->isUserLoggedIn()) { + return; + } + + $shopUser = $this->loggedInShopUserProvider->provide(); + $email = $shopUser->getCustomer()->getEmail(); + + $this->bus->dispatch(new AssignCustomerToCart($cartPickedUp->orderToken(), $email)); + } +} diff --git a/src/Handler/Cart/PickupCartHandler.php b/src/Handler/Cart/PickupCartHandler.php index 8fda8edba..2c3d840a6 100644 --- a/src/Handler/Cart/PickupCartHandler.php +++ b/src/Handler/Cart/PickupCartHandler.php @@ -10,6 +10,8 @@ use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Resource\Factory\FactoryInterface; use Sylius\ShopApiPlugin\Command\Cart\PickupCart; +use Sylius\ShopApiPlugin\Event\CartPickedUp; +use Symfony\Component\Messenger\MessageBusInterface; use Webmozart\Assert\Assert; final class PickupCartHandler @@ -23,14 +25,19 @@ final class PickupCartHandler /** @var ChannelRepositoryInterface */ private $channelRepository; + /** @var MessageBusInterface */ + private $eventBus; + public function __construct( FactoryInterface $cartFactory, OrderRepositoryInterface $cartRepository, - ChannelRepositoryInterface $channelRepository + ChannelRepositoryInterface $channelRepository, + MessageBusInterface $eventBus ) { $this->cartFactory = $cartFactory; $this->cartRepository = $cartRepository; $this->channelRepository = $channelRepository; + $this->eventBus = $eventBus; } public function __invoke(PickupCart $pickupCart): void @@ -48,5 +55,7 @@ public function __invoke(PickupCart $pickupCart): void $cart->setTokenValue($pickupCart->orderToken()); $this->cartRepository->add($cart); + + $this->eventBus->dispatch(new CartPickedUp($pickupCart->orderToken())); } } diff --git a/src/Resources/config/app/config.yml b/src/Resources/config/app/config.yml index 7e1443c38..f13cbfe89 100644 --- a/src/Resources/config/app/config.yml +++ b/src/Resources/config/app/config.yml @@ -13,10 +13,13 @@ jms_serializer: framework: messenger: + default_bus: sylius_shop_api_plugin.command_bus buses: sylius_shop_api_plugin.command_bus: middleware: - doctrine_transaction + sylius_shop_api_plugin.event_bus: + default_middleware: allow_no_handlers sylius_customer: resources: diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 4cad85691..01d5bca41 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -83,9 +83,13 @@ - - - + + + + diff --git a/src/Resources/config/services/handler/cart.xml b/src/Resources/config/services/handler/cart.xml index 6b7392530..6fdbc448d 100644 --- a/src/Resources/config/services/handler/cart.xml +++ b/src/Resources/config/services/handler/cart.xml @@ -15,6 +15,7 @@ + diff --git a/tests/Controller/Cart/CartPickupApiTest.php b/tests/Controller/Cart/CartPickupApiTest.php index c6fe27580..d95c8e588 100644 --- a/tests/Controller/Cart/CartPickupApiTest.php +++ b/tests/Controller/Cart/CartPickupApiTest.php @@ -53,6 +53,12 @@ public function it_only_creates_one_cart_if_user_is_logged_in(): void $orders = $orderRepository->findAll(); $this->assertCount(1, $orders, 'Only one cart should be created'); + + /** @var OrderInterface $order */ + $order = $orders[0]; + $customer = $order->getCustomer(); + $this->assertNotNull($customer, 'Cart should have customer assigned, but it has not.'); + $this->assertSame('oliver@queen.com', $customer->getEmail()); } /**