<?php declare(strict_types = 1);
namespace MailPoet\Automation\Integrations\MailPoet\Actions;
if (!defined('ABSPATH')) exit;
use MailPoet\Automation\Engine\Control\SubjectTransformerHandler;
use MailPoet\Automation\Engine\Data\Automation;
use MailPoet\Automation\Engine\Data\Step;
use MailPoet\Automation\Engine\Registry;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\NewsletterOptionFieldEntity;
class AutomationSendEmailSubjectResolver {
private Registry $registry;
private SubjectTransformerHandler $subjectTransformerHandler;
public function __construct(
Registry $registry,
SubjectTransformerHandler $subjectTransformerHandler
) {
$this->registry = $registry;
$this->subjectTransformerHandler = $subjectTransformerHandler;
}
/** @return string[] */
public function getGuaranteedSubjectKeysForStep(Automation $automation, Step $sendEmailStep): array {
if ($sendEmailStep->getKey() !== SendEmailAction::KEY) {
return [];
}
$triggerSteps = $this->getTriggerStepsReachingStep($automation, $sendEmailStep);
if ($triggerSteps === []) {
return [];
}
return $this->intersectTriggerSubjectKeys($triggerSteps);
}
/** @return string[] */
public function getGuaranteedSubjectKeysForEmail(Automation $automation, NewsletterEntity $newsletter): array {
$exactStep = $this->getExactSendEmailStep($automation, $newsletter);
if ($exactStep) {
return $this->getGuaranteedSubjectKeysForStep($automation, $exactStep);
}
$steps = $this->getSendEmailStepsReferencingNewsletter($automation, $newsletter);
if ($steps === []) {
return [];
}
$subjectKeySets = array_map(function (Step $step) use ($automation): array {
return $this->getGuaranteedSubjectKeysForStep($automation, $step);
}, $steps);
return $this->intersectSubjectKeySets($subjectKeySets);
}
public function hasGuaranteedSubjectForEmail(Automation $automation, NewsletterEntity $newsletter, string $subjectKey): bool {
return in_array($subjectKey, $this->getGuaranteedSubjectKeysForEmail($automation, $newsletter), true);
}
/** @return Step[] */
private function getTriggerStepsReachingStep(Automation $automation, Step $targetStep): array {
$triggerSteps = [];
foreach ($automation->getTriggers() as $triggerStep) {
if ($this->stepCanReachStep($automation, $triggerStep, $targetStep)) {
$triggerSteps[] = $triggerStep;
}
}
return $triggerSteps;
}
private function stepCanReachStep(Automation $automation, Step $fromStep, Step $toStep): bool {
$steps = $automation->getSteps();
$stack = [$fromStep->getId()];
$visited = [];
while ($stack !== []) {
$stepId = array_pop($stack);
if (!is_string($stepId) || isset($visited[$stepId])) {
continue;
}
$visited[$stepId] = true;
if ($stepId === $toStep->getId()) {
return true;
}
$step = $steps[$stepId] ?? null;
if (!$step instanceof Step) {
continue;
}
foreach ($step->getNextStepIds() as $nextStepId) {
$stack[] = $nextStepId;
}
}
return false;
}
/** @param Step[] $triggerSteps */
private function intersectTriggerSubjectKeys(array $triggerSteps): array {
$subjectKeySets = [];
foreach ($triggerSteps as $triggerStep) {
$trigger = $this->registry->getTrigger($triggerStep->getKey());
if (!$trigger) {
return [];
}
$subjectKeySets[] = $this->subjectTransformerHandler->getSubjectKeysForTrigger($trigger);
}
return $this->intersectSubjectKeySets($subjectKeySets);
}
/** @param array<int, string[]> $subjectKeySets */
private function intersectSubjectKeySets(array $subjectKeySets): array {
if ($subjectKeySets === []) {
return [];
}
$subjectKeys = array_shift($subjectKeySets);
foreach ($subjectKeySets as $nextSubjectKeys) {
$subjectKeys = array_values(array_intersect($subjectKeys, $nextSubjectKeys));
}
$subjectKeys = array_values(array_unique($subjectKeys));
sort($subjectKeys);
return $subjectKeys;
}
private function getExactSendEmailStep(Automation $automation, NewsletterEntity $newsletter): ?Step {
$stepId = $newsletter->getOptionValue(NewsletterOptionFieldEntity::NAME_AUTOMATION_STEP_ID);
if (!is_string($stepId) || $stepId === '') {
return null;
}
$step = $automation->getStep($stepId);
return $step instanceof Step && $step->getKey() === SendEmailAction::KEY ? $step : null;
}
/** @return Step[] */
private function getSendEmailStepsReferencingNewsletter(Automation $automation, NewsletterEntity $newsletter): array {
$newsletterId = $newsletter->getId();
$wpPostId = $newsletter->getWpPostId();
return array_values(array_filter($automation->getSteps(), function (Step $step) use ($newsletterId, $wpPostId): bool {
if ($step->getKey() !== SendEmailAction::KEY) {
return false;
}
$args = $step->getArgs();
$emailId = $args['email_id'] ?? null;
$emailWpPostId = $args['email_wp_post_id'] ?? null;
return ($newsletterId !== null && (int)$emailId === (int)$newsletterId)
|| ($wpPostId !== null && (int)$emailWpPostId === (int)$wpPostId);
}));
}
}