Introduce subject transformation
[MAILPOET-4935]
This commit is contained in:
@@ -10,6 +10,7 @@ use MailPoet\Automation\Engine\Data\AutomationRunLog;
|
||||
use MailPoet\Automation\Engine\Data\Step;
|
||||
use MailPoet\Automation\Engine\Data\StepRunArgs;
|
||||
use MailPoet\Automation\Engine\Data\StepValidationArgs;
|
||||
use MailPoet\Automation\Engine\Data\Subject as SubjectData;
|
||||
use MailPoet\Automation\Engine\Data\SubjectEntry;
|
||||
use MailPoet\Automation\Engine\Exceptions;
|
||||
use MailPoet\Automation\Engine\Exceptions\InvalidStateException;
|
||||
@@ -55,6 +56,9 @@ class StepHandler {
|
||||
/** @var Registry */
|
||||
private $registry;
|
||||
|
||||
/** @var SubjectTransformerHandler */
|
||||
private $subjectTransformerHandler;
|
||||
|
||||
public function __construct(
|
||||
ActionScheduler $actionScheduler,
|
||||
ActionStepRunner $actionStepRunner,
|
||||
@@ -64,7 +68,8 @@ class StepHandler {
|
||||
AutomationRunStorage $automationRunStorage,
|
||||
AutomationRunLogStorage $automationRunLogStorage,
|
||||
AutomationStorage $automationStorage,
|
||||
Registry $registry
|
||||
Registry $registry,
|
||||
SubjectTransformerHandler $subjectTransformerHandler
|
||||
) {
|
||||
$this->actionScheduler = $actionScheduler;
|
||||
$this->actionStepRunner = $actionStepRunner;
|
||||
@@ -75,6 +80,7 @@ class StepHandler {
|
||||
$this->automationRunLogStorage = $automationRunLogStorage;
|
||||
$this->automationStorage = $automationStorage;
|
||||
$this->registry = $registry;
|
||||
$this->subjectTransformerHandler = $subjectTransformerHandler;
|
||||
}
|
||||
|
||||
public function initialize(): void {
|
||||
@@ -217,6 +223,7 @@ class StepHandler {
|
||||
$subjectEntries = [];
|
||||
foreach ($requiredSubjectKeys as $key) {
|
||||
$subjectData = $subjectDataMap[$key] ?? null;
|
||||
$subjectData = $subjectData ?? $this->transformSubject($key, $automationRun);
|
||||
if (!$subjectData) {
|
||||
throw Exceptions::subjectDataNotFound($key, $automationRun->getId());
|
||||
}
|
||||
@@ -227,6 +234,13 @@ class StepHandler {
|
||||
return $subjectEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SubjectData[]|null
|
||||
*/
|
||||
private function transformSubject(string $target, AutomationRun $automationRun): ?array {
|
||||
return $this->subjectTransformerHandler->transformSubjectData($target, $automationRun);
|
||||
}
|
||||
|
||||
private function postProcessAutomationRun(int $automationRunId): void {
|
||||
$automationRun = $this->automationRunStorage->getAutomationRun($automationRunId);
|
||||
if (!$automationRun) {
|
||||
|
@@ -0,0 +1,142 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Automation\Engine\Control;
|
||||
|
||||
use MailPoet\Automation\Engine\Data\Automation;
|
||||
use MailPoet\Automation\Engine\Data\AutomationRun;
|
||||
use MailPoet\Automation\Engine\Data\Step as StepData;
|
||||
use MailPoet\Automation\Engine\Data\Subject as SubjectData;
|
||||
use MailPoet\Automation\Engine\Integration\Step;
|
||||
use MailPoet\Automation\Engine\Integration\SubjectTransformer;
|
||||
use MailPoet\Automation\Engine\Registry;
|
||||
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
||||
|
||||
class SubjectTransformerHandler {
|
||||
|
||||
/* @var Registry */
|
||||
private $registry;
|
||||
|
||||
/* @var AutomationStorage */
|
||||
private $automationStorage;
|
||||
|
||||
public function __construct(
|
||||
Registry $registry,
|
||||
AutomationStorage $automationStorage
|
||||
) {
|
||||
$this->registry = $registry;
|
||||
$this->automationStorage = $automationStorage;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function subjectKeysForAutomation(Automation $automation): array {
|
||||
$configuredTriggers = array_filter(
|
||||
$automation->getSteps(),
|
||||
function (StepData $step): bool {
|
||||
return $step->getType() === StepData::TYPE_TRIGGER;
|
||||
}
|
||||
);
|
||||
|
||||
$triggers = array_filter(array_map(
|
||||
function(StepData $step): ?Step {
|
||||
return $this->registry->getStep($step->getKey());
|
||||
},
|
||||
$configuredTriggers
|
||||
));
|
||||
|
||||
$triggerKeys = [];
|
||||
foreach ($triggers as $trigger) {
|
||||
$triggerKeys[$trigger->getKey()] = $trigger->getSubjectKeys();
|
||||
}
|
||||
if (!$triggerKeys) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$triggerKeys = count($triggerKeys) === 1 ? current($triggerKeys) : array_intersect(...array_values($triggerKeys));
|
||||
$possibleKeys = [];
|
||||
foreach ($triggerKeys as $key) {
|
||||
$possibleKeys = array_merge($possibleKeys, $this->getPossibleTransformations($key));
|
||||
}
|
||||
return array_unique(array_values(array_merge($triggerKeys, $possibleKeys)));
|
||||
}
|
||||
|
||||
private function getPossibleTransformations(string $key, string $stopKey = null): array {
|
||||
if (!$stopKey) {
|
||||
$stopKey = $key;
|
||||
}
|
||||
$allTransformer = $this->registry->getSubjectTransformer();
|
||||
$possibleTransformer = array_filter(
|
||||
$allTransformer,
|
||||
function (SubjectTransformer $transformer) use ($key): bool {
|
||||
return $transformer->accepts() === $key;
|
||||
}
|
||||
);
|
||||
|
||||
$possibleKeys = [];
|
||||
foreach ($possibleTransformer as $transformer) {
|
||||
$possibleKey = $transformer->returns();
|
||||
if ($possibleKey === $stopKey) {
|
||||
continue;
|
||||
}
|
||||
$possibleKeys[$possibleKey] = $possibleKey;
|
||||
$possibleKeys = array_merge(
|
||||
$possibleKeys,
|
||||
$this->getPossibleTransformations($possibleKey, $stopKey)
|
||||
);
|
||||
}
|
||||
return $possibleKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SubjectData[]|null
|
||||
*/
|
||||
public function transformSubjectData(string $target, AutomationRun $automationRun): ?array {
|
||||
$automation = $this->automationStorage->getAutomation($automationRun->getAutomationId(), $automationRun->getVersionId());
|
||||
if (!$automation || !in_array($target, $this->subjectKeysForAutomation($automation), true)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$transformedSubjects = [];
|
||||
$subjects = $automationRun->getSubjects();
|
||||
foreach ($subjects as $subject) {
|
||||
$transformerChain = $this->getTransformerChain($subject->getKey(), $target);
|
||||
if (!$transformerChain) {
|
||||
continue;
|
||||
}
|
||||
foreach ($transformerChain as $transformer) {
|
||||
$subject = $transformer->transform($subject);
|
||||
}
|
||||
$transformedSubjects[] = $subject;
|
||||
}
|
||||
return count($transformedSubjects) > 0 ? $transformedSubjects : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SubjectTransformer[]
|
||||
*/
|
||||
private function getTransformerChain(string $from, string $to): array {
|
||||
$transformers = $this->registry->getSubjectTransformer();
|
||||
$transformerChain = [];
|
||||
|
||||
//walk the graph of transformers to find the shortest path
|
||||
$queue = [];
|
||||
$queue[] = [$from, []];
|
||||
while (count($queue) > 0) {
|
||||
$current = array_shift($queue);
|
||||
$currentKey = $current[0];
|
||||
$currentPath = $current[1];
|
||||
if ($currentKey === $to) {
|
||||
$transformerChain = $currentPath;
|
||||
break;
|
||||
}
|
||||
foreach ($transformers as $transformer) {
|
||||
if ($transformer->accepts() === $currentKey) {
|
||||
$newPath = $currentPath;
|
||||
$newPath[] = $transformer;
|
||||
$queue[] = [$transformer->returns(), $newPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $transformerChain;
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Automation\Engine\Integration;
|
||||
|
||||
use MailPoet\Automation\Engine\Data\Subject;
|
||||
|
||||
interface SubjectTransformer {
|
||||
public function transform(Subject $data): Subject;
|
||||
|
||||
public function returns(): string;
|
||||
|
||||
public function accepts(): string;
|
||||
}
|
@@ -7,6 +7,7 @@ use MailPoet\Automation\Engine\Integration\Action;
|
||||
use MailPoet\Automation\Engine\Integration\Payload;
|
||||
use MailPoet\Automation\Engine\Integration\Step;
|
||||
use MailPoet\Automation\Engine\Integration\Subject;
|
||||
use MailPoet\Automation\Engine\Integration\SubjectTransformer;
|
||||
use MailPoet\Automation\Engine\Integration\Trigger;
|
||||
|
||||
class Registry {
|
||||
@@ -16,6 +17,9 @@ class Registry {
|
||||
/** @var array<string, Subject<Payload>> */
|
||||
private $subjects = [];
|
||||
|
||||
/** @var SubjectTransformer[] */
|
||||
private $subjectTransformer = [];
|
||||
|
||||
/** @var array<string, Trigger> */
|
||||
private $triggers = [];
|
||||
|
||||
@@ -55,6 +59,14 @@ class Registry {
|
||||
return $this->subjects;
|
||||
}
|
||||
|
||||
public function addSubjectTransformer(SubjectTransformer $transformer): void {
|
||||
$this->subjectTransformer[] = $transformer;
|
||||
}
|
||||
|
||||
public function getSubjectTransformer(): array {
|
||||
return $this->subjectTransformer;
|
||||
}
|
||||
|
||||
public function addStep(Step $step): void {
|
||||
if ($step instanceof Trigger) {
|
||||
$this->addTrigger($step);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace MailPoet\Automation\Engine\Validation\AutomationRules;
|
||||
|
||||
use MailPoet\Automation\Engine\Control\SubjectTransformerHandler;
|
||||
use MailPoet\Automation\Engine\Data\Automation;
|
||||
use MailPoet\Automation\Engine\Data\Step;
|
||||
use MailPoet\Automation\Engine\Exceptions;
|
||||
@@ -13,10 +14,15 @@ class ValidStepOrderRule implements AutomationNodeVisitor {
|
||||
/** @var Registry */
|
||||
private $registry;
|
||||
|
||||
/** @var SubjectTransformerHandler */
|
||||
private $subjectTransformerHandler;
|
||||
|
||||
public function __construct(
|
||||
Registry $registry
|
||||
Registry $registry,
|
||||
SubjectTransformerHandler $subjectTransformerHandler
|
||||
) {
|
||||
$this->registry = $registry;
|
||||
$this->subjectTransformerHandler = $subjectTransformerHandler;
|
||||
}
|
||||
|
||||
public function initialize(Automation $automation): void {
|
||||
@@ -39,7 +45,7 @@ class ValidStepOrderRule implements AutomationNodeVisitor {
|
||||
return;
|
||||
}
|
||||
|
||||
$subjectKeys = $this->collectSubjectKeys($automation, $node->getParents());
|
||||
$subjectKeys = $this->subjectTransformerHandler->subjectKeysForAutomation($automation);
|
||||
$missingSubjectKeys = array_diff($requiredSubjectKeys, $subjectKeys);
|
||||
if (count($missingSubjectKeys) > 0) {
|
||||
throw Exceptions::missingRequiredSubjects($step, $missingSubjectKeys);
|
||||
@@ -48,24 +54,4 @@ class ValidStepOrderRule implements AutomationNodeVisitor {
|
||||
|
||||
public function complete(Automation $automation): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Step[] $parents
|
||||
* @return string[]
|
||||
*/
|
||||
private function collectSubjectKeys(Automation $automation, array $parents): array {
|
||||
$triggers = array_filter($parents, function (Step $step) {
|
||||
return $step->getType() === Step::TYPE_TRIGGER;
|
||||
});
|
||||
|
||||
$subjectKeys = [];
|
||||
foreach ($triggers as $trigger) {
|
||||
$registryTrigger = $this->registry->getTrigger($trigger->getKey());
|
||||
if (!$registryTrigger) {
|
||||
throw Exceptions::automationTriggerNotFound($automation->getId(), $trigger->getKey());
|
||||
}
|
||||
$subjectKeys = array_merge($subjectKeys, $registryTrigger->getSubjectKeys());
|
||||
}
|
||||
return array_unique($subjectKeys);
|
||||
}
|
||||
}
|
||||
|
@@ -123,6 +123,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\ActionScheduler::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\RootStep::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\StepHandler::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\SubjectTransformerHandler::class)->setPublic(true)->setShared(false);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\SubjectLoader::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\Steps\ActionStepRunner::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Control\TriggerHandler::class)->setPublic(true);
|
||||
|
@@ -0,0 +1,199 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Automation\Engine\Control;
|
||||
|
||||
use MailPoet\Automation\Engine\Data\Automation;
|
||||
use MailPoet\Automation\Engine\Data\AutomationRun;
|
||||
use MailPoet\Automation\Engine\Data\Step;
|
||||
use MailPoet\Automation\Engine\Data\Subject;
|
||||
use MailPoet\Automation\Engine\Integration\SubjectTransformer;
|
||||
use MailPoet\Automation\Engine\Integration\Trigger;
|
||||
use MailPoet\Automation\Engine\Registry;
|
||||
use MailPoet\Automation\Engine\Storage\AutomationStorage;
|
||||
use MailPoetUnitTest;
|
||||
|
||||
class SubjectTransformerHandlerTest extends MailPoetUnitTest {
|
||||
public function testItFindsAllPossibleSubjects(): void {
|
||||
$triggerSubject = 'subject_a';
|
||||
$graphKeys = [
|
||||
$triggerSubject => ['subject_b1', 'subject_b2'],
|
||||
'subject_b1' => ['subject_c1'],
|
||||
'subject_b2' => ['subject_c2'],
|
||||
'subject_c1' => ['subject_d1'],
|
||||
];
|
||||
|
||||
$transformers = [];
|
||||
foreach ($graphKeys as $from => $tos) {
|
||||
foreach ($tos as $to) {
|
||||
$transformer = $this->createMock(SubjectTransformer::class);
|
||||
$transformer->method('returns')->willReturn($to);
|
||||
$transformer->method('accepts')->willReturn($from);
|
||||
$transformers[] = $transformer;
|
||||
}
|
||||
}
|
||||
|
||||
$anotherRegisteredTransformer = $this->createMock(SubjectTransformer::class);
|
||||
$anotherRegisteredTransformer->method('returns')->willReturn('yet_another_subject');
|
||||
$anotherRegisteredTransformer->method('accepts')->willReturn('another_unrelated_subject');
|
||||
$transformers[] = $anotherRegisteredTransformer;
|
||||
|
||||
$trigger = $this->createMock(Trigger::class);
|
||||
$trigger->expects($this->any())->method('getKey')->willReturn('trigger');
|
||||
$trigger->expects($this->any())->method('getSubjectKeys')->willReturn([$triggerSubject]);
|
||||
$registry = $this->createMock(Registry::class);
|
||||
$registry->expects($this->any())->method('getSubjectTransformer')->willReturn($transformers);
|
||||
$registry->expects($this->any())->method('getStep')->willReturnCallback(function($key) use ($trigger){
|
||||
return $key === 'trigger' ? $trigger : null;
|
||||
});
|
||||
$storage = $this->createMock(AutomationStorage::class);
|
||||
$testee = new SubjectTransformerHandler($registry, $storage);
|
||||
|
||||
$triggerData = $this->createMock(Step::class);
|
||||
$triggerData->expects($this->any())->method('getType')->willReturn(Step::TYPE_TRIGGER);
|
||||
$triggerData->expects($this->any())->method('getKey')->willReturn('trigger');
|
||||
$automation = $this->createMock(Automation::class);
|
||||
$automation->method('getSteps')->willReturn([$triggerData]);
|
||||
$result = $testee->subjectKeysForAutomation($automation);
|
||||
$this->assertEquals(['subject_a', 'subject_b1', 'subject_c1', 'subject_d1', 'subject_b2', 'subject_c2'], $result);
|
||||
}
|
||||
|
||||
public function testItDoesNotRunInfiniteWhileFindingAllSubjects(): void {
|
||||
$triggerSubject = 'subject_a';
|
||||
$graphKeys = [
|
||||
$triggerSubject => 'subject_b',
|
||||
'subject_b' => 'subject_c',
|
||||
'subject_c' => 'subject_a',
|
||||
];
|
||||
|
||||
$transformers = [];
|
||||
foreach ($graphKeys as $from => $to) {
|
||||
$transformer = $this->createMock(SubjectTransformer::class);
|
||||
$transformer->method('returns')->willReturn($to);
|
||||
$transformer->method('accepts')->willReturn($from);
|
||||
$transformers[] = $transformer;
|
||||
}
|
||||
|
||||
$trigger = $this->createMock(Trigger::class);
|
||||
$trigger->expects($this->any())->method('getKey')->willReturn('trigger');
|
||||
$trigger->expects($this->any())->method('getSubjectKeys')->willReturn([$triggerSubject]);
|
||||
$registry = $this->createMock(Registry::class);
|
||||
$registry->expects($this->any())->method('getSubjectTransformer')->willReturn($transformers);
|
||||
$registry->expects($this->any())->method('getStep')->willReturnCallback(function($key) use ($trigger){
|
||||
return $key === 'trigger' ? $trigger : null;
|
||||
});
|
||||
$storage = $this->createMock(AutomationStorage::class);
|
||||
$testee = new SubjectTransformerHandler($registry, $storage);
|
||||
|
||||
$triggerData = $this->createMock(Step::class);
|
||||
$triggerData->expects($this->any())->method('getType')->willReturn(Step::TYPE_TRIGGER);
|
||||
$triggerData->expects($this->any())->method('getKey')->willReturn('trigger');
|
||||
$automation = $this->createMock(Automation::class);
|
||||
$automation->method('getSteps')->willReturn([$triggerData]);
|
||||
$result = $testee->subjectKeysForAutomation($automation);
|
||||
$this->assertEquals(['subject_a', 'subject_b', 'subject_c'], $result);
|
||||
}
|
||||
|
||||
public function testItReturnsOnlyKeysInCommonForMultipleTriggers(): void {
|
||||
$trigger1Keys = ['a', 'b', 'c'];
|
||||
$trigger1 = $this->createMock(Trigger::class);
|
||||
$trigger1->expects($this->any())->method('getKey')->willReturn('trigger1');
|
||||
$trigger1->expects($this->any())->method('getSubjectKeys')->willReturn($trigger1Keys);
|
||||
|
||||
$trigger2Keys = ['b', 'c', 'd'];
|
||||
$trigger2 = $this->createMock(Trigger::class);
|
||||
$trigger2->expects($this->any())->method('getKey')->willReturn('trigger2');
|
||||
$trigger2->expects($this->any())->method('getSubjectKeys')->willReturn($trigger2Keys);
|
||||
|
||||
$registry = $this->createMock(Registry::class);
|
||||
$registry->expects($this->any())->method('getSubjectTransformer')->willReturn([]);
|
||||
$registry->expects($this->any())->method('getStep')->willReturnCallback(function($key) use ($trigger1, $trigger2){
|
||||
if ($key === 'trigger1') {
|
||||
return $trigger1;
|
||||
}
|
||||
if ($key === 'trigger2') {
|
||||
return $trigger2;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
$storage = $this->createMock(AutomationStorage::class);
|
||||
$testee = new SubjectTransformerHandler($registry, $storage);
|
||||
|
||||
$trigger1Data = $this->createMock(Step::class);
|
||||
$trigger1Data->expects($this->any())->method('getType')->willReturn(Step::TYPE_TRIGGER);
|
||||
$trigger1Data->expects($this->any())->method('getKey')->willReturn('trigger1');
|
||||
|
||||
$trigger2Data = $this->createMock(Step::class);
|
||||
$trigger2Data->expects($this->any())->method('getType')->willReturn(Step::TYPE_TRIGGER);
|
||||
$trigger2Data->expects($this->any())->method('getKey')->willReturn('trigger2');
|
||||
|
||||
$automation = $this->createMock(Automation::class);
|
||||
$automation->method('getSteps')->willReturn([$trigger1Data, $trigger2Data]);
|
||||
$result = $testee->subjectKeysForAutomation($automation);
|
||||
$this->assertEquals(['b', 'c'], $result);
|
||||
}
|
||||
|
||||
public function testItTransformsSubjects(): void {
|
||||
|
||||
$subjectTransformerStart = $this->createMock(SubjectTransformer::class);
|
||||
$subjectTransformerStart->expects($this->any())->method('accepts')->willReturn('from');
|
||||
$subjectTransformerStart->expects($this->any())->method('returns')->willReturn('middle');
|
||||
$subjectTransformerStart->expects($this->any())->method('transform')->willReturnCallback(function($subject) {
|
||||
if ($subject->getKey() === 'from') {
|
||||
return new Subject('middle', []);
|
||||
}
|
||||
return $subject;
|
||||
});
|
||||
|
||||
$subjectTransformerEnd = $this->createMock(SubjectTransformer::class);
|
||||
$subjectTransformerEnd->expects($this->any())->method('accepts')->willReturn('middle');
|
||||
$subjectTransformerEnd->expects($this->any())->method('returns')->willReturn('to');
|
||||
$subjectTransformerEnd->expects($this->any())->method('transform')->willReturnCallback(function($subject) {
|
||||
if ($subject->getKey() === 'middle') {
|
||||
return new Subject('to', []);
|
||||
}
|
||||
return $subject;
|
||||
});
|
||||
|
||||
$transformer = [
|
||||
$subjectTransformerEnd,
|
||||
$subjectTransformerStart,
|
||||
];
|
||||
$automation = $this->createMock(Automation::class);
|
||||
$triggerStep = $this->createMock(Step::class);
|
||||
$triggerStep->expects($this->any())->method('getType')->willReturn(Step::TYPE_TRIGGER);
|
||||
$triggerStep->expects($this->any())->method('getKey')->willReturn('trigger');
|
||||
$automation->expects($this->any())->method('getSteps')->willReturn([$triggerStep]);
|
||||
|
||||
$registry = $this->createMock(Registry::class);
|
||||
$registry->expects($this->any())->method('getStep')->willReturnCallback(
|
||||
function($key) {
|
||||
if ($key !== 'trigger') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$trigger = $this->createMock(Trigger::class);
|
||||
$trigger->expects($this->any())->method('getKey')->willReturn('trigger');
|
||||
$trigger->expects($this->any())->method('getSubjectKeys')->willReturn(['from']);
|
||||
return $trigger;
|
||||
}
|
||||
);
|
||||
$registry->expects($this->any())->method('getSubjectTransformer')->willReturn($transformer);
|
||||
$storage = $this->createMock(AutomationStorage::class);
|
||||
$storage->expects($this->any())->method('getAutomation')->willReturnCallback(function($id) use ($automation) {
|
||||
return $id === 1 ? $automation : null;
|
||||
});
|
||||
$testee = new SubjectTransformerHandler($registry, $storage);
|
||||
|
||||
$subject = new Subject('from', ['key' => 'value']);
|
||||
$automationRun = $this->createMock(AutomationRun::class);
|
||||
$automationRun->expects($this->any())->method('getAutomationId')->willReturn(1);
|
||||
$automationRun->expects($this->any())->method('getVersionId')->willReturn(1);
|
||||
$automationRun->expects($this->any())->method('getSubjects')->willReturn([$subject]);
|
||||
$subjects = $testee->transformSubjectData('to', $automationRun);
|
||||
$this->assertNotNull($subjects);
|
||||
$this->assertCount(1, $subjects);
|
||||
$subject = current($subjects);
|
||||
$this->assertInstanceOf(Subject::class, $subject);
|
||||
$this->assertEquals('to', $subject->getKey());
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ namespace MailPoet\Automation\Engine\Validation\AutomationRules;
|
||||
require_once __DIR__ . '/AutomationRuleTest.php';
|
||||
|
||||
use MailPoet\Automation\Engine\Control\RootStep;
|
||||
use MailPoet\Automation\Engine\Control\SubjectTransformerHandler;
|
||||
use MailPoet\Automation\Engine\Data\Automation;
|
||||
use MailPoet\Automation\Engine\Data\NextStep;
|
||||
use MailPoet\Automation\Engine\Data\Step;
|
||||
@@ -23,7 +24,6 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
$registry->addStep(new RootStep());
|
||||
$registry->addStep($this->getTrigger('test:trigger', ['subject-a']));
|
||||
$registry->addStep($this->getAction('test:action', ['subject-a', 'subject-b']));
|
||||
$rule = new ValidStepOrderRule($registry);
|
||||
|
||||
$automation = $this->make(Automation::class, [
|
||||
'getId' => 1,
|
||||
@@ -34,6 +34,12 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
],
|
||||
]);
|
||||
|
||||
$subjectTransformer = $this->createMock(SubjectTransformerHandler::class);
|
||||
$subjectTransformer->expects($this->any())->method('subjectKeysForAutomation')->willReturnCallback(function($a) use ($automation) {
|
||||
return $a === $automation ? ['subject-a'] : [];
|
||||
});
|
||||
$rule = new ValidStepOrderRule($registry, $subjectTransformer);
|
||||
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage("Step with ID 'a' is missing required subjects with keys: subject-b");
|
||||
(new AutomationWalker())->walk($automation, [$rule]);
|
||||
@@ -45,7 +51,6 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
$registry->addStep($this->getTrigger('test:trigger-a', ['subject-a', 'subject-b']));
|
||||
$registry->addStep($this->getTrigger('test:trigger-b', ['subject-a']));
|
||||
$registry->addStep($this->getAction('test:action', ['subject-a', 'subject-b']));
|
||||
$rule = new ValidStepOrderRule($registry);
|
||||
|
||||
$automation = $this->make(Automation::class, [
|
||||
'getId' => 1,
|
||||
@@ -57,6 +62,14 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
],
|
||||
]);
|
||||
|
||||
$subjectTransformer = $this->createMock(SubjectTransformerHandler::class);
|
||||
$subjectTransformer->expects($this->any())->method('subjectKeysForAutomation')->willReturnCallback(function($a) use ($automation) {
|
||||
return $a === $automation ? ['subject-a'] : [];
|
||||
});
|
||||
|
||||
$rule = new ValidStepOrderRule($registry, $subjectTransformer);
|
||||
|
||||
|
||||
$this->expectException(UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage("Step with ID 's' is missing required subjects with keys: subject-b");
|
||||
(new AutomationWalker())->walk($automation, [$rule]);
|
||||
@@ -67,7 +80,6 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
$registry->addStep(new RootStep());
|
||||
$registry->addStep($this->getTrigger('test:trigger'));
|
||||
$registry->addStep($this->getAction('test:action'));
|
||||
$rule = new ValidStepOrderRule($registry);
|
||||
|
||||
$automation = $this->make(Automation::class, [
|
||||
'getSteps' => [
|
||||
@@ -76,6 +88,13 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
'a' => new Step('a', 'action', 'test:action', [], []),
|
||||
],
|
||||
]);
|
||||
|
||||
$subjectTransformer = $this->createMock(SubjectTransformerHandler::class);
|
||||
$subjectTransformer->expects($this->any())->method('subjectKeysForAutomation')->willReturnCallback(function($a) use ($automation) {
|
||||
return $a === $automation ? ['subject-a'] : [];
|
||||
});
|
||||
$rule = new ValidStepOrderRule($registry, $subjectTransformer);
|
||||
|
||||
(new AutomationWalker())->walk($automation, [$rule]);
|
||||
}
|
||||
|
||||
@@ -84,7 +103,6 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
$registry->addStep(new RootStep());
|
||||
$registry->addStep($this->getTrigger('test:trigger', ['subject-a', 'subject-b', 'subject-c']));
|
||||
$registry->addStep($this->getAction('test:action', ['subject-a', 'subject-b']));
|
||||
$rule = new ValidStepOrderRule($registry);
|
||||
|
||||
$automation = $this->make(Automation::class, [
|
||||
'getSteps' => [
|
||||
@@ -93,6 +111,14 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
'a' => new Step('a', 'action', 'test:action', [], []),
|
||||
],
|
||||
]);
|
||||
|
||||
$subjectTransformer = $this->createMock(SubjectTransformerHandler::class);
|
||||
$subjectTransformer->expects($this->any())->method('subjectKeysForAutomation')->willReturnCallback(function($a) use ($automation) {
|
||||
return $a === $automation ? ['subject-a', 'subject-b'] : [];
|
||||
});
|
||||
|
||||
$rule = new ValidStepOrderRule($registry, $subjectTransformer);
|
||||
|
||||
(new AutomationWalker())->walk($automation, [$rule]);
|
||||
}
|
||||
|
||||
@@ -102,7 +128,6 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
$registry->addStep($this->getTrigger('test:trigger-a', ['subject-a', 'subject-b', 'subject-c']));
|
||||
$registry->addStep($this->getTrigger('test:trigger-b', ['subject-a', 'subject-b']));
|
||||
$registry->addStep($this->getAction('test:action', ['subject-a', 'subject-b']));
|
||||
$rule = new ValidStepOrderRule($registry);
|
||||
|
||||
$automation = $this->make(Automation::class, [
|
||||
'getId' => 1,
|
||||
@@ -113,6 +138,13 @@ class ValidStepOrderRuleTest extends AutomationRuleTest {
|
||||
's' => new Step('s', 'action', 'test:action', [], []),
|
||||
],
|
||||
]);
|
||||
|
||||
$subjectTransformer = $this->createMock(SubjectTransformerHandler::class);
|
||||
$subjectTransformer->expects($this->any())->method('subjectKeysForAutomation')->willReturnCallback(function($a) use ($automation) {
|
||||
return $a === $automation ? ['subject-a', 'subject-b'] : [];
|
||||
});
|
||||
$rule = new ValidStepOrderRule($registry, $subjectTransformer);
|
||||
|
||||
(new AutomationWalker())->walk($automation, [$rule]);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user