vendor/shopware/core/Checkout/Customer/Subscriber/CustomerMetaFieldSubscriber.php line 53

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Checkout\Customer\Subscriber;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Checkout\Order\OrderDefinition;
  5. use Shopware\Core\Checkout\Order\OrderStates;
  6. use Shopware\Core\Defaults;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\RetryableQuery;
  8. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\DeleteCommand;
  9. use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
  10. use Shopware\Core\Framework\Uuid\Uuid;
  11. use Shopware\Core\System\StateMachine\Event\StateMachineTransitionEvent;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. class CustomerMetaFieldSubscriber implements EventSubscriberInterface
  14. {
  15.     private Connection $connection;
  16.     /**
  17.      * @internal
  18.      */
  19.     public function __construct(Connection $connection)
  20.     {
  21.         $this->connection $connection;
  22.     }
  23.     public static function getSubscribedEvents(): array
  24.     {
  25.         return [
  26.             StateMachineTransitionEvent::class => 'fillCustomerMetaDataFields',
  27.             PreWriteValidationEvent::class => 'deleteOrder',
  28.         ];
  29.     }
  30.     public function fillCustomerMetaDataFields(StateMachineTransitionEvent $event): void
  31.     {
  32.         if ($event->getContext()->getVersionId() !== Defaults::LIVE_VERSION) {
  33.             return;
  34.         }
  35.         if ($event->getEntityName() !== 'order') {
  36.             return;
  37.         }
  38.         if ($event->getToPlace()->getTechnicalName() !== OrderStates::STATE_COMPLETED && $event->getFromPlace()->getTechnicalName() !== OrderStates::STATE_COMPLETED) {
  39.             return;
  40.         }
  41.         $this->updateCustomer([$event->getEntityId()]);
  42.     }
  43.     public function deleteOrder(PreWriteValidationEvent $event): void
  44.     {
  45.         if ($event->getContext()->getVersionId() !== Defaults::LIVE_VERSION) {
  46.             return;
  47.         }
  48.         $orderIds = [];
  49.         foreach ($event->getCommands() as $command) {
  50.             if ($command->getDefinition()->getClass() === OrderDefinition::class
  51.                 && $command instanceof DeleteCommand
  52.             ) {
  53.                 $orderIds[] = Uuid::fromBytesToHex($command->getPrimaryKey()['id']);
  54.             }
  55.         }
  56.         $this->updateCustomer($orderIdstrue);
  57.     }
  58.     private function updateCustomer(array $orderIdsbool $isDelete false): void
  59.     {
  60.         if (empty($orderIds)) {
  61.             return;
  62.         }
  63.         $customerIds $this->connection->fetchFirstColumn(
  64.             'SELECT DISTINCT LOWER(HEX(customer_id)) FROM `order_customer` WHERE order_id IN (:ids) AND order_version_id = :version AND customer_id IS NOT NULL',
  65.             ['ids' => Uuid::fromHexToBytesList($orderIds), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)],
  66.             ['ids' => Connection::PARAM_STR_ARRAY]
  67.         );
  68.         if (empty($customerIds)) {
  69.             return;
  70.         }
  71.         $whereOrder $isDelete 'AND `order`.id NOT IN (:exceptOrderIds)' '';
  72.         $select '
  73.             SELECT `order_customer`.customer_id as id,
  74.                    COUNT(`order`.id) as order_count,
  75.                    SUM(`order`.amount_total) as order_total_amount,
  76.                    MAX(`order`.order_date_time) as last_order_date
  77.             FROM `order_customer`
  78.             INNER JOIN `order`
  79.                 ON `order`.id = `order_customer`.order_id
  80.                 AND `order`.version_id = `order_customer`.order_version_id
  81.                 AND `order`.version_id = :version
  82.                 ' $whereOrder '
  83.             INNER JOIN `state_machine_state`
  84.                 ON `state_machine_state`.id = `order`.state_id
  85.                 AND `state_machine_state`.technical_name = :state
  86.             WHERE `order_customer`.customer_id IN (:customerIds)
  87.             GROUP BY `order_customer`.customer_id
  88.         ';
  89.         $data $this->connection->fetchAllAssociative($select, [
  90.             'customerIds' => Uuid::fromHexToBytesList($customerIds),
  91.             'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION),
  92.             'state' => OrderStates::STATE_COMPLETED,
  93.             'exceptOrderIds' => Uuid::fromHexToBytesList($orderIds),
  94.         ], [
  95.             'customerIds' => Connection::PARAM_STR_ARRAY,
  96.             'exceptOrderIds' => Connection::PARAM_STR_ARRAY,
  97.         ]);
  98.         if (empty($data)) {
  99.             foreach ($customerIds as $customerId) {
  100.                 $data[] = [
  101.                     'id' => Uuid::fromHexToBytes($customerId),
  102.                     'order_count' => 0,
  103.                     'order_total_amount' => 0,
  104.                     'last_order_date' => null,
  105.                 ];
  106.             }
  107.         }
  108.         $update = new RetryableQuery(
  109.             $this->connection,
  110.             $this->connection->prepare('UPDATE `customer` SET order_count = :order_count, order_total_amount = :order_total_amount, last_order_date = :last_order_date WHERE id = :id')
  111.         );
  112.         foreach ($data as $record) {
  113.             $update->execute($record);
  114.         }
  115.     }
  116. }