vendor/shopware/core/Content/Flow/Dispatching/Action/SetOrderStateAction.php line 68

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Flow\Dispatching\Action;
  3. use Doctrine\DBAL\Connection;
  4. use Psr\Log\LoggerInterface;
  5. use Shopware\Core\Checkout\Order\SalesChannel\OrderService;
  6. use Shopware\Core\Framework\Context;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Dbal\EntityDefinitionQueryHelper;
  8. use Shopware\Core\Framework\Event\DelayAware;
  9. use Shopware\Core\Framework\Event\FlowEvent;
  10. use Shopware\Core\Framework\Event\OrderAware;
  11. use Shopware\Core\Framework\ShopwareHttpException;
  12. use Shopware\Core\Framework\Uuid\Uuid;
  13. use Shopware\Core\System\StateMachine\Exception\IllegalTransitionException;
  14. use Shopware\Core\System\StateMachine\Exception\StateMachineNotFoundException;
  15. use Symfony\Component\HttpFoundation\ParameterBag;
  16. class SetOrderStateAction extends FlowAction
  17. {
  18.     public const FORCE_TRANSITION 'force_transition';
  19.     private const ORDER 'order';
  20.     private const ORDER_DELIVERY 'order_delivery';
  21.     private const ORDER_TRANSACTION 'order_transaction';
  22.     private Connection $connection;
  23.     private LoggerInterface $logger;
  24.     private OrderService $orderService;
  25.     /**
  26.      * @internal
  27.      */
  28.     public function __construct(
  29.         Connection $connection,
  30.         LoggerInterface $logger,
  31.         OrderService $orderService
  32.     ) {
  33.         $this->connection $connection;
  34.         $this->logger $logger;
  35.         $this->orderService $orderService;
  36.     }
  37.     public static function getName(): string
  38.     {
  39.         return 'action.set.order.state';
  40.     }
  41.     /**
  42.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  43.      */
  44.     public static function getSubscribedEvents()
  45.     {
  46.         return [
  47.             self::getName() => 'handle',
  48.         ];
  49.     }
  50.     public function requirements(): array
  51.     {
  52.         return [OrderAware::class, DelayAware::class];
  53.     }
  54.     public function handle(FlowEvent $event): void
  55.     {
  56.         $config $event->getConfig();
  57.         if (empty($config)) {
  58.             return;
  59.         }
  60.         $baseEvent $event->getEvent();
  61.         if (!$baseEvent instanceof OrderAware) {
  62.             return;
  63.         }
  64.         $context $baseEvent->getContext();
  65.         if ($config[self::FORCE_TRANSITION] ?? false) {
  66.             $context->addState(self::FORCE_TRANSITION);
  67.         }
  68.         $this->connection->beginTransaction();
  69.         try {
  70.             $orderId $baseEvent->getOrderId();
  71.             $transitions array_filter([
  72.                 self::ORDER => $config[self::ORDER] ?? null,
  73.                 self::ORDER_DELIVERY => $config[self::ORDER_DELIVERY] ?? null,
  74.                 self::ORDER_TRANSACTION => $config[self::ORDER_TRANSACTION] ?? null,
  75.             ]);
  76.             foreach ($transitions as $machine => $toPlace) {
  77.                 $this->transitState((string) $machine$orderId, (string) $toPlace$context);
  78.             }
  79.             $this->connection->commit();
  80.         } catch (ShopwareHttpException $e) {
  81.             $this->connection->rollBack();
  82.             $this->logger->error($e->getMessage());
  83.         } finally {
  84.             $context->removeState(self::FORCE_TRANSITION);
  85.         }
  86.     }
  87.     /**
  88.      * @throws IllegalTransitionException
  89.      * @throws StateMachineNotFoundException
  90.      */
  91.     private function transitState(string $machinestring $orderIdstring $toPlaceContext $context): void
  92.     {
  93.         if (!$toPlace) {
  94.             return;
  95.         }
  96.         $data = new ParameterBag();
  97.         $machineId $machine === self::ORDER $orderId $this->getMachineId($machine$orderId);
  98.         if (!$machineId) {
  99.             throw new StateMachineNotFoundException($machine);
  100.         }
  101.         $actionName $this->getAvailableActionName($machine$machineId$toPlace);
  102.         if (!$actionName) {
  103.             $actionName $toPlace;
  104.         }
  105.         switch ($machine) {
  106.             case self::ORDER:
  107.                 $this->orderService->orderStateTransition($orderId$actionName$data$context);
  108.                 return;
  109.             case self::ORDER_DELIVERY:
  110.                 $this->orderService->orderDeliveryStateTransition($machineId$actionName$data$context);
  111.                 return;
  112.             case self::ORDER_TRANSACTION:
  113.                 $this->orderService->orderTransactionStateTransition($machineId$actionName$data$context);
  114.                 return;
  115.             default:
  116.                 throw new StateMachineNotFoundException($machine);
  117.         }
  118.     }
  119.     private function getMachineId(string $machinestring $orderId): ?string
  120.     {
  121.         $query $this->connection->createQueryBuilder();
  122.         $query->select('LOWER(HEX(id))');
  123.         $query->from($machine);
  124.         $query->where('`order_id` = :id');
  125.         $query->setParameter('id'Uuid::fromHexToBytes($orderId));
  126.         return $query->execute()->fetchOne() ?: null;
  127.     }
  128.     private function getAvailableActionName(string $machinestring $machineIdstring $toPlace): ?string
  129.     {
  130.         $query $this->connection->createQueryBuilder();
  131.         $query->select('action_name');
  132.         $query->from('state_machine_transition');
  133.         $query->where('from_state_id = :fromStateId');
  134.         $query->andWhere('to_state_id = :toPlaceId');
  135.         $query->setParameters([
  136.             'fromStateId' => $this->getFromPlaceId($machine$machineId),
  137.             'toPlaceId' => $this->getToPlaceId($toPlace$machine),
  138.         ]);
  139.         return $query->execute()->fetchOne() ?: null;
  140.     }
  141.     private function getToPlaceId(string $toPlacestring $machine): ?string
  142.     {
  143.         $query $this->connection->createQueryBuilder();
  144.         $query->select('id');
  145.         $query->from('state_machine_state');
  146.         $query->where('technical_name = :toPlace');
  147.         $query->andWhere('state_machine_id = :stateMachineId');
  148.         $query->setParameters([
  149.             'toPlace' => $toPlace,
  150.             'stateMachineId' => $this->getStateMachineId($machine),
  151.         ]);
  152.         return $query->execute()->fetchOne() ?: null;
  153.     }
  154.     private function getFromPlaceId(string $machinestring $machineId): ?string
  155.     {
  156.         $escaped EntityDefinitionQueryHelper::escape($machine);
  157.         $query $this->connection->createQueryBuilder();
  158.         $query->select('state_id');
  159.         $query->from($escaped);
  160.         $query->where('id = :id');
  161.         $query->setParameter('id'Uuid::fromHexToBytes($machineId));
  162.         return $query->execute()->fetchOne() ?: null;
  163.     }
  164.     private function getStateMachineId(string $machine): ?string
  165.     {
  166.         $query $this->connection->createQueryBuilder();
  167.         $query->select('id');
  168.         $query->from('state_machine');
  169.         $query->where('technical_name = :technicalName');
  170.         $query->setParameter('technicalName'$machine '.state');
  171.         return $query->execute()->fetchOne() ?: null;
  172.     }
  173. }