Require subjects by class name to have them type checked and autocompleted

[MAILPOET-4465]
This commit is contained in:
Jan Jakes
2022-07-05 14:59:26 +02:00
committed by Veljko V
parent 841ee97203
commit 3cccc52515
3 changed files with 37 additions and 4 deletions

View File

@ -95,6 +95,12 @@ class Exceptions {
->withMessage(__(sprintf("Subject with key '%s' not found.", $key), 'mailpoet')); ->withMessage(__(sprintf("Subject with key '%s' not found.", $key), 'mailpoet'));
} }
public static function subjectClassNotFound(string $key): NotFoundException {
return NotFoundException::create()
->withErrorCode(self::SUBJECT_NOT_FOUND)
->withMessage(__(sprintf("Subject of class '%s' not found.", $key), 'mailpoet'));
}
public static function subjectLoadFailed(string $key, array $args): InvalidStateException { public static function subjectLoadFailed(string $key, array $args): InvalidStateException {
return InvalidStateException::create() return InvalidStateException::create()
->withErrorCode(self::SUBJECT_LOAD_FAILED) ->withErrorCode(self::SUBJECT_LOAD_FAILED)

View File

@ -4,6 +4,7 @@ namespace MailPoet\Automation\Engine\Workflows;
use DateTimeImmutable; use DateTimeImmutable;
use MailPoet\Automation\Engine\Exceptions; use MailPoet\Automation\Engine\Exceptions;
use MailPoet\Automation\Engine\Exceptions\InvalidStateException;
use MailPoet\Automation\Engine\Utils\Json; use MailPoet\Automation\Engine\Utils\Json;
class WorkflowRun { class WorkflowRun {
@ -33,6 +34,12 @@ class WorkflowRun {
/** @var Subject[] */ /** @var Subject[] */
private $subjects; private $subjects;
/** @var array<class-string, string> */
private $subjectKeyClassMap = [];
/**
* @param Subject[] $subjects
*/
public function __construct( public function __construct(
int $workflowId, int $workflowId,
string $triggerKey, string $triggerKey,
@ -43,6 +50,10 @@ class WorkflowRun {
$this->triggerKey = $triggerKey; $this->triggerKey = $triggerKey;
$this->subjects = $subjects; $this->subjects = $subjects;
foreach ($subjects as $subject) {
$this->subjectKeyClassMap[get_class($subject)] = $subject->getKey();
}
if ($id) { if ($id) {
$this->id = $id; $this->id = $id;
} }
@ -88,7 +99,17 @@ class WorkflowRun {
return $this->subjects; return $this->subjects;
} }
public function requireSubject(string $key): Subject { /**
* @template T of Subject
* @param class-string<T> $class
* @return T
*/
public function requireSubject(string $class): Subject {
$key = $this->subjectKeyClassMap[$class] ?? null;
if (!$key) {
throw Exceptions::subjectClassNotFound($class);
}
$subjects = $this->getSubjects($key); $subjects = $this->getSubjects($key);
if (count($subjects) === 0) { if (count($subjects) === 0) {
throw Exceptions::subjectNotFound($key); throw Exceptions::subjectNotFound($key);
@ -96,7 +117,13 @@ class WorkflowRun {
if (count($subjects) > 1) { if (count($subjects) > 1) {
throw Exceptions::multipleSubjectsFound($key); throw Exceptions::multipleSubjectsFound($key);
} }
return $subjects[0];
// ensure PHPStan we're indeed returning an instance of $class
$subject = $subjects[0];
if (!$subject instanceof $class) {
throw new InvalidStateException();
}
return $subject;
} }
public function toArray(): array { public function toArray(): array {

View File

@ -76,7 +76,7 @@ class SendWelcomeEmailAction implements Action {
public function run(Workflow $workflow, WorkflowRun $workflowRun, Step $step): void { public function run(Workflow $workflow, WorkflowRun $workflowRun, Step $step): void {
$newsletter = $this->getWelcomeEmailForStep($step); $newsletter = $this->getWelcomeEmailForStep($step);
$subscriberSubject = $workflowRun->requireSubject(SubscriberSubject::KEY); $subscriberSubject = $workflowRun->requireSubject(SubscriberSubject::class);
$subscriberId = $subscriberSubject->getFields()['id']->getValue(); $subscriberId = $subscriberSubject->getFields()['id']->getValue();
$subscriber = $this->subscribersRepository->findOneById($subscriberId); $subscriber = $this->subscribersRepository->findOneById($subscriberId);
@ -88,7 +88,7 @@ class SendWelcomeEmailAction implements Action {
throw InvalidStateException::create()->withMessage(sprintf("Cannot schedule a newsletter for subscriber ID '%s' because their status is '%s'.", $subscriber->getId(), $subscriber->getStatus())); throw InvalidStateException::create()->withMessage(sprintf("Cannot schedule a newsletter for subscriber ID '%s' because their status is '%s'.", $subscriber->getId(), $subscriber->getStatus()));
} }
$segmentSubject = $workflowRun->requireSubject(SegmentSubject::KEY); $segmentSubject = $workflowRun->requireSubject(SegmentSubject::class);
$segmentId = $segmentSubject->getFields()['id']->getValue(); $segmentId = $segmentSubject->getFields()['id']->getValue();
$subscriberSegment = $this->subscriberSegmentRepository->findOneBy([ $subscriberSegment = $this->subscriberSegmentRepository->findOneBy([
'subscriber' => $subscriber, 'subscriber' => $subscriber,