vendor/shopware/core/Content/Flow/Dispatching/FlowDispatcher.php line 45

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Content\Flow\Dispatching;
  3. use Psr\EventDispatcher\StoppableEventInterface;
  4. use Psr\Log\LoggerInterface;
  5. use Shopware\Core\Content\Flow\Dispatching\Struct\Flow;
  6. use Shopware\Core\Content\Flow\Exception\ExecuteSequenceException;
  7. use Shopware\Core\Framework\Context;
  8. use Shopware\Core\Framework\Event\FlowEventAware;
  9. use Shopware\Core\Framework\Event\FlowLogEvent;
  10. use Shopware\Core\Framework\Log\Package;
  11. use Symfony\Component\DependencyInjection\ContainerInterface;
  12. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  13. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. /**
  16.  * @internal not intended for decoration or replacement
  17.  */
  18. #[Package('business-ops')]
  19. class FlowDispatcher implements EventDispatcherInterface
  20. {
  21.     private ContainerInterface $container;
  22.     public function __construct(
  23.         private readonly EventDispatcherInterface $dispatcher,
  24.         private readonly LoggerInterface $logger,
  25.         private readonly FlowFactory $flowFactory
  26.     ) {
  27.     }
  28.     public function setContainer(ContainerInterface $container): void
  29.     {
  30.         $this->container $container;
  31.     }
  32.     /**
  33.      * @template TEvent of object
  34.      *
  35.      * @param TEvent $event
  36.      *
  37.      * @return TEvent
  38.      */
  39.     public function dispatch(object $event, ?string $eventName null): object
  40.     {
  41.         $event $this->dispatcher->dispatch($event$eventName);
  42.         if (!$event instanceof FlowEventAware) {
  43.             return $event;
  44.         }
  45.         $flowLogEvent = new FlowLogEvent(FlowLogEvent::NAME$event);
  46.         $this->dispatcher->dispatch($flowLogEvent$flowLogEvent->getName());
  47.         if (($event instanceof StoppableEventInterface && $event->isPropagationStopped())
  48.             || $event->getContext()->hasState(Context::SKIP_TRIGGER_FLOW)
  49.         ) {
  50.             return $event;
  51.         }
  52.         $storableFlow $this->flowFactory->create($event);
  53.         $this->callFlowExecutor($storableFlow);
  54.         return $event;
  55.     }
  56.     /**
  57.      * @param callable $listener can not use native type declaration @see https://github.com/symfony/symfony/issues/42283
  58.      */
  59.     public function addListener(string $eventName$listenerint $priority 0): void // @phpstan-ignore-line
  60.     {
  61.         /** @var callable(object): void $listener - Specify generic callback interface callers can provide more specific implementations */
  62.         $this->dispatcher->addListener($eventName$listener$priority);
  63.     }
  64.     public function addSubscriber(EventSubscriberInterface $subscriber): void
  65.     {
  66.         $this->dispatcher->addSubscriber($subscriber);
  67.     }
  68.     public function removeListener(string $eventName, callable $listener): void
  69.     {
  70.         /** @var callable(object): void $listener - Specify generic callback interface callers can provide more specific implementations */
  71.         $this->dispatcher->removeListener($eventName$listener);
  72.     }
  73.     public function removeSubscriber(EventSubscriberInterface $subscriber): void
  74.     {
  75.         $this->dispatcher->removeSubscriber($subscriber);
  76.     }
  77.     /**
  78.      * @return array<array-key, array<array-key, callable(object): void>|callable(object): void>
  79.      */
  80.     public function getListeners(?string $eventName null): array
  81.     {
  82.         return $this->dispatcher->getListeners($eventName);
  83.     }
  84.     public function getListenerPriority(string $eventName, callable $listener): ?int
  85.     {
  86.         /** @var callable(object): void $listener - Specify generic callback interface callers can provide more specific implementations */
  87.         return $this->dispatcher->getListenerPriority($eventName$listener);
  88.     }
  89.     public function hasListeners(?string $eventName null): bool
  90.     {
  91.         return $this->dispatcher->hasListeners($eventName);
  92.     }
  93.     private function callFlowExecutor(StorableFlow $event): void
  94.     {
  95.         $flows $this->getFlows($event->getName());
  96.         if (empty($flows)) {
  97.             return;
  98.         }
  99.         /** @var FlowExecutor|null $flowExecutor */
  100.         $flowExecutor $this->container->get(FlowExecutor::class);
  101.         if ($flowExecutor === null) {
  102.             throw new ServiceNotFoundException(FlowExecutor::class);
  103.         }
  104.         foreach ($flows as $flow) {
  105.             try {
  106.                 /** @var Flow $payload */
  107.                 $payload $flow['payload'];
  108.                 $flowExecutor->execute($payload$event);
  109.             } catch (ExecuteSequenceException $e) {
  110.                 $this->logger->error(
  111.                     "Could not execute flow with error message:\n"
  112.                     'Flow name: ' $flow['name'] . "\n"
  113.                     'Flow id: ' $flow['id'] . "\n"
  114.                     'Sequence id: ' $e->getSequenceId() . "\n"
  115.                     $e->getMessage() . "\n"
  116.                     'Error Code: ' $e->getCode() . "\n"
  117.                 );
  118.             } catch (\Throwable $e) {
  119.                 $this->logger->error(
  120.                     "Could not execute flow with error message:\n"
  121.                     'Flow name: ' $flow['name'] . "\n"
  122.                     'Flow id: ' $flow['id'] . "\n"
  123.                     $e->getMessage() . "\n"
  124.                     'Error Code: ' $e->getCode() . "\n"
  125.                 );
  126.             }
  127.         }
  128.     }
  129.     /**
  130.      * @return array<string, mixed>
  131.      */
  132.     private function getFlows(string $eventName): array
  133.     {
  134.         /** @var AbstractFlowLoader|null $flowLoader */
  135.         $flowLoader $this->container->get(FlowLoader::class);
  136.         if ($flowLoader === null) {
  137.             throw new ServiceNotFoundException(FlowExecutor::class);
  138.         }
  139.         $flows $flowLoader->load();
  140.         $result = [];
  141.         if (\array_key_exists($eventName$flows)) {
  142.             $result $flows[$eventName];
  143.         }
  144.         return $result;
  145.     }
  146. }