Make next step ID nullable (ability to save multiple edges without next steps)

[MAILPOET-5586]
This commit is contained in:
Jan Jakes
2023-09-15 15:24:53 +02:00
committed by Aschepikov
parent 32e5d4f8ac
commit f55c4f7755
12 changed files with 35 additions and 28 deletions

View File

@@ -78,7 +78,8 @@ class DuplicateAutomationController {
$step->getKey(),
$step->getArgs(),
array_map(function (NextStep $nextStep) use ($newIds): NextStep {
return new NextStep($newIds[$nextStep->getId()]);
$nextStepId = $nextStep->getId();
return new NextStep($nextStepId ? $newIds[$nextStepId] : null);
}, $step->getNextSteps())
);
}

View File

@@ -68,8 +68,8 @@ class StepScheduler {
public function hasScheduledNextStep(StepRunArgs $args): bool {
$runId = $args->getAutomationRun()->getId();
foreach ($args->getStep()->getNextSteps() as $nextStep) {
$data = $this->getActionData($runId, $nextStep->getId());
foreach ($args->getStep()->getNextStepIds() as $nextStepId) {
$data = $this->getActionData($runId, $nextStepId);
$hasStep = $this->actionScheduler->hasScheduledAction(Hooks::AUTOMATION_STEP, $data);
if ($hasStep) {
return true;

View File

@@ -3,16 +3,16 @@
namespace MailPoet\Automation\Engine\Data;
class NextStep {
/** @var string */
/** @var string|null */
protected $id;
public function __construct(
string $id
?string $id
) {
$this->id = $id;
}
public function getId(): string {
public function getId(): ?string {
return $this->id;
}

View File

@@ -62,6 +62,17 @@ class Step {
return $this->nextSteps;
}
public function getNextStepIds(): array {
$ids = [];
foreach ($this->nextSteps as $nextStep) {
$nextStepId = $nextStep->getId();
if ($nextStepId) {
$ids[] = $nextStep->getId();
}
}
return $ids;
}
/** @param NextStep[] $nextSteps */
public function setNextSteps(array $nextSteps): void {
$this->nextSteps = $nextSteps;

View File

@@ -54,6 +54,9 @@ class AutomationWalker {
foreach (array_reverse($step->getNextSteps()) as $nextStepData) {
$nextStepId = $nextStepData->getId();
if (!$nextStepId) {
continue; // empty edge
}
$nextStep = $steps[$nextStepId] ?? null;
if (!$nextStep) {
throw $this->createStepNotFoundException($nextStepId, $step->getId());

View File

@@ -24,8 +24,7 @@ class NoCycleRule implements AutomationNodeVisitor {
$parents
) ?: [];
foreach ($step->getNextSteps() as $nextStep) {
$nextStepId = $nextStep->getId();
foreach ($step->getNextStepIds() as $nextStepId) {
if ($nextStepId === $step->getId() || isset($parentIdsMap[$nextStepId])) {
throw Exceptions::automationStructureNotValid(__('Cycle found in automation graph', 'mailpoet'), self::RULE_ID);
}

View File

@@ -15,11 +15,11 @@ class NoDuplicateEdgesRule implements AutomationNodeVisitor {
public function visitNode(Automation $automation, AutomationNode $node): void {
$visitedNextStepIdsMap = [];
foreach ($node->getStep()->getNextSteps() as $nextStep) {
if (isset($visitedNextStepIdsMap[$nextStep->getId()])) {
foreach ($node->getStep()->getNextStepIds() as $nextStepId) {
if (isset($visitedNextStepIdsMap[$nextStepId])) {
throw Exceptions::automationStructureNotValid(__('Duplicate next step definition found', 'mailpoet'), self::RULE_ID);
}
$visitedNextStepIdsMap[$nextStep->getId()] = true;
$visitedNextStepIdsMap[$nextStepId] = true;
}
}

View File

@@ -20,8 +20,7 @@ class NoJoinRule implements AutomationNodeVisitor {
public function visitNode(Automation $automation, AutomationNode $node): void {
$step = $node->getStep();
foreach ($step->getNextSteps() as $nextStep) {
$nextStepId = $nextStep->getId();
foreach ($step->getNextStepIds() as $nextStepId) {
$this->directParentMap[$nextStepId] = array_merge($this->directParentMap[$nextStepId] ?? [], [$step]);
}

View File

@@ -23,12 +23,14 @@ class TriggerNeedsToBeFollowedByActionRule implements AutomationNodeVisitor {
if ($step->getType() !== Step::TYPE_TRIGGER) {
return;
}
$nextSteps = $step->getNextSteps();
if (!count($nextSteps)) {
$nextStepIds = $step->getNextStepIds();
if (!count($nextStepIds)) {
throw Exceptions::automationStructureNotValid(__('A trigger needs to be followed by an action.', 'mailpoet'), self::RULE_ID);
}
foreach ($nextSteps as $step) {
$step = $automation->getStep($step->getId());
foreach ($nextStepIds as $nextStepsId) {
$step = $automation->getStep($nextStepsId);
if ($step && $step->getType() === Step::TYPE_ACTION) {
continue;
}

View File

@@ -29,8 +29,7 @@ class TriggersUnderRootRule implements AutomationNodeVisitor {
return;
}
foreach ($step->getNextSteps() as $nextStep) {
$nextStepId = $nextStep->getId();
foreach ($step->getNextStepIds() as $nextStepId) {
if (isset($this->triggersMap[$nextStepId])) {
throw Exceptions::automationStructureNotValid(__('Trigger must be a direct descendant of automation root', 'mailpoet'), self::RULE_ID);
}

View File

@@ -46,7 +46,7 @@ class AutomationSchema {
public static function getNextStepsSchema(): ArraySchema {
return Builder::array(
Builder::object([
'id' => Builder::string()->required(),
'id' => Builder::string()->required()->nullable(),
])
);
}

View File

@@ -5,7 +5,6 @@ namespace MailPoet\Automation\Integrations\MailPoet\Actions;
use MailPoet\AutomaticEmails\WooCommerce\Events\AbandonedCart;
use MailPoet\Automation\Engine\Control\StepRunController;
use MailPoet\Automation\Engine\Data\Automation;
use MailPoet\Automation\Engine\Data\NextStep;
use MailPoet\Automation\Engine\Data\Step;
use MailPoet\Automation\Engine\Data\StepRunArgs;
use MailPoet\Automation\Engine\Data\StepValidationArgs;
@@ -267,13 +266,7 @@ class SendEmailAction implements Action {
}
foreach ($transactionalTriggers as $trigger) {
$nextSteps = array_map(
function(NextStep $nextStep): string {
return $nextStep->getId();
},
$trigger->getNextSteps()
);
if (!in_array($step->getId(), $nextSteps, true)) {
if (!in_array($step->getId(), $trigger->getNextStepIds(), true)) {
return false;
}
}