Add validation rule identifiers to exceptions and responses

[MAILPOET-4659]
This commit is contained in:
Jan Jakes
2022-10-06 13:44:29 +02:00
committed by Jan Jakeš
parent 9da204489d
commit 6638707282
9 changed files with 28 additions and 11 deletions

View File

@ -161,11 +161,12 @@ class Exceptions {
->withMessage(__("Workflow structure modification not supported.", 'mailpoet')); ->withMessage(__("Workflow structure modification not supported.", 'mailpoet'));
} }
public static function workflowStructureNotValid(string $detail): UnexpectedValueException { public static function workflowStructureNotValid(string $detail, string $ruleId): UnexpectedValueException {
return UnexpectedValueException::create() return UnexpectedValueException::create()
->withErrorCode(self::WORKFLOW_STRUCTURE_NOT_VALID) ->withErrorCode(self::WORKFLOW_STRUCTURE_NOT_VALID)
// translators: %s is a detailed information // translators: %s is a detailed information
->withMessage(sprintf(__("Invalid workflow structure: %s", 'mailpoet'), $detail)); ->withMessage(sprintf(__("Invalid workflow structure: %s", 'mailpoet'), $detail))
->withErrors(['rule_id' => $ruleId]);
} }
public static function workflowStepModifiedWhenUnknown(Step $step): UnexpectedValueException { public static function workflowStepModifiedWhenUnknown(Step $step): UnexpectedValueException {

View File

@ -15,7 +15,7 @@ class WorkflowWalker {
$steps = $workflow->getSteps(); $steps = $workflow->getSteps();
$root = $steps['root'] ?? null; $root = $steps['root'] ?? null;
if (!$root) { if (!$root) {
throw Exceptions::workflowStructureNotValid(__("Workflow must contain a 'root' step", 'mailpoet')); throw Exceptions::workflowStructureNotValid(__("Workflow must contain a 'root' step", 'mailpoet'), 'no-root');
} }
foreach ($visitors as $visitor) { foreach ($visitors as $visitor) {
@ -75,7 +75,8 @@ class WorkflowWalker {
__("Step with ID '%1\$s' not found (referenced from '%2\$s')", 'mailpoet'), __("Step with ID '%1\$s' not found (referenced from '%2\$s')", 'mailpoet'),
$stepId, $stepId,
$parentStepId $parentStepId
) ),
'step-not-found'
); );
} }
} }

View File

@ -8,12 +8,15 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class ConsistentStepMapRule implements WorkflowNodeVisitor { class ConsistentStepMapRule implements WorkflowNodeVisitor {
public const RULE_ID = 'consistent-step-map';
public function initialize(Workflow $workflow): void { public function initialize(Workflow $workflow): void {
foreach ($workflow->getSteps() as $id => $step) { foreach ($workflow->getSteps() as $id => $step) {
if ($id !== $step->getId()) { if ($id !== $step->getId()) {
// translators: %1$s is the ID of the step, %2$s is its index in the steps object. // translators: %1$s is the ID of the step, %2$s is its index in the steps object.
throw Exceptions::workflowStructureNotValid( throw Exceptions::workflowStructureNotValid(
sprintf(__("Step with ID '%1\$s' stored under a mismatched index '%2\$s'.", 'mailpoet'), $step->getId(), $id) sprintf(__("Step with ID '%1\$s' stored under a mismatched index '%2\$s'.", 'mailpoet'), $step->getId(), $id),
self::RULE_ID
); );
} }
} }

View File

@ -9,6 +9,8 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class NoCycleRule implements WorkflowNodeVisitor { class NoCycleRule implements WorkflowNodeVisitor {
public const RULE_ID = 'no-cycle';
public function initialize(Workflow $workflow): void { public function initialize(Workflow $workflow): void {
} }
@ -25,7 +27,7 @@ class NoCycleRule implements WorkflowNodeVisitor {
foreach ($step->getNextSteps() as $nextStep) { foreach ($step->getNextSteps() as $nextStep) {
$nextStepId = $nextStep->getId(); $nextStepId = $nextStep->getId();
if ($nextStepId === $step->getId() || isset($parentIdsMap[$nextStepId])) { if ($nextStepId === $step->getId() || isset($parentIdsMap[$nextStepId])) {
throw Exceptions::workflowStructureNotValid(__('Cycle found in workflow graph', 'mailpoet')); throw Exceptions::workflowStructureNotValid(__('Cycle found in workflow graph', 'mailpoet'), self::RULE_ID);
} }
} }
} }

View File

@ -8,6 +8,8 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class NoDuplicateEdgesRule implements WorkflowNodeVisitor { class NoDuplicateEdgesRule implements WorkflowNodeVisitor {
public const RULE_ID = 'no-duplicate-edges';
public function initialize(Workflow $workflow): void { public function initialize(Workflow $workflow): void {
} }
@ -15,7 +17,7 @@ class NoDuplicateEdgesRule implements WorkflowNodeVisitor {
$visitedNextStepIdsMap = []; $visitedNextStepIdsMap = [];
foreach ($node->getStep()->getNextSteps() as $nextStep) { foreach ($node->getStep()->getNextSteps() as $nextStep) {
if (isset($visitedNextStepIdsMap[$nextStep->getId()])) { if (isset($visitedNextStepIdsMap[$nextStep->getId()])) {
throw Exceptions::workflowStructureNotValid(__('Duplicate next step definition found', 'mailpoet')); throw Exceptions::workflowStructureNotValid(__('Duplicate next step definition found', 'mailpoet'), self::RULE_ID);
} }
$visitedNextStepIdsMap[$nextStep->getId()] = true; $visitedNextStepIdsMap[$nextStep->getId()] = true;
} }

View File

@ -9,6 +9,8 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class NoJoinRule implements WorkflowNodeVisitor { class NoJoinRule implements WorkflowNodeVisitor {
public const RULE_ID = 'no-join';
/** @var array<string, Step> */ /** @var array<string, Step> */
private $visitedSteps = []; private $visitedSteps = [];
@ -22,7 +24,7 @@ class NoJoinRule implements WorkflowNodeVisitor {
foreach ($step->getNextSteps() as $nextStep) { foreach ($step->getNextSteps() as $nextStep) {
$nextStepId = $nextStep->getId(); $nextStepId = $nextStep->getId();
if (isset($this->visitedSteps[$nextStepId])) { if (isset($this->visitedSteps[$nextStepId])) {
throw Exceptions::workflowStructureNotValid(__('Path join found in workflow graph', 'mailpoet')); throw Exceptions::workflowStructureNotValid(__('Path join found in workflow graph', 'mailpoet'), self::RULE_ID);
} }
} }
} }

View File

@ -8,13 +8,15 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class NoSplitRule implements WorkflowNodeVisitor { class NoSplitRule implements WorkflowNodeVisitor {
public const RULE_ID = 'no-split';
public function initialize(Workflow $workflow): void { public function initialize(Workflow $workflow): void {
} }
public function visitNode(Workflow $workflow, WorkflowNode $node): void { public function visitNode(Workflow $workflow, WorkflowNode $node): void {
$step = $node->getStep(); $step = $node->getStep();
if (count($step->getNextSteps()) > 1) { if (count($step->getNextSteps()) > 1) {
throw Exceptions::workflowStructureNotValid(__('Path split found in workflow graph', 'mailpoet')); throw Exceptions::workflowStructureNotValid(__('Path split found in workflow graph', 'mailpoet'), self::RULE_ID);
} }
} }

View File

@ -8,6 +8,8 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class NoUnreachableStepsRule implements WorkflowNodeVisitor { class NoUnreachableStepsRule implements WorkflowNodeVisitor {
public const RULE_ID = 'no-unreachable-steps';
/** @var WorkflowNode[] */ /** @var WorkflowNode[] */
private $visitedNodes = []; private $visitedNodes = [];
@ -21,7 +23,7 @@ class NoUnreachableStepsRule implements WorkflowNodeVisitor {
public function complete(Workflow $workflow): void { public function complete(Workflow $workflow): void {
if (count($this->visitedNodes) !== count($workflow->getSteps())) { if (count($this->visitedNodes) !== count($workflow->getSteps())) {
throw Exceptions::workflowStructureNotValid(__('Unreachable steps found in workflow graph', 'mailpoet')); throw Exceptions::workflowStructureNotValid(__('Unreachable steps found in workflow graph', 'mailpoet'), self::RULE_ID);
} }
} }
} }

View File

@ -9,6 +9,8 @@ use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNode;
use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor; use MailPoet\Automation\Engine\Validation\WorkflowGraph\WorkflowNodeVisitor;
class TriggersUnderRootRule implements WorkflowNodeVisitor { class TriggersUnderRootRule implements WorkflowNodeVisitor {
public const RULE_ID = 'triggers-under-root';
/** @var array<string, Step> $triggersMap */ /** @var array<string, Step> $triggersMap */
private $triggersMap = []; private $triggersMap = [];
@ -30,7 +32,7 @@ class TriggersUnderRootRule implements WorkflowNodeVisitor {
foreach ($step->getNextSteps() as $nextStep) { foreach ($step->getNextSteps() as $nextStep) {
$nextStepId = $nextStep->getId(); $nextStepId = $nextStep->getId();
if (isset($this->triggersMap[$nextStepId])) { if (isset($this->triggersMap[$nextStepId])) {
throw Exceptions::workflowStructureNotValid(__('Trigger must be a direct descendant of workflow root', 'mailpoet')); throw Exceptions::workflowStructureNotValid(__('Trigger must be a direct descendant of workflow root', 'mailpoet'), self::RULE_ID);
} }
} }
} }