-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PISHPS-311: added custom event and cart collector for subscriptions
- Loading branch information
1 parent
b2b7361
commit 9e1fa93
Showing
4 changed files
with
232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
src/Service/Cart/Subscription/SubscriptionCartCollector.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Kiener\MolliePayments\Service\Cart\Subscription; | ||
|
||
use Kiener\MolliePayments\Event\MollieSubscriptionCartItemAddedEvent; | ||
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\Checkout\Cart\LineItem\LineItem as CheckoutCartLineItem; | ||
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 | ||
{ | ||
private const SUBSCRIPTION_ENABLED = 'mollie_payments_product_subscription_enabled'; | ||
|
||
/** | ||
* @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 ($this->lineItemIsSubscriptionProduct($lineItem)) { | ||
$events[] = new MollieSubscriptionCartItemAddedEvent($context, $lineItem); | ||
} | ||
} | ||
array_map([$this->dispatcher, 'dispatch'], $events); | ||
} | ||
|
||
/** | ||
* Checks if a line item is a subscription product. | ||
* | ||
* @param CheckoutCartLineItem $lineItem The line item to check | ||
* @return bool True if the line item is a subscription product, false otherwise | ||
*/ | ||
private function lineItemIsSubscriptionProduct(CheckoutCartLineItem $lineItem): bool | ||
{ | ||
$customFields = $lineItem->getPayloadValue('customFields'); | ||
|
||
if (is_array($customFields) === false || isset($customFields[self::SUBSCRIPTION_ENABLED]) === false) { | ||
return false; | ||
} | ||
|
||
return (bool)$customFields[self::SUBSCRIPTION_ENABLED]; | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
tests/PHPUnit/Service/Cart/Subscription/SubscriptionCartCollectorTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace MolliePayments\Tests\Service\Cart\Subscription; | ||
|
||
|
||
use Kiener\MolliePayments\Event\MollieSubscriptionCartItemAddedEvent; | ||
use Kiener\MolliePayments\Service\Cart\Subscription\SubscriptionCartCollector; | ||
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\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); | ||
} | ||
|
||
public function testDoesNotDispatchEventWhenCustomFieldsIsMissingSubscriptionData(): void | ||
{ | ||
$incorrectlyConfiguredProduct = $this->createLineItemMockWithPayloadValue((object)[self::SUBSCRIPTION_ENABLED => false,]); | ||
|
||
$this->configureGetLineItemsMethodOfCart($incorrectlyConfiguredProduct); | ||
|
||
// 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 $this->createConfiguredMock( | ||
CheckoutCartLineItem::class, | ||
[ | ||
'getPayloadValue' => $value | ||
] | ||
); | ||
} | ||
|
||
private function configureGetLineItemsMethodOfCart(CheckoutCartLineItem ...$items): void | ||
{ | ||
$this->original->method('getLineItems')->willReturn(new LineItemCollection($items)); | ||
} | ||
} |