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

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