<?php declare(strict_types=1);namespace Shopware\Core\Checkout\Customer\Subscriber;use Doctrine\DBAL\Connection;use Shopware\Core\Checkout\Order\OrderDefinition;use Shopware\Core\Checkout\Order\OrderStates;use Shopware\Core\Defaults;use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\RetryableQuery;use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\DeleteCommand;use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;use Shopware\Core\Framework\Log\Package;use Shopware\Core\Framework\Uuid\Uuid;use Shopware\Core\System\StateMachine\Event\StateMachineTransitionEvent;use Symfony\Component\EventDispatcher\EventSubscriberInterface;/** * @deprecated tag:v6.5.0 - reason:becomes-internal - EventSubscribers will become internal in v6.5.0 */#[Package('customer-order')]class CustomerMetaFieldSubscriber implements EventSubscriberInterface{ private Connection $connection; /** * @internal */ public function __construct(Connection $connection) { $this->connection = $connection; } public static function getSubscribedEvents(): array { return [ StateMachineTransitionEvent::class => 'fillCustomerMetaDataFields', PreWriteValidationEvent::class => 'deleteOrder', ]; } public function fillCustomerMetaDataFields(StateMachineTransitionEvent $event): void { if ($event->getContext()->getVersionId() !== Defaults::LIVE_VERSION) { return; } if ($event->getEntityName() !== 'order') { return; } if ($event->getToPlace()->getTechnicalName() !== OrderStates::STATE_COMPLETED && $event->getFromPlace()->getTechnicalName() !== OrderStates::STATE_COMPLETED) { return; } $this->updateCustomer([$event->getEntityId()]); } public function deleteOrder(PreWriteValidationEvent $event): void { if ($event->getContext()->getVersionId() !== Defaults::LIVE_VERSION) { return; } $orderIds = []; foreach ($event->getCommands() as $command) { if ($command->getDefinition()->getClass() === OrderDefinition::class && $command instanceof DeleteCommand ) { $orderIds[] = Uuid::fromBytesToHex($command->getPrimaryKey()['id']); } } $this->updateCustomer($orderIds, true); } /** * @param array<string> $orderIds */ private function updateCustomer(array $orderIds, bool $isDelete = false): void { if (empty($orderIds)) { return; } $customerIds = $this->connection->fetchFirstColumn( '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', ['ids' => Uuid::fromHexToBytesList($orderIds), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION)], ['ids' => Connection::PARAM_STR_ARRAY] ); if (empty($customerIds)) { return; } $parameters = [ 'customerIds' => Uuid::fromHexToBytesList($customerIds), 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION), 'state' => OrderStates::STATE_COMPLETED, ]; $types = [ 'customerIds' => Connection::PARAM_STR_ARRAY, ]; $whereOrder = ''; if ($isDelete) { $whereOrder = 'AND `order`.id NOT IN (:exceptOrderIds)'; $parameters['exceptOrderIds'] = Uuid::fromHexToBytesList($orderIds); $types['exceptOrderIds'] = Connection::PARAM_STR_ARRAY; } $select = ' SELECT `order_customer`.customer_id as id, COUNT(`order`.id) as order_count, SUM(`order`.amount_total) as order_total_amount, MAX(`order`.order_date_time) as last_order_date FROM `order_customer` INNER JOIN `order` ON `order`.id = `order_customer`.order_id AND `order`.version_id = `order_customer`.order_version_id AND `order`.version_id = :version ' . $whereOrder . ' INNER JOIN `state_machine_state` ON `state_machine_state`.id = `order`.state_id AND `state_machine_state`.technical_name = :state WHERE `order_customer`.customer_id IN (:customerIds) GROUP BY `order_customer`.customer_id '; $data = $this->connection->fetchAllAssociative($select, $parameters, $types); if (empty($data)) { foreach ($customerIds as $customerId) { $data[] = [ 'id' => Uuid::fromHexToBytes($customerId), 'order_count' => 0, 'order_total_amount' => 0, 'last_order_date' => null, ]; } } $update = new RetryableQuery( $this->connection, $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') ); foreach ($data as $record) { $update->execute($record); } }}