Skip to content

Commit

Permalink
refactor #12512 [API] Fix cart blaming (GSadee, arti0090)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.10-dev branch.

Discussion
----------

| Q               | A
| --------------- | -----
| Branch?         | master
| Bug fix?        | yes?
| New feature?    | no
| BC breaks?      | no
| Deprecations?   | no
| Related tickets | 
| License         | MIT

Based on #12509

Commits
-------

6a525e7 Remove listening for JWT event in CartBlamerListener and use section provider in this listener
87e13c5 [API] Overwrite CartBlamerListener in ApiBundle
34c8357 add new Section class and fix cart blaming
7aaf9d3 move cartBlamerListener to proper bundle
9fd8d13 fix and rename listeners
  • Loading branch information
lchrusciel committed Apr 13, 2021
2 parents 18b1ed4 + 9fd8d13 commit ccf0808
Show file tree
Hide file tree
Showing 10 changed files with 264 additions and 53 deletions.
2 changes: 2 additions & 0 deletions UPGRADE-1.10.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# UPGRADE FROM `v1.9.X` TO `v1.10.0`

1. `Sylius\Bundle\CoreBundle\EventListener\CartBlamerListener` has been moved from CoreBundle to ShopBundle, renamed to `Sylius\Bundle\ShopBundle\EventListener\ShopCartBlamerListener` and adjusted to work properly when decoupled.

### New API

1. API CartShippingMethod key `cost` has been changed to `price`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\EventListener;

use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiOrdersSubSection;
use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface;
use Sylius\Bundle\UserBundle\Event\UserEvent;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\Order\Context\CartContextInterface;
use Sylius\Component\Order\Context\CartNotFoundException;
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

final class ApiCartBlamerListener
{
/** @var CartContextInterface */
private $cartContext;

/** @var SectionProviderInterface */
private $uriBasedSectionContext;

public function __construct(
CartContextInterface $cartContext,
SectionProviderInterface $uriBasedSectionContext
) {
$this->cartContext = $cartContext;
$this->uriBasedSectionContext = $uriBasedSectionContext;
}

public function onImplicitLogin(UserEvent $userEvent): void
{
if (!$this->uriBasedSectionContext->getSection() instanceof ShopApiOrdersSubSection) {
return;
}

$user = $userEvent->getUser();
if (!$user instanceof ShopUserInterface) {
return;
}

$this->blame($user);
}

public function onInteractiveLogin(InteractiveLoginEvent $interactiveLoginEvent): void
{
if (!$this->uriBasedSectionContext->getSection() instanceof ShopApiOrdersSubSection) {
return;
}

$user = $interactiveLoginEvent->getAuthenticationToken()->getUser();
if (!$user instanceof ShopUserInterface) {
return;
}

$this->blame($user);
}

private function blame(ShopUserInterface $user): void
{
$cart = $this->getCart();
if (null === $cart || null !== $cart->getCustomer()) {
return;
}

$cart->setCustomer($user->getCustomer());
}

/**
* @throws UnexpectedTypeException
*/
private function getCart(): ?OrderInterface
{
try {
$cart = $this->cartContext->getCart();
} catch (CartNotFoundException $exception) {
return null;
}

if (!$cart instanceof OrderInterface) {
throw new UnexpectedTypeException($cart, OrderInterface::class);
}

return $cart;
}
}
8 changes: 8 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,15 @@

<service id="sylius.api.section_resolver.shop_api_uri_based_section_resolver" class="Sylius\Bundle\ApiBundle\SectionResolver\ShopApiUriBasedSectionResolver">
<argument>%sylius.security.new_api_shop_route%</argument>
<argument>orders</argument>
<tag name="sylius.uri_based_section_resolver" priority="40" />
</service>

<service id="sylius.listener.api_cart_blamer" class="Sylius\Bundle\ApiBundle\EventListener\ApiCartBlamerListener">
<argument type="service" id="sylius.context.cart" />
<argument type="service" id="sylius.section_resolver.uri_based_section_resolver" />
<tag name="kernel.event_listener" event="sylius.user.security.implicit_login" method="onImplicitLogin" />
<tag name="kernel.event_listener" event="security.interactive_login" method="onInteractiveLogin" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\SectionResolver;

class ShopApiOrdersSubSection extends ShopApiSection
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,25 @@ final class ShopApiUriBasedSectionResolver implements UriBasedSectionResolverInt
/** @var string */
private $shopApiUriBeginning;

public function __construct(string $shopApiUriBeginning)
/** @var string */
private $shopApiOrdersResourceUri;

public function __construct(string $shopApiUriBeginning, string $shopApiOrdersResourceUri)
{
$this->shopApiUriBeginning = $shopApiUriBeginning;
$this->shopApiOrdersResourceUri = $shopApiOrdersResourceUri;
}

public function getSection(string $uri): SectionInterface
{
if (0 === strpos($uri, $this->shopApiUriBeginning)) {
return new ShopApiSection();
if (0 !== strpos($uri, $this->shopApiUriBeginning)) {
throw new SectionCannotBeResolvedException();
}

if (str_contains($uri, $this->shopApiOrdersResourceUri)) {
return new ShopApiOrdersSubSection();
}

throw new SectionCannotBeResolvedException();
return new ShopApiSection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace spec\Sylius\Bundle\ApiBundle\SectionResolver;

use PhpSpec\ObjectBehavior;
use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiOrdersSubSection;
use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiSection;
use Sylius\Bundle\CoreBundle\SectionResolver\SectionCannotBeResolvedException;
use Sylius\Bundle\CoreBundle\SectionResolver\UriBasedSectionResolverInterface;
Expand All @@ -22,7 +23,7 @@ final class ShopApiUriBasedSectionResolverSpec extends ObjectBehavior
{
function let(): void
{
$this->beConstructedWith('/api/v2/shop');
$this->beConstructedWith('/api/v2/shop', 'orders');
}

function it_is_uri_based_section_resolver(): void
Expand All @@ -36,6 +37,11 @@ function it_returns_shop_api_section_if_path_starts_with_api_v2_shop(): void
$this->getSection('/api/v2/shop')->shouldBeLike(new ShopApiSection());
}

function it_returns_shop_api_orders_subsection_if_path_contains_orders(): void
{
$this->getSection('/api/v2/shop/orders')->shouldBeLike(new ShopApiOrdersSubSection());
}

function it_throws_an_exception_if_path_does_not_start_with_api_v2_shop(): void
{
$this->shouldThrow(SectionCannotBeResolvedException::class)->during('getSection', ['/shop']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@
<services>
<defaults public="true" />

<service id="sylius.listener.cart_blamer" class="Sylius\Bundle\CoreBundle\EventListener\CartBlamerListener">
<argument type="service" id="sylius.manager.order" />
<argument type="service" id="sylius.context.cart" />
<tag name="kernel.event_listener" event="sylius.user.security.implicit_login" method="onImplicitLogin" />
<tag name="kernel.event_listener" event="security.interactive_login" method="onInteractiveLogin" />
<tag name="kernel.event_listener" event="lexik_jwt_authentication.on_jwt_authenticated" method="onJWTAuthenticatedLogin" />
</service>
<service id="sylius.listener.channel" class="Sylius\Bundle\CoreBundle\EventListener\ChannelDeletionListener">
<argument type="service" id="sylius.repository.channel" />
<tag name="kernel.event_listener" event="sylius.channel.pre_delete" method="onChannelPreDelete" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

declare(strict_types=1);

namespace Sylius\Bundle\CoreBundle\EventListener;
namespace Sylius\Bundle\ShopBundle\EventListener;

use Doctrine\Persistence\ObjectManager;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent;
use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface;
use Sylius\Bundle\ShopBundle\SectionResolver\ShopSection;
use Sylius\Bundle\UserBundle\Event\UserEvent;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
Expand All @@ -23,22 +23,28 @@
use Sylius\Component\Resource\Exception\UnexpectedTypeException;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

final class CartBlamerListener
final class ShopCartBlamerListener
{
/** @var ObjectManager */
private $cartManager;

/** @var CartContextInterface */
private $cartContext;

public function __construct(ObjectManager $cartManager, CartContextInterface $cartContext)
{
$this->cartManager = $cartManager;
/** @var SectionProviderInterface */
private $uriBasedSectionContext;

public function __construct(
CartContextInterface $cartContext,
SectionProviderInterface $uriBasedSectionContext
) {
$this->cartContext = $cartContext;
$this->uriBasedSectionContext = $uriBasedSectionContext;
}

public function onImplicitLogin(UserEvent $userEvent): void
{
if (!$this->uriBasedSectionContext->getSection() instanceof ShopSection) {
return;
}

$user = $userEvent->getUser();
if (!$user instanceof ShopUserInterface) {
return;
Expand All @@ -49,17 +55,12 @@ public function onImplicitLogin(UserEvent $userEvent): void

public function onInteractiveLogin(InteractiveLoginEvent $interactiveLoginEvent): void
{
$user = $interactiveLoginEvent->getAuthenticationToken()->getUser();
if (!$user instanceof ShopUserInterface) {
$section = $this->uriBasedSectionContext->getSection();
if (!$section instanceof ShopSection) {
return;
}

$this->blame($user);
}

public function onJWTAuthenticatedLogin(JWTAuthenticatedEvent $event): void
{
$user = $event->getToken()->getUser();
$user = $interactiveLoginEvent->getAuthenticationToken()->getUser();
if (!$user instanceof ShopUserInterface) {
return;
}
Expand All @@ -70,13 +71,11 @@ public function onJWTAuthenticatedLogin(JWTAuthenticatedEvent $event): void
private function blame(ShopUserInterface $user): void
{
$cart = $this->getCart();
if (null === $cart) {
if (null === $cart || null !== $cart->getCustomer()) {
return;
}

$cart->setCustomer($user->getCustomer());
$this->cartManager->persist($cart);
$this->cartManager->flush();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
<services>
<defaults public="true" />

<service id="sylius.listener.shop_cart_blamer" class="Sylius\Bundle\ShopBundle\EventListener\ShopCartBlamerListener">
<argument type="service" id="sylius.context.cart" />
<argument type="service" id="sylius.section_resolver.uri_based_section_resolver" />
<tag name="kernel.event_listener" event="sylius.user.security.implicit_login" method="onImplicitLogin" />
<tag name="kernel.event_listener" event="security.interactive_login" method="onInteractiveLogin" />
</service>

<service id="sylius.listener.email_updater" class="Sylius\Bundle\ShopBundle\EventListener\CustomerEmailUpdaterListener">
<argument type="service" id="sylius.shop_user.token_generator.email_verification" />
<argument type="service" id="sylius.context.channel" />
Expand Down
Loading

0 comments on commit ccf0808

Please sign in to comment.