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

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\Promotion\Cart\PromotionProcessor;
  6. use Shopware\Core\Defaults;
  7. use Shopware\Core\Framework\Context;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\RetryableQuery;
  9. use Shopware\Core\Framework\Uuid\Uuid;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. class PromotionRedemptionUpdater implements EventSubscriberInterface
  12. {
  13.     /**
  14.      * @var Connection
  15.      */
  16.     private $connection;
  17.     public function __construct(Connection $connection)
  18.     {
  19.         $this->connection $connection;
  20.     }
  21.     /**
  22.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  23.      */
  24.     public static function getSubscribedEvents()
  25.     {
  26.         return [
  27.             CheckoutOrderPlacedEvent::class => 'orderPlaced',
  28.         ];
  29.     }
  30.     public function update(array $idsContext $context): void
  31.     {
  32.         $ids array_unique(array_filter($ids));
  33.         if (empty($ids) || $context->getVersionId() !== Defaults::LIVE_VERSION) {
  34.             return;
  35.         }
  36.         $sql = <<<'SQL'
  37.                 SELECT JSON_UNQUOTE(JSON_EXTRACT(`order_line_item`.`payload`, '$.promotionId')) as promotion_id,
  38.                        COUNT(DISTINCT order_line_item.id) as total,
  39.                        LOWER(HEX(order_customer.customer_id)) as customer_id
  40.                 FROM order_line_item
  41.                 INNER JOIN order_customer
  42.                     ON order_customer.order_id = order_line_item.order_id
  43.                     AND order_customer.version_id = order_line_item.version_id
  44.                 WHERE order_line_item.type = :type
  45.                 AND JSON_UNQUOTE(JSON_EXTRACT(`order_line_item`.`payload`, "$.promotionId")) IN (:ids)
  46.                 AND order_line_item.version_id = :versionId
  47.                 GROUP BY JSON_UNQUOTE(JSON_EXTRACT(`order_line_item`.`payload`, "$.promotionId")), order_customer.customer_id
  48. SQL;
  49.         $promotions $this->connection->fetchAll(
  50.             $sql,
  51.             ['type' => PromotionProcessor::LINE_ITEM_TYPE'ids' => $ids'versionId' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  52.             ['ids' => Connection::PARAM_STR_ARRAY]
  53.         );
  54.         if (empty($promotions)) {
  55.             return;
  56.         }
  57.         $update = new RetryableQuery(
  58.             $this->connection,
  59.             $this->connection->prepare('UPDATE promotion SET order_count = :count, orders_per_customer_count = :customerCount WHERE id = :id')
  60.         );
  61.         // group the promotions to update each promotion with a single update statement
  62.         $promotions $this->groupByPromotion($promotions);
  63.         foreach ($promotions as $id => $totals) {
  64.             $total array_sum($totals);
  65.             $update->execute([
  66.                 'id' => Uuid::fromHexToBytes($id),
  67.                 'count' => (int) $total,
  68.                 'customerCount' => json_encode($totals),
  69.             ]);
  70.         }
  71.     }
  72.     public function orderPlaced(CheckoutOrderPlacedEvent $event): void
  73.     {
  74.         $lineItems $event->getOrder()->getLineItems();
  75.         if (!$lineItems) {
  76.             return;
  77.         }
  78.         $promotionIds $lineItems
  79.             ->filterByType(PromotionProcessor::LINE_ITEM_TYPE)
  80.             ->getPayloadsProperty('promotionId');
  81.         // update redemption counts immediately
  82.         $this->update($promotionIds$event->getContext());
  83.     }
  84.     private function groupByPromotion(array $promotions): array
  85.     {
  86.         $grouped = [];
  87.         foreach ($promotions as $promotion) {
  88.             $id $promotion['promotion_id'];
  89.             $customerId $promotion['customer_id'];
  90.             $grouped[$id][$customerId] = (int) $promotion['total'];
  91.         }
  92.         return $grouped;
  93.     }
  94. }