<?phpdeclare(strict_types=1);namespace Meteor\PromotionGift\Subscribers;use Meteor\PromotionGift\Checker\LineItemIsFreeGiftInterface;use Meteor\PromotionGift\Core\Checkout\Promotion\Cart\GiftProcessor;use Meteor\PromotionGift\Dal\FetchCustomerCountsForPromotionsInterface;use Meteor\PromotionGift\Dal\UpdatePromotionCountInterface;use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;use Shopware\Core\Framework\Uuid\Uuid;use Symfony\Component\EventDispatcher\EventSubscriberInterface;class FreeGiftRedemptionUpdater implements EventSubscriberInterface{ private LineItemIsFreeGiftInterface $lineItemIsFreeGift; private FetchCustomerCountsForPromotionsInterface $fetchCustomerCountsForPromotions; private UpdatePromotionCountInterface $updatePromotionCount; public function __construct(LineItemIsFreeGiftInterface $lineItemIsFreeGift, FetchCustomerCountsForPromotionsInterface $fetchCustomerCountsForPromotions, UpdatePromotionCountInterface $updatePromotionCount) { $this->lineItemIsFreeGift = $lineItemIsFreeGift; $this->fetchCustomerCountsForPromotions = $fetchCustomerCountsForPromotions; $this->updatePromotionCount = $updatePromotionCount; } public static function getSubscribedEvents(): array { return [ CheckoutOrderPlacedEvent::class => '__invoke', ]; } public function __invoke(CheckoutOrderPlacedEvent $event): void { $lineItems = $event->getOrder()->getLineItems(); $customer = $event->getOrder()->getOrderCustomer(); if (!$lineItems || !$customer) { return; } $customerId = $customer->getCustomerId(); $promotionIds = []; foreach ($lineItems as $lineItem) { if (!($this->lineItemIsFreeGift)($lineItem)) { continue; } $promotionId = $this->fetchPromotionId($lineItem); if (!$promotionId) { continue; } $promotionIds[] = $promotionId; } if (0 === count($promotionIds)) { return; } $promotionsUsedByCustomersCount = ($this->fetchCustomerCountsForPromotions)($promotionIds); $calculatedPromotionsUsedByCustomer = []; foreach ($promotionIds as $promotionId) { $calculatedPromotionsUsedByCustomer[$promotionId] = $this->calculatePromotionUsedByCustomer( $promotionsUsedByCustomersCount, $promotionId, $customerId ); } ($this->updatePromotionCount)($promotionIds, $calculatedPromotionsUsedByCustomer); } private function calculatePromotionUsedByCustomer(array $allCustomerCounts, $promotionId, $customerId): array { $promotionUsedByCustomers = $allCustomerCounts[$promotionId] ?? null; if (null === $promotionUsedByCustomers) { // Prepare array if code isn't used yet $allCustomerCounts[$promotionId] = []; } $promotionUsedByCurrentCustomer = $promotionUsedByCustomers[$customerId] ?? null; if (null === $promotionUsedByCurrentCustomer) { // initiate count if customer hasn't used promotion yet $promotionUsedByCustomers[$customerId] = 1; return $promotionUsedByCustomers; } // +1 if customer has used this code before $promotionUsedByCustomers[$customerId] = $promotionUsedByCurrentCustomer + 1; return $promotionUsedByCustomers; } private function fetchPromotionId(OrderLineItemEntity $lineItem): ?string { $payload = $lineItem->getPayload(); $payloadPromotionIdKey = $payload[GiftProcessor::PAYLOAD_PROMOTION_ID_KEY] ?? null; if (null === $payloadPromotionIdKey) { return null; } $promotionId = $payload[GiftProcessor::PAYLOAD_PROMOTION_ID_KEY] ?? null; if (!Uuid::isValid((string) $promotionId)) { return null; } return (string) $promotionId; }}