Simplify SubjectTransformer

[MAILPOET-4935]
This commit is contained in:
David Remer
2023-03-27 13:55:17 +03:00
committed by Aschepikov
parent 68f09b6bd1
commit 8cf48d2707
6 changed files with 81 additions and 179 deletions

View File

@@ -5,8 +5,6 @@ namespace MailPoet\Automation\Engine\Control;
use MailPoet\Automation\Engine\Data\Automation;
use MailPoet\Automation\Engine\Data\Step as StepData;
use MailPoet\Automation\Engine\Data\Subject;
use MailPoet\Automation\Engine\Integration\Step;
use MailPoet\Automation\Engine\Integration\SubjectTransformer;
use MailPoet\Automation\Engine\Integration\Trigger;
use MailPoet\Automation\Engine\Registry;
@@ -21,181 +19,85 @@ class SubjectTransformerHandler {
$this->registry = $registry;
}
public function subjectKeysForTrigger(Trigger $trigger): array {
$subjectKeys = $trigger->getSubjectKeys();
$possibleKeys = [];
foreach ($subjectKeys as $key) {
$possibleKeys = array_merge($possibleKeys, $this->getPossibleTransformations($key));
}
return array_unique(array_values(array_merge($subjectKeys, $possibleKeys)));
}
/** @return string[] */
public function subjectKeysForAutomation(Automation $automation): array {
$configuredTriggers = array_filter(
public function getSubjectKeysForAutomation(Automation $automation): array {
$triggerData = array_values(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 = [];
$triggers = array_filter(array_map(
function (StepData $step): ?Trigger {
return $this->registry->getTrigger($step->getKey());
},
$triggerData
));
$all = [];
foreach ($triggers as $trigger) {
$triggerKeys[$trigger->getKey()] = $trigger->getSubjectKeys();
$all[] = $this->getSubjectKeysForTrigger($trigger);
}
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)));
$all = count($all) > 1 ? array_intersect(...$all) : $all[0] ?? [];
return array_values(array_unique($all));
}
private function getPossibleTransformations(string $key, string $stopKey = null): array {
if (!$stopKey) {
$stopKey = $key;
public function getSubjectKeysForTrigger(Trigger $trigger): array {
$all = [];
foreach ($trigger->getSubjectKeys() as $key) {
$all = array_merge($all, $this->getSubjectKeysForSingleKey($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 $all;
}
/**
* @param Trigger $trigger
* @param Subject ...$subjects
* @return Subject[]
*/
public function provideAllSubjects(Trigger $trigger, Subject ...$subjects): array {
$allSubjectsKeys = $this->subjectKeysForTrigger($trigger);
$allSubjectKeyTargets = array_filter(
array_diff($allSubjectsKeys, array_map(
function(Subject $subject): string {
return $subject->getKey();
},
$subjects
)),
function(string $target) use ($subjects): bool {
return $this->canSubjectsTransformTo($target, ...$subjects);
}
);
$allSubjects = [];
foreach ($subjects as $existingSubject) {
$allSubjects[$existingSubject->getKey()] = $existingSubject;
}
foreach ($allSubjectKeyTargets as $target) {
if (isset($allSubjects[$target])) {
continue;
}
foreach ($subjects as $subject) {
$transformedSubject = $this->transformSubjectTo($subject, $target);
if ($transformedSubject) {
$allSubjects[$transformedSubject->getKey()] = $transformedSubject;
}
}
}
$allSubjectsTransformed = true;
do {
foreach ($allSubjectKeyTargets as $key) {
if (!isset($allSubjects[$key])) {
$allSubjectsTransformed = false;
break;
}
}
$allSubjects = $allSubjectsTransformed ? $allSubjects : $this->provideAllSubjects($trigger, ...array_values($allSubjects));
} while (!$allSubjectsTransformed);
return array_values($allSubjects);
}
private function transformSubjectTo(Subject $subject, string $target): ?Subject {
$transformerChain = $this->getTransformerChain($subject->getKey(), $target);
if (!$transformerChain) {
return null;
}
foreach ($transformerChain as $transformer) {
$subject = $transformer->transform($subject);
}
return $subject;
}
/**
* @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;
}
private function canSubjectsTransformTo(string $target, Subject ...$subjects): bool {
if (
in_array($target, array_map(
function(Subject $subject): string {
return $subject->getKey();
},
$subjects
))
) {
return true;
}
public function getAllSubjects(Subject ...$subjects): array {
$transformerMap = $this->getTransformerMap();
$all = [];
foreach ($subjects as $subject) {
$possibleTransformations = $this->getPossibleTransformations($subject->getKey());
if (in_array($target, $possibleTransformations)) {
return true;
$all[$subject->getKey()] = $subject;
}
$queue = array_map(
function(Subject $subject): string {
return $subject->getKey();
},
$subjects
);
while ($key = array_shift($queue)) {
foreach ($transformerMap[$key] ?? [] as $transformer) {
$newKey = $transformer->returns();
if (!isset($all[$newKey])) {
$all[$newKey] = $transformer->transform($all[$key]);
$queue[] = $newKey;
}
}
}
return false;
return array_values($all);
}
private function getTransformerMap(): array {
$transformerMap = [];
foreach ($this->registry->getSubjectTransformer() as $transformer) {
$transformerMap[$transformer->accepts()] = array_merge($transformerMap[$transformer->accepts()] ?? [], [$transformer]);
}
return $transformerMap;
}
/**
* @return string[]
*/
private function getSubjectKeysForSingleKey(string $subjectKey): array {
$transformerMap = $this->getTransformerMap();
$all = [$subjectKey];
$queue = [$subjectKey];
while ($key = array_shift($queue)) {
foreach ($transformerMap[$key] ?? [] as $transformer) {
$newKey = $transformer->returns();
if (!in_array($newKey, $all, true)) {
$all[] = $newKey;
$queue[] = $newKey;
}
}
}
return $all;
}
}