platform/src/Core/Checkout/Promotion/DataAbstractionLayer/PromotionRedemptionUpdater.php line 83

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