<?php declare(strict_types=1);namespace Shopware\Core\Content\Flow\Dispatching;use Psr\EventDispatcher\StoppableEventInterface;use Psr\Log\LoggerInterface;use Shopware\Core\Content\Flow\Dispatching\Struct\Flow;use Shopware\Core\Content\Flow\Exception\ExecuteSequenceException;use Shopware\Core\Framework\Context;use Shopware\Core\Framework\Event\BusinessEvent;use Shopware\Core\Framework\Event\FlowEvent;use Shopware\Core\Framework\Event\FlowEventAware;use Shopware\Core\Framework\Event\FlowLogEvent;use Shopware\Core\Framework\Feature;use Shopware\Core\Framework\Log\Package;use Symfony\Component\DependencyInjection\ContainerInterface;use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;use Symfony\Component\EventDispatcher\EventDispatcherInterface;use Symfony\Component\EventDispatcher\EventSubscriberInterface;/** * @internal not intended for decoration or replacement */#[Package('business-ops')]class FlowDispatcher implements EventDispatcherInterface{ private EventDispatcherInterface $dispatcher; private ContainerInterface $container; private LoggerInterface $logger; private FlowFactory $flowFactory; public function __construct(EventDispatcherInterface $dispatcher, LoggerInterface $logger, FlowFactory $flowFactory) { $this->dispatcher = $dispatcher; $this->logger = $logger; $this->flowFactory = $flowFactory; } public function setContainer(ContainerInterface $container): void { $this->container = $container; } /** * @template TEvent of object * * @param TEvent $event * * @return TEvent */ public function dispatch($event, ?string $eventName = null): object { $event = $this->dispatcher->dispatch($event, $eventName); if (!$event instanceof FlowEventAware) { return $event; } if (Feature::isActive('v6.5.0.0')) { $flowLogEvent = new FlowLogEvent(FlowLogEvent::NAME, $event); $this->dispatcher->dispatch($flowLogEvent, $flowLogEvent->getName()); } if (Feature::isActive('FEATURE_NEXT_17858')) { if ($event instanceof FlowEvent) { return $event; } } else { if ($event instanceof BusinessEvent || $event instanceof FlowEvent) { return $event; } } if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { return $event; } if ($event->getContext()->hasState(Context::SKIP_TRIGGER_FLOW)) { return $event; } $storableFlow = $this->flowFactory->create($event); /** @deprecated tag:v6.5.0 Will be removed */ if (!Feature::isActive('v6.5.0.0')) { $storableFlow->setOriginalEvent($event); } $this->callFlowExecutor($storableFlow); return $event; } /** * @param string $eventName * @param callable $listener * @param int $priority */ public function addListener($eventName, $listener, $priority = 0): void { $this->dispatcher->addListener($eventName, $listener, $priority); } public function addSubscriber(EventSubscriberInterface $subscriber): void { $this->dispatcher->addSubscriber($subscriber); } /** * @param string $eventName * @param callable $listener */ public function removeListener($eventName, $listener): void { $this->dispatcher->removeListener($eventName, $listener); } public function removeSubscriber(EventSubscriberInterface $subscriber): void { $this->dispatcher->removeSubscriber($subscriber); } public function getListeners(?string $eventName = null): array { return $this->dispatcher->getListeners($eventName); } /** * @param string $eventName * @param callable $listener */ public function getListenerPriority($eventName, $listener): ?int { return $this->dispatcher->getListenerPriority($eventName, $listener); } public function hasListeners(?string $eventName = null): bool { return $this->dispatcher->hasListeners($eventName); } private function callFlowExecutor(StorableFlow $event): void { $flows = $this->getFlows($event->getName()); if (empty($flows)) { return; } /** @var FlowExecutor|null $flowExecutor */ $flowExecutor = $this->container->get(FlowExecutor::class); if ($flowExecutor === null) { throw new ServiceNotFoundException(FlowExecutor::class); } foreach ($flows as $flow) { try { /** @var Flow $payload */ $payload = $flow['payload']; $flowExecutor->execute($payload, $event); } catch (ExecuteSequenceException $e) { $this->logger->error( "Could not execute flow with error message:\n" . 'Flow name: ' . $flow['name'] . "\n" . 'Flow id: ' . $flow['id'] . "\n" . 'Sequence id: ' . $e->getSequenceId() . "\n" . $e->getMessage() . "\n" . 'Error Code: ' . $e->getCode() . "\n" ); } catch (\Throwable $e) { $this->logger->error( "Could not execute flow with error message:\n" . 'Flow name: ' . $flow['name'] . "\n" . 'Flow id: ' . $flow['id'] . "\n" . $e->getMessage() . "\n" . 'Error Code: ' . $e->getCode() . "\n" ); } } } /** * @return array<string, mixed> */ private function getFlows(string $eventName): array { /** @var AbstractFlowLoader|null $flowLoader */ $flowLoader = $this->container->get(FlowLoader::class); if ($flowLoader === null) { throw new ServiceNotFoundException(FlowExecutor::class); } $flows = $flowLoader->load(); $result = []; if (\array_key_exists($eventName, $flows)) { $result = $flows[$eventName]; } return $result; }}