Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PISHPS-311: added custom event and cart collector for subscriptions #801

Merged
merged 3 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/Event/MollieSubscriptionCartItemAddedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Event;

use Shopware\Core\Checkout\Cart\LineItem\LineItem as CheckoutCartLineItem;
use Shopware\Core\System\SalesChannel\SalesChannelContext;

/**
* Class MollieSubscriptionCartItemAddedEvent
*
* This event is triggered when a product with a Mollie subscription is added to the cart.
*/
class MollieSubscriptionCartItemAddedEvent
{
/**
* @var SalesChannelContext
*/
private $context;

/**
* @var CheckoutCartLineItem
*/
private $lineItem;

/**
* MollieSubscriptionCartItemAddedEvent constructor.
*
* @param SalesChannelContext $context The sales channel context
* @param CheckoutCartLineItem $lineItem The line item added to the cart
*/
public function __construct(SalesChannelContext $context, CheckoutCartLineItem $lineItem)
{
$this->context = $context;
$this->lineItem = $lineItem;
}

/**
* Get the sales channel context.
*
* @return SalesChannelContext The sales channel context
*/
public function getSalesChannelContext(): SalesChannelContext
{
return $this->context;
}

/**
* Get the line item that was added to the cart.
*
* @return CheckoutCartLineItem The line item added to the cart
*/
public function getLineItem(): CheckoutCartLineItem
{
return $this->lineItem;
}
}
6 changes: 6 additions & 0 deletions src/Resources/config/services/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@
<argument type="service" id="mollie_payments.logger"/>
</service>

<service id="Kiener\MolliePayments\Service\Cart\Subscription\SubscriptionCartCollector">
<tag name="shopware.cart.collector" priority="1999" />
<argument type="service" id="event_dispatcher"/>
</service>


<service id="Kiener\MolliePayments\Service\Cart\Voucher\VoucherCartCollector">
<argument type="service" id="Kiener\MolliePayments\Service\Voucher\VoucherService"/>
<argument type="service" id="Kiener\MolliePayments\Repository\PaymentMethod\PaymentMethodRepository"/>
Expand Down
56 changes: 56 additions & 0 deletions src/Service/Cart/Subscription/SubscriptionCartCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Service\Cart\Subscription;

use Kiener\MolliePayments\Event\MollieSubscriptionCartItemAddedEvent;
use Kiener\MolliePayments\Struct\LineItem\LineItemAttributes;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartBehavior;
use Shopware\Core\Checkout\Cart\CartDataCollectorInterface;
use Shopware\Core\Checkout\Cart\LineItem\CartDataCollection;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
* Class SubscriptionCartCollector
*
* This class is responsible for collecting subscription products added to the cart
* and dispatching corresponding events.
*/
class SubscriptionCartCollector implements CartDataCollectorInterface
{
/**
* @var EventDispatcherInterface
*/
private $dispatcher;

/**
* SubscriptionCartCollector constructor.
*
* @param EventDispatcherInterface $dispatcher The event dispatcher
*/
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}

/**
* Collects subscription line items from the cart and dispatches events for each subscription product added.
*
* @param CartDataCollection $data The cart data collection
* @param Cart $original The original cart
* @param SalesChannelContext $context The sales channel context
* @param CartBehavior $behavior The cart behavior
*/
public function collect(CartDataCollection $data, Cart $original, SalesChannelContext $context, CartBehavior $behavior): void
{
$events = [];
foreach ($original->getLineItems() as $lineItem) {
if ((new LineItemAttributes($lineItem))->isSubscriptionProduct()) {
$events[] = new MollieSubscriptionCartItemAddedEvent($context, $lineItem);
}
}
array_map([$this->dispatcher, 'dispatch'], $events);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);

namespace MolliePayments\Tests\Service\Cart\Subscription;


use Kiener\MolliePayments\Event\MollieSubscriptionCartItemAddedEvent;
use Kiener\MolliePayments\Service\Cart\Subscription\SubscriptionCartCollector;
use Kiener\MolliePayments\Service\Cart\Subscription\SubscriptionProductIdentifier;
use PHPUnit\Framework\TestCase;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\CartBehavior;
use Shopware\Core\Checkout\Cart\LineItem\CartDataCollection;
use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Shopware\Core\Checkout\Cart\LineItem\LineItem as CheckoutCartLineItem;

class SubscriptionCartCollectorTest extends TestCase
{
const SUBSCRIPTION_ENABLED = 'mollie_payments_product_subscription_enabled';
private $dispatcher;
private $collector;
private $data;

protected function setUp(): void
{
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
$this->collector = new SubscriptionCartCollector($this->dispatcher);
$this->data = $this->createMock(CartDataCollection::class);
$this->original = $this->createMock(Cart::class);
$this->context = $this->createMock(SalesChannelContext::class);
$this->behavior = $this->createMock(CartBehavior::class);
}

public function testDispatchesEventWhenAProductIsAMollieSubscriptionProduct(): void
{
// this will cause the line item to be considered a subscription product and trigger the event
$subscriptionProduct = $this->createLineItemMockWithPayloadValue([self::SUBSCRIPTION_ENABLED => true,]);

// this will cause the line item to be considered a regular product and not trigger the event
$regularProduct = $this->createLineItemMockWithPayloadValue([self::SUBSCRIPTION_ENABLED => false,]);

$this->configureGetLineItemsMethodOfCart($subscriptionProduct, $regularProduct);

// we expect the event to be dispatched only once
$this->dispatcher->expects($this->once())
->method('dispatch')
->with($this->isInstanceOf(MollieSubscriptionCartItemAddedEvent::class));

$this->collector->collect($this->data, $this->original, $this->context, $this->behavior);
}

public function testDoesNotDispatchEventWhenNoMollieSubscriptionProductIsAdded(): void
{
// this will cause the line item to be considered a regular product and not trigger the event
$regularProduct = $this->createLineItemMockWithPayloadValue([self::SUBSCRIPTION_ENABLED => false,]);

$this->configureGetLineItemsMethodOfCart($regularProduct);

// we expect the event to not be dispatched
$this->dispatcher->expects($this->never())->method('dispatch');

$this->collector->collect($this->data, $this->original, $this->context, $this->behavior);
}

private function createLineItemMockWithPayloadValue($value): CheckoutCartLineItem
{
return (new CheckoutCartLineItem(
Uuid::randomBytes(),
'product'
))->setPayload(['customFields' => $value]);
}

private function configureGetLineItemsMethodOfCart(CheckoutCartLineItem ...$items): void
{
$this->original->method('getLineItems')->willReturn(new LineItemCollection($items));
}
}
Loading