From 68f09b6bd13ea4cfd926dd5251b85c7126a8974d Mon Sep 17 00:00:00 2001 From: David Remer Date: Mon, 20 Mar 2023 12:14:48 +0200 Subject: [PATCH] Prevent infinite loop when a subject from the trigger is missing Given the trigger provides two subjects but only one subject was given via parameter and no transformer was able to generate the second from the first, this method runs into an infinite loop. This commit prevents this infinite loop. [MAILPOET-4935] --- .../Control/SubjectTransformerHandler.php | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/mailpoet/lib/Automation/Engine/Control/SubjectTransformerHandler.php b/mailpoet/lib/Automation/Engine/Control/SubjectTransformerHandler.php index 951eba6051..470bde3598 100644 --- a/mailpoet/lib/Automation/Engine/Control/SubjectTransformerHandler.php +++ b/mailpoet/lib/Automation/Engine/Control/SubjectTransformerHandler.php @@ -96,12 +96,17 @@ class SubjectTransformerHandler { */ public function provideAllSubjects(Trigger $trigger, Subject ...$subjects): array { $allSubjectsKeys = $this->subjectKeysForTrigger($trigger); - $allSubjectKeyTargets = array_diff($allSubjectsKeys, array_map( + $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) { @@ -118,9 +123,17 @@ class SubjectTransformerHandler { } } } - while (count($allSubjects) < count($allSubjectsKeys)) { - $allSubjects = $this->provideAllSubjects($trigger, ...array_values($allSubjects)); - } + + $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); } @@ -164,4 +177,25 @@ class SubjectTransformerHandler { 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; + } + + foreach ($subjects as $subject) { + $possibleTransformations = $this->getPossibleTransformations($subject->getKey()); + if (in_array($target, $possibleTransformations)) { + return true; + } + } + return false; + } }