vendor/shopware/core/Checkout/Promotion/DataAbstractionLayer/PromotionRedemptionUpdater.php line 95

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Checkout\Promotion\DataAbstractionLayer;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  5. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
  6. use Shopware\Core\Checkout\Promotion\Cart\PromotionProcessor;
  7. use Shopware\Core\Defaults;
  8. use Shopware\Core\Framework\Context;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\RetryableQuery;
  10. use Shopware\Core\Framework\Log\Package;
  11. use Shopware\Core\Framework\Uuid\Uuid;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. /**
  14.  * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0
  15.  */
  16. #[Package('core')]
  17. class PromotionRedemptionUpdater implements EventSubscriberInterface
  18. {
  19.     private Connection $connection;
  20.     /**
  21.      * @internal
  22.      */
  23.     public function __construct(Connection $connection)
  24.     {
  25.         $this->connection $connection;
  26.     }
  27.     /**
  28.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  29.      */
  30.     public static function getSubscribedEvents()
  31.     {
  32.         return [
  33.             CheckoutOrderPlacedEvent::class => 'orderPlaced',
  34.         ];
  35.     }
  36.     /**
  37.      * @param array<string> $ids
  38.      */
  39.     public function update(array $idsContext $context): void
  40.     {
  41.         $ids array_unique(array_filter($ids));
  42.         if (empty($ids) || $context->getVersionId() !== Defaults::LIVE_VERSION) {
  43.             return;
  44.         }
  45.         $sql = <<<'SQL'
  46.                 SELECT LOWER(HEX(order_line_item.promotion_id)) as promotion_id,
  47.                        COUNT(DISTINCT order_line_item.id) as total,
  48.                        LOWER(HEX(order_customer.customer_id)) as customer_id
  49.                 FROM order_line_item
  50.                 INNER JOIN order_customer
  51.                     ON order_customer.order_id = order_line_item.order_id
  52.                     AND order_customer.version_id = order_line_item.version_id
  53.                 WHERE order_line_item.type = :type
  54.                 AND order_line_item.promotion_id IN (:ids)
  55.                 AND order_line_item.version_id = :versionId
  56.                 GROUP BY order_line_item.promotion_id, order_customer.customer_id
  57. SQL;
  58.         $promotions $this->connection->fetchAllAssociative(
  59.             $sql,
  60.             ['type' => PromotionProcessor::LINE_ITEM_TYPE'ids' => Uuid::fromHexToBytesList($ids), 'versionId' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  61.             ['ids' => Connection::PARAM_STR_ARRAY]
  62.         );
  63.         if (empty($promotions)) {
  64.             return;
  65.         }
  66.         $update = new RetryableQuery(
  67.             $this->connection,
  68.             $this->connection->prepare('UPDATE promotion SET order_count = :count, orders_per_customer_count = :customerCount WHERE id = :id')
  69.         );
  70.         // group the promotions to update each promotion with a single update statement
  71.         $promotions $this->groupByPromotion($promotions);
  72.         foreach ($promotions as $id => $totals) {
  73.             $total array_sum($totals);
  74.             $update->execute([
  75.                 'id' => Uuid::fromHexToBytes($id),
  76.                 'count' => (int) $total,
  77.                 'customerCount' => json_encode($totals),
  78.             ]);
  79.         }
  80.     }
  81.     public function orderPlaced(CheckoutOrderPlacedEvent $event): void
  82.     {
  83.         $lineItems $event->getOrder()->getLineItems();
  84.         $customer $event->getOrder()->getOrderCustomer();
  85.         if (!$lineItems || !$customer) {
  86.             return;
  87.         }
  88.         $promotionIds = [];
  89.         /** @var OrderLineItemEntity $lineItem */
  90.         foreach ($lineItems as $lineItem) {
  91.             if ($lineItem->getType() !== PromotionProcessor::LINE_ITEM_TYPE) {
  92.                 continue;
  93.             }
  94.             $promotionId $lineItem->getPromotionId();
  95.             if ($promotionId === null) {
  96.                 continue;
  97.             }
  98.             $promotionIds[] = $promotionId;
  99.         }
  100.         if (!$promotionIds) {
  101.             return;
  102.         }
  103.         $allCustomerCounts $this->getAllCustomerCounts($promotionIds);
  104.         $update = new RetryableQuery(
  105.             $this->connection,
  106.             $this->connection->prepare('UPDATE promotion SET order_count = order_count + 1, orders_per_customer_count = :customerCount WHERE id = :id')
  107.         );
  108.         foreach ($promotionIds as $promotionId) {
  109.             $customerId $customer->getCustomerId();
  110.             if ($customerId !== null) {
  111.                 $allCustomerCounts[$promotionId][$customerId] = + ($allCustomerCounts[$promotionId][$customerId] ?? 0);
  112.             }
  113.             $update->execute([
  114.                 'id' => Uuid::fromHexToBytes($promotionId),
  115.                 'customerCount' => json_encode($allCustomerCounts[$promotionId]),
  116.             ]);
  117.         }
  118.     }
  119.     /**
  120.      * @param array<mixed> $promotions
  121.      *
  122.      * @return array<mixed>
  123.      */
  124.     private function groupByPromotion(array $promotions): array
  125.     {
  126.         $grouped = [];
  127.         foreach ($promotions as $promotion) {
  128.             $id $promotion['promotion_id'];
  129.             $customerId $promotion['customer_id'];
  130.             $grouped[$id][$customerId] = (int) $promotion['total'];
  131.         }
  132.         return $grouped;
  133.     }
  134.     /**
  135.      * @param array<string> $promotionIds
  136.      *
  137.      * @return array<string>
  138.      */
  139.     private function getAllCustomerCounts(array $promotionIds): array
  140.     {
  141.         $allCustomerCounts = [];
  142.         $countResult $this->connection->fetchAllAssociative(
  143.             'SELECT `id`, `orders_per_customer_count` FROM `promotion` WHERE `id` IN (:ids)',
  144.             ['ids' => Uuid::fromHexToBytesList($promotionIds)],
  145.             ['ids' => Connection::PARAM_STR_ARRAY]
  146.         );
  147.         foreach ($countResult as $row) {
  148.             if (!\is_string($row['orders_per_customer_count'])) {
  149.                 $allCustomerCounts[Uuid::fromBytesToHex($row['id'])] = [];
  150.                 continue;
  151.             }
  152.             $customerCount json_decode($row['orders_per_customer_count'], true);
  153.             if (!$customerCount) {
  154.                 $allCustomerCounts[Uuid::fromBytesToHex($row['id'])] = [];
  155.                 continue;
  156.             }
  157.             $allCustomerCounts[Uuid::fromBytesToHex($row['id'])] = $customerCount;
  158.         }
  159.         return $allCustomerCounts;
  160.     }
  161. }