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

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\Content\Flow\Dispatching\DelayableAction;
  7. use Shopware\Core\Content\Flow\Dispatching\StorableFlow;
  8. use Shopware\Core\Defaults;
  9. use Shopware\Core\Framework\Context;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Dbal\EntityDefinitionQueryHelper;
  11. use Shopware\Core\Framework\Event\FlowEvent;
  12. use Shopware\Core\Framework\Event\OrderAware;
  13. use Shopware\Core\Framework\Feature;
  14. use Shopware\Core\Framework\Log\Package;
  15. use Shopware\Core\Framework\ShopwareHttpException;
  16. use Shopware\Core\Framework\Uuid\Uuid;
  17. use Shopware\Core\System\StateMachine\Exception\IllegalTransitionException;
  18. use Shopware\Core\System\StateMachine\Exception\StateMachineNotFoundException;
  19. use Symfony\Component\HttpFoundation\ParameterBag;
  20. /**
  21.  * @deprecated tag:v6.5.0 - reason:remove-subscriber - FlowActions won't be executed over the event system anymore,
  22.  * therefore the actions won't implement the EventSubscriberInterface anymore.
  23.  */
  24. #[Package('business-ops')]
  25. class SetOrderStateAction extends FlowAction implements DelayableAction
  26. {
  27.     public const FORCE_TRANSITION 'force_transition';
  28.     private const ORDER 'order';
  29.     private const ORDER_DELIVERY 'order_delivery';
  30.     private const ORDER_TRANSACTION 'order_transaction';
  31.     private Connection $connection;
  32.     private LoggerInterface $logger;
  33.     private OrderService $orderService;
  34.     /**
  35.      * @internal
  36.      */
  37.     public function __construct(
  38.         Connection $connection,
  39.         LoggerInterface $logger,
  40.         OrderService $orderService
  41.     ) {
  42.         $this->connection $connection;
  43.         $this->logger $logger;
  44.         $this->orderService $orderService;
  45.     }
  46.     public static function getName(): string
  47.     {
  48.         return 'action.set.order.state';
  49.     }
  50.     /**
  51.      * @deprecated tag:v6.5.0 - reason:remove-subscriber - Will be removed
  52.      *
  53.      * @return array<string, string|array{0: string, 1: int}|list<array{0: string, 1?: int}>>
  54.      */
  55.     public static function getSubscribedEvents()
  56.     {
  57.         if (Feature::isActive('v6.5.0.0')) {
  58.             return [];
  59.         }
  60.         return [
  61.             self::getName() => 'handle',
  62.         ];
  63.     }
  64.     /**
  65.      * @return array<int, string>
  66.      */
  67.     public function requirements(): array
  68.     {
  69.         return [OrderAware::class];
  70.     }
  71.     /**
  72.      * @deprecated tag:v6.5.0 Will be removed, implement handleFlow instead
  73.      */
  74.     public function handle(FlowEvent $event): void
  75.     {
  76.         Feature::triggerDeprecationOrThrow(
  77.             'v6.5.0.0',
  78.             Feature::deprecatedMethodMessage(__CLASS____METHOD__'v6.5.0.0')
  79.         );
  80.         $baseEvent $event->getEvent();
  81.         if (!$baseEvent instanceof OrderAware) {
  82.             return;
  83.         }
  84.         $this->update($baseEvent->getContext(), $event->getConfig(), $baseEvent->getOrderId());
  85.     }
  86.     public function handleFlow(StorableFlow $flow): void
  87.     {
  88.         if (!$flow->hasStore(OrderAware::ORDER_ID)) {
  89.             return;
  90.         }
  91.         $this->update($flow->getContext(), $flow->getConfig(), $flow->getStore(OrderAware::ORDER_ID));
  92.     }
  93.     /**
  94.      * @param array<string, mixed> $config
  95.      */
  96.     private function update(Context $context, array $configstring $orderId): void
  97.     {
  98.         if (empty($config)) {
  99.             return;
  100.         }
  101.         if ($config[self::FORCE_TRANSITION] ?? false) {
  102.             $context->addState(self::FORCE_TRANSITION);
  103.         }
  104.         $this->connection->beginTransaction();
  105.         try {
  106.             $transitions array_filter([
  107.                 self::ORDER => $config[self::ORDER] ?? null,
  108.                 self::ORDER_DELIVERY => $config[self::ORDER_DELIVERY] ?? null,
  109.                 self::ORDER_TRANSACTION => $config[self::ORDER_TRANSACTION] ?? null,
  110.             ]);
  111.             foreach ($transitions as $machine => $toPlace) {
  112.                 $this->transitState((string) $machine$orderId, (string) $toPlace$context);
  113.             }
  114.             $this->connection->commit();
  115.         } catch (ShopwareHttpException $e) {
  116.             $this->connection->rollBack();
  117.             $this->logger->error($e->getMessage());
  118.         } finally {
  119.             $context->removeState(self::FORCE_TRANSITION);
  120.         }
  121.     }
  122.     /**
  123.      * @throws IllegalTransitionException
  124.      * @throws StateMachineNotFoundException
  125.      */
  126.     private function transitState(string $machinestring $orderIdstring $toPlaceContext $context): void
  127.     {
  128.         if (!$toPlace) {
  129.             return;
  130.         }
  131.         $data = new ParameterBag();
  132.         $machineId $machine === self::ORDER $orderId $this->getMachineId($machine$orderId);
  133.         if (!$machineId) {
  134.             throw new StateMachineNotFoundException($machine);
  135.         }
  136.         $actionName $this->getAvailableActionName($machine$machineId$toPlace);
  137.         if (!$actionName) {
  138.             $actionName $toPlace;
  139.         }
  140.         switch ($machine) {
  141.             case self::ORDER:
  142.                 $this->orderService->orderStateTransition($orderId$actionName$data$context);
  143.                 return;
  144.             case self::ORDER_DELIVERY:
  145.                 $this->orderService->orderDeliveryStateTransition($machineId$actionName$data$context);
  146.                 return;
  147.             case self::ORDER_TRANSACTION:
  148.                 $this->orderService->orderTransactionStateTransition($machineId$actionName$data$context);
  149.                 return;
  150.             default:
  151.                 throw new StateMachineNotFoundException($machine);
  152.         }
  153.     }
  154.     private function getMachineId(string $machinestring $orderId): ?string
  155.     {
  156.         return $this->connection->fetchOne(
  157.             'SELECT LOWER(HEX(id)) FROM ' $machine ' WHERE order_id = :id AND version_id = :version ORDER BY created_at DESC',
  158.             [
  159.                 'id' => Uuid::fromHexToBytes($orderId),
  160.                 'version' => Uuid::fromHexToBytes(Defaults::LIVE_VERSION),
  161.             ]
  162.         ) ?: null;
  163.     }
  164.     private function getAvailableActionName(string $machinestring $machineIdstring $toPlace): ?string
  165.     {
  166.         $actionName $this->connection->fetchOne(
  167.             'SELECT action_name FROM state_machine_transition WHERE from_state_id = :fromStateId AND to_state_id = :toPlaceId',
  168.             [
  169.                 'fromStateId' => $this->getFromPlaceId($machine$machineId),
  170.                 'toPlaceId' => $this->getToPlaceId($toPlace$machine),
  171.             ]
  172.         );
  173.         return $actionName ?: null;
  174.     }
  175.     private function getToPlaceId(string $toPlacestring $machine): ?string
  176.     {
  177.         $id $this->connection->fetchOne(
  178.             'SELECT id FROM state_machine_state WHERE technical_name = :toPlace AND state_machine_id = :stateMachineId',
  179.             [
  180.                 'toPlace' => $toPlace,
  181.                 'stateMachineId' => $this->getStateMachineId($machine),
  182.             ]
  183.         );
  184.         return $id ?: null;
  185.     }
  186.     private function getFromPlaceId(string $machinestring $machineId): ?string
  187.     {
  188.         $escaped EntityDefinitionQueryHelper::escape($machine);
  189.         $id $this->connection->fetchOne(
  190.             'SELECT state_id FROM ' $escaped 'WHERE id = :id',
  191.             [
  192.                 'id' => Uuid::fromHexToBytes($machineId),
  193.             ]
  194.         );
  195.         return $id ?: null;
  196.     }
  197.     private function getStateMachineId(string $machine): ?string
  198.     {
  199.         $id $this->connection->fetchOne(
  200.             'SELECT id FROM state_machine WHERE technical_name = :technicalName',
  201.             [
  202.                 'technicalName' => $machine '.state',
  203.             ]
  204.         );
  205.         return $id ?: null;
  206.     }
  207. }