<?php
declare(strict_types=1);
namespace NetInventors\NetiNextExportOnEvent\Services\Flow;
use NetInventors\NetiNextExportOnEvent\Exception\ExceptionCollection;
use NetInventors\NetiNextExportOnEvent\Services\Event\ExportOnEventAware;
use NetInventors\NetiNextExportOnEvent\Services\Builder\AdditionalDataBuilder;
use NetInventors\NetiNextExportOnEvent\Struct\EventDataBag;
use NetInventors\NetiNextExportOnEvent\Utility\IterateUtility;
use Psr\Log\LoggerInterface;
use Shopware\Core\Content\Flow\Dispatching\Action\FlowAction;
use Shopware\Core\Framework\Event\FlowEvent;
use Shopware\Core\Framework\Event\FlowEventAware;
use Shopware\Core\Framework\Event\SalesChannelAware;
use Shopware\Core\Framework\Struct\Collection;
use Throwable;
abstract class AbstractFlowAction extends FlowAction
{
protected LoggerInterface $logger;
protected AdditionalDataBuilder $additionalDataBuilder;
public function getLogger(): LoggerInterface
{
return $this->logger;
}
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
public function setAdditionalDataBuilder(
AdditionalDataBuilder $additionalDataBuilder
): void {
$this->additionalDataBuilder = $additionalDataBuilder;
}
public static function getSubscribedEvents(): array
{
return [
static::getName() => 'handle',
];
}
/**
* @psalm-suppress MixedReturnTypeCoercion
*/
public function requirements(): array
{
return [ ExportOnEventAware::class ];
}
public function handle(
FlowEvent $event
): void {
$config = $event->getConfig();
$sequenceId = $event->getFlowState()->getSequenceId();
if (
!$this->validateConfigData(
$config,
[
'sequenceId' => $sequenceId,
]
)
) {
return;
}
$exceptionCollection = new ExceptionCollection();
/**
* @var EventDataBag $eventData
*/
foreach ($this->createEventData($event) as $eventData) {
try {
$this->executeEvent(
$eventData,
$event,
$config,
$sequenceId
);
} catch (Throwable $exception) {
$exceptionCollection->add($exception);
}
}
if (0 === $exceptionCollection->count()) {
return;
}
throw $exceptionCollection;
}
/**
* @return array<string, mixed>
*/
protected function getAvailableData(FlowEventAware $event): array
{
$data = [];
foreach (\array_keys($event::getAvailableData()->toArray()) as $key) {
$getter = 'get' . \ucfirst((string) $key);
if (!\method_exists($event, $getter)) {
continue;
}
/**
* @psalm-suppress MixedAssignment
*/
$data[$key] = $event->$getter();
}
/**
* @var array<string, mixed> $data
*/
return $data;
}
abstract protected function executeEvent(
EventDataBag $eventData,
FlowEvent $event,
array $config,
string $sequenceId
): void;
protected function createEventData(
FlowEvent $event
): iterable {
$config = $event->getConfig();
$sequenceId = $event->getFlowState()->getSequenceId();
$stateEvent = $event->getEvent();
$availableData = $this->additionalDataBuilder->buildAdditionalData(
$stateEvent->getName(),
$this->getAvailableData($stateEvent),
$stateEvent->getContext()
);
/**
* @var string|null $iterationPath
*/
$iterationPath = $config['iterationPath'] ?? null;
if (null !== $iterationPath) {
/**
* @var array $data
*/
foreach ($this->getIterateableData($availableData, $iterationPath) as $data) {
yield $this->buildEventDataBag(
$data,
$config,
$stateEvent,
$sequenceId,
$event
);
}
return;
}
yield $this->buildEventDataBag(
$availableData,
$config,
$stateEvent,
$sequenceId,
$event
);
}
protected function validateConfigData(array $config, array $logContext = []): bool
{
if (!\array_key_exists('exportProfileId', $config)) {
$this->logger->error(
"exportProfileId does not exist in config data:\n"
. \json_encode($config, JSON_THROW_ON_ERROR) . "\n",
$logContext
);
return false;
}
if (!\array_key_exists('filename', $config)) {
$this->logger->error(
"filename does not exist in config data:\n"
. \json_encode($config, JSON_THROW_ON_ERROR) . "\n",
$logContext
);
return false;
}
return true;
}
/**
* @return array[]|iterable
*/
protected function getIterateableData(
array $data,
string $iterationPath
): iterable {
$iterationKeys = \explode('.', $iterationPath);
$valueToIterate = IterateUtility::getNestedValue($data, $iterationKeys);
if (!\is_iterable($valueToIterate)) {
return;
}
if (!$valueToIterate instanceof Collection) {
return;
}
$classname = \get_class($valueToIterate);
$i = 0;
/**
* @var mixed $item
*/
foreach ($valueToIterate->getElements() as $item) {
$data['iterationIndex'] = ++$i;
IterateUtility::setNestedValue(
$data,
$iterationKeys,
new $classname([ $item ])
);
yield $data;
}
}
protected function buildEventDataBag(
array $availableData,
array $config,
FlowEventAware $stateEvent,
string $sequenceId,
FlowEvent $event
): EventDataBag {
$eventData = new EventDataBag($availableData);
$eventData->assign($config);
$salesChannelId = null;
if ($stateEvent instanceof SalesChannelAware) {
$salesChannelId = $stateEvent->getSalesChannelId();
}
$eventData->assign(
[
'sequenceId' => $sequenceId,
'context' => $event->getContext(),
'salesChannelId' => $salesChannelId,
]
);
return $eventData;
}
}