Introduce template storage and rebuild create form template endpoint
[MAILPOET-4538]
This commit is contained in:
@@ -4,6 +4,7 @@ namespace MailPoet\Automation\Engine\Builder;
|
||||
|
||||
use MailPoet\Automation\Engine\Data\Workflow;
|
||||
use MailPoet\Automation\Engine\Storage\WorkflowStorage;
|
||||
use MailPoet\Automation\Engine\Storage\WorkflowTemplateStorage;
|
||||
use MailPoet\Automation\Integrations\MailPoet\Templates\WorkflowBuilder;
|
||||
use MailPoet\UnexpectedValueException;
|
||||
|
||||
@@ -11,33 +12,25 @@ class CreateWorkflowFromTemplateController {
|
||||
/** @var WorkflowStorage */
|
||||
private $storage;
|
||||
|
||||
/** @var WorkflowBuilder */
|
||||
private $templates;
|
||||
/** @var WorkflowTemplateStorage */
|
||||
private $templateStorage;
|
||||
|
||||
public function __construct(
|
||||
WorkflowStorage $storage,
|
||||
WorkflowBuilder $templates
|
||||
WorkflowTemplateStorage $templateStorage
|
||||
) {
|
||||
$this->storage = $storage;
|
||||
$this->templates = $templates;
|
||||
$this->templateStorage = $templateStorage;
|
||||
}
|
||||
|
||||
public function createWorkflow(array $data): Workflow {
|
||||
$name = $data['name'];
|
||||
$template = $data['template'];
|
||||
public function createWorkflow(string $slug): Workflow {
|
||||
|
||||
switch ($template) {
|
||||
case 'delayed-email-after-signup':
|
||||
$workflow = $this->templates->delayedEmailAfterSignupWorkflow($name);
|
||||
break;
|
||||
case 'welcome-email-sequence':
|
||||
$workflow = $this->templates->welcomeEmailSequence($name);
|
||||
break;
|
||||
default:
|
||||
throw UnexpectedValueException::create()->withMessage('Template not found.');
|
||||
$template = $this->templateStorage->getTemplateBySlug($slug);
|
||||
if (! $template) {
|
||||
throw UnexpectedValueException::create()->withMessage('Template not found.');
|
||||
}
|
||||
|
||||
$this->storage->createWorkflow($workflow);
|
||||
return $workflow;
|
||||
$this->storage->createWorkflow($template->getWorkflow());
|
||||
return $template->getWorkflow();
|
||||
}
|
||||
}
|
||||
|
@@ -18,8 +18,8 @@ class WorkflowTemplate
|
||||
self::CATEGORY_WOOCOMMERCE,
|
||||
];
|
||||
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var string */
|
||||
private $slug;
|
||||
|
||||
/** @var int */
|
||||
private $category;
|
||||
@@ -30,18 +30,18 @@ class WorkflowTemplate
|
||||
/** @var Workflow */
|
||||
private $workflow;
|
||||
|
||||
public function __construct(int $id, int $category, string $description, Workflow $workflow) {
|
||||
public function __construct(string $slug, int $category, string $description, Workflow $workflow) {
|
||||
if (! in_array($category, self::ALL_CATEGORIES)) {
|
||||
throw new RuntimeException("$category is not a valid category.");
|
||||
}
|
||||
$this->id = $id;
|
||||
$this->slug = $slug;
|
||||
$this->category = $category;
|
||||
$this->description = $description;
|
||||
$this->workflow = $workflow;
|
||||
}
|
||||
|
||||
public function getId() : int {
|
||||
return $this->id;
|
||||
public function getSlug() : string {
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function getName() : string {
|
||||
@@ -62,7 +62,7 @@ class WorkflowTemplate
|
||||
|
||||
public function toArray() : array {
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'slug' => $this->getSlug(),
|
||||
'name' => $this->getName(),
|
||||
'category' => $this->getCategory(),
|
||||
'description' => $this->getDescription(),
|
||||
|
@@ -6,6 +6,8 @@ use MailPoet\Automation\Engine\API\Endpoint;
|
||||
use MailPoet\Automation\Engine\API\Request;
|
||||
use MailPoet\Automation\Engine\API\Response;
|
||||
use MailPoet\Automation\Engine\Builder\CreateWorkflowFromTemplateController;
|
||||
use MailPoet\RuntimeException;
|
||||
use MailPoet\UnexpectedValueException;
|
||||
use MailPoet\Validator\Builder;
|
||||
|
||||
class WorkflowsCreateFromTemplateEndpoint extends Endpoint {
|
||||
@@ -19,15 +21,13 @@ class WorkflowsCreateFromTemplateEndpoint extends Endpoint {
|
||||
}
|
||||
|
||||
public function handle(Request $request): Response {
|
||||
$data = $request->getParams();
|
||||
$this->createWorkflowFromTemplateController->createWorkflow($data);
|
||||
$this->createWorkflowFromTemplateController->createWorkflow((string)$request->getParam('slug'));
|
||||
return new Response();
|
||||
}
|
||||
|
||||
public static function getRequestSchema(): array {
|
||||
return [
|
||||
'name' => Builder::string()->required(),
|
||||
'template' => Builder::string()->required(),
|
||||
'slug' => Builder::string()->required(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,8 @@ class Hooks {
|
||||
public const WORKFLOW_BEFORE_SAVE = 'mailpoet/automation/workflow/before_save';
|
||||
public const WORKFLOW_STEP_BEFORE_SAVE = 'mailpoet/automation/workflow/step/before_save';
|
||||
|
||||
public const WORKFLOW_TEMPLATES = 'mailpoet/automation/workflow/templates';
|
||||
|
||||
public function doWorkflowBeforeSave(Workflow $workflow): void {
|
||||
$this->wordPress->doAction(self::WORKFLOW_BEFORE_SAVE, $workflow);
|
||||
}
|
||||
|
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Automation\Engine\Storage;
|
||||
|
||||
use MailPoet\Automation\Engine\Data\WorkflowTemplate;
|
||||
use MailPoet\Automation\Engine\Hooks;
|
||||
use MailPoet\Automation\Integrations\Core\Actions\DelayAction;
|
||||
use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction;
|
||||
use MailPoet\Automation\Integrations\MailPoet\Templates\WorkflowBuilder;
|
||||
use MailPoet\Automation\Integrations\MailPoet\Triggers\SegmentSubscribedTrigger;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class WorkflowTemplateStorage
|
||||
{
|
||||
|
||||
/** @var WorkflowTemplate[] */
|
||||
private $templates = [];
|
||||
|
||||
/** @var WorkflowBuilder */
|
||||
private $builder;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(WorkflowBuilder $builder, WPFunctions $wp) {
|
||||
$this->builder = $builder;
|
||||
$this->wp = $wp;
|
||||
$this->templates = $this->createTemplates();
|
||||
}
|
||||
|
||||
public function getTemplateBySlug(string $slug) : ?WorkflowTemplate {
|
||||
foreach ($this->templates as $template) {
|
||||
if ($template->getSlug() === $slug) {
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return WorkflowTemplate[] */
|
||||
public function getTemplates(int $category = null) : array {
|
||||
if (! $category) {
|
||||
return $this->templates;
|
||||
}
|
||||
return array_values(
|
||||
array_filter(
|
||||
$this->templates,
|
||||
function(WorkflowTemplate $template) use ($category) : bool {
|
||||
return $template->getCategory() === $category;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function createTemplates() : array {
|
||||
$simpleWelcomeEmail = new WorkflowTemplate(
|
||||
'simple-welcome-email',
|
||||
WorkflowTemplate::CATEGORY_WELCOME,
|
||||
"Automation template description is going to be here. Let's describe a lot of interesting ideas which incorporated into this beautiful and useful template",
|
||||
$this->builder->createFromSequence(
|
||||
__('Simple welcome email', 'mailpoet'),
|
||||
[
|
||||
SegmentSubscribedTrigger::class,
|
||||
DelayAction::class,
|
||||
SendEmailAction::class,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$templates = $this->wp->applyFilters(Hooks::WORKFLOW_TEMPLATES,[
|
||||
$simpleWelcomeEmail,
|
||||
]);
|
||||
return is_array($templates)?$templates:[];
|
||||
}
|
||||
}
|
@@ -4,6 +4,8 @@ namespace MailPoet\Automation\Integrations\MailPoet\Templates;
|
||||
|
||||
use MailPoet\Automation\Engine\Data\Step;
|
||||
use MailPoet\Automation\Engine\Data\Workflow;
|
||||
use MailPoet\Automation\Engine\Data\WorkflowTemplate;
|
||||
use MailPoet\Automation\Engine\Workflows\Trigger;
|
||||
use MailPoet\Automation\Integrations\Core\Actions\DelayAction;
|
||||
use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction;
|
||||
use MailPoet\Automation\Integrations\MailPoet\Triggers\SegmentSubscribedTrigger;
|
||||
@@ -12,115 +14,28 @@ use MailPoet\Validator\Schema\ObjectSchema;
|
||||
|
||||
class WorkflowBuilder {
|
||||
|
||||
/** @var DelayAction */
|
||||
private $delayAction;
|
||||
|
||||
/** @var SegmentSubscribedTrigger */
|
||||
private $segmentSubscribedTrigger;
|
||||
|
||||
/** @var SendEmailAction */
|
||||
private $sendEmailAction;
|
||||
|
||||
public function __construct(
|
||||
SegmentSubscribedTrigger $segmentSubscribedTrigger,
|
||||
SendEmailAction $sendEmailAction,
|
||||
DelayAction $delayAction
|
||||
) {
|
||||
$this->delayAction = $delayAction;
|
||||
$this->segmentSubscribedTrigger = $segmentSubscribedTrigger;
|
||||
$this->sendEmailAction = $sendEmailAction;
|
||||
}
|
||||
|
||||
public function delayedEmailAfterSignupWorkflow(string $name): Workflow {
|
||||
$triggerStep = $this->segmentSubscribedTriggerStep();
|
||||
|
||||
$delayStep = $this->delayStep(null, "HOURS");
|
||||
$triggerStep->setNextStepId($delayStep->getId());
|
||||
|
||||
$sendEmailStep = $this->sendEmailActionStep();
|
||||
$delayStep->setNextStepId($sendEmailStep->getId());
|
||||
|
||||
$steps = [
|
||||
$triggerStep,
|
||||
$delayStep,
|
||||
$sendEmailStep,
|
||||
];
|
||||
|
||||
return new Workflow($name, $steps);
|
||||
}
|
||||
|
||||
public function welcomeEmailSequence(string $name): Workflow {
|
||||
$triggerStep = $this->segmentSubscribedTriggerStep();
|
||||
|
||||
$firstDelayStep = $this->delayStep(null, 'HOURS');
|
||||
$triggerStep->setNextStepId($firstDelayStep->getId());
|
||||
|
||||
$sendFirstEmailStep = $this->sendEmailActionStep();
|
||||
$firstDelayStep->setNextStepId($sendFirstEmailStep->getId());
|
||||
|
||||
$secondDelayStep = $this->delayStep(null, 'HOURS');
|
||||
$sendFirstEmailStep->setNextStepId($secondDelayStep->getId());
|
||||
|
||||
$sendSecondEmailStep = $this->sendEmailActionStep();
|
||||
$secondDelayStep->setNextStepId($sendSecondEmailStep->getId());
|
||||
|
||||
$steps = [
|
||||
$triggerStep,
|
||||
$firstDelayStep,
|
||||
$sendFirstEmailStep,
|
||||
$secondDelayStep,
|
||||
$sendSecondEmailStep,
|
||||
];
|
||||
|
||||
return new Workflow($name, $steps);
|
||||
}
|
||||
|
||||
private function delayStep(?int $delay, string $delayType): Step {
|
||||
return new Step(
|
||||
$this->uniqueId(),
|
||||
Step::TYPE_ACTION,
|
||||
$this->delayAction->getKey(),
|
||||
null,
|
||||
[
|
||||
'delay' => $delay,
|
||||
'delay_type' => $delayType,
|
||||
] + $this->getDefaultArgs($this->delayAction->getArgsSchema())
|
||||
);
|
||||
}
|
||||
|
||||
private function segmentSubscribedTriggerStep(?int $segmentId = null): Step {
|
||||
return new Step(
|
||||
$this->uniqueId(),
|
||||
Step::TYPE_TRIGGER,
|
||||
$this->segmentSubscribedTrigger->getKey(),
|
||||
null,
|
||||
[
|
||||
'segment_id' => $segmentId,
|
||||
] + $this->getDefaultArgs($this->segmentSubscribedTrigger->getArgsSchema())
|
||||
);
|
||||
}
|
||||
|
||||
private function sendEmailActionStep(): Step {
|
||||
return new Step(
|
||||
$this->uniqueId(),
|
||||
Step::TYPE_ACTION,
|
||||
$this->sendEmailAction->getKey(),
|
||||
null,
|
||||
$this->getDefaultArgs($this->sendEmailAction->getArgsSchema())
|
||||
public function createFromSequence(string $name, array $sequence, array $sequenceArgs = []) : Workflow {
|
||||
$steps = [];
|
||||
$nextStep = null;
|
||||
foreach (array_reverse($sequence) as $index => $stepClass) {
|
||||
$step = new Step(
|
||||
$this->uniqueId(),
|
||||
in_array(Trigger::class, (array) class_implements($stepClass)) ? Step::TYPE_TRIGGER : Step::TYPE_ACTION,
|
||||
$stepClass::getKey(),
|
||||
$nextStep,
|
||||
array_reverse($sequenceArgs)[$index] ?? []
|
||||
);
|
||||
$nextStep = $step->getId();
|
||||
$steps[] = $step;
|
||||
}
|
||||
$steps = array_reverse($steps);
|
||||
return new Workflow(
|
||||
$name,
|
||||
$steps
|
||||
);
|
||||
}
|
||||
|
||||
private function uniqueId(): string {
|
||||
return Security::generateRandomString(16);
|
||||
}
|
||||
|
||||
private function getDefaultArgs(ObjectSchema $argsSchema): array {
|
||||
$args = [];
|
||||
foreach ($argsSchema->toArray()['properties'] ?? [] as $name => $schema) {
|
||||
if (array_key_exists('default', $schema)) {
|
||||
$args[$name] = $schema['default'];
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
@@ -121,6 +121,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
||||
$container->autowire(\MailPoet\Automation\Engine\Migrations\Migrator::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Registry::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Storage\WorkflowRunStorage::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Storage\WorkflowTemplateStorage::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\Storage\WorkflowStorage::class)->setPublic(true);
|
||||
$container->autowire(\MailPoet\Automation\Engine\WordPress::class)->setPublic(true);
|
||||
// Automation - API endpoints
|
||||
|
@@ -1,6 +1,11 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
|
||||
-
|
||||
message: "#^Cannot cast mixed to string\\.$#"
|
||||
count: 1
|
||||
path: ../../lib/Automation/Engine/Endpoints/Workflows/WorkflowsCreateFromTemplateEndpoint.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access property \\$permissions on mixed\\.$#"
|
||||
count: 1
|
||||
|
@@ -1,6 +1,15 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
|
||||
-
|
||||
message: "#^Cannot cast mixed to string\\.$#"
|
||||
count: 1
|
||||
path: ../../lib/Automation/Engine/Endpoints/Workflows/WorkflowsCreateFromTemplateEndpoint.php
|
||||
-
|
||||
message: "#^Cannot cast mixed to int\\.$#"
|
||||
count: 1
|
||||
path: ../../lib/Automation/Engine/Endpoints/Workflows/WorkflowTemplatesGetEndpoint.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access property \\$permissions on mixed\\.$#"
|
||||
count: 1
|
||||
|
@@ -1,5 +1,15 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Cannot cast mixed to string\\.$#"
|
||||
count: 1
|
||||
path: ../../lib/Automation/Engine/Endpoints/Workflows/WorkflowsCreateFromTemplateEndpoint.php
|
||||
-
|
||||
message: "#^Cannot cast mixed to int\\.$#"
|
||||
count: 1
|
||||
path: ../../lib/Automation/Engine/Endpoints/Workflows/WorkflowTemplatesGetEndpoint.php
|
||||
|
||||
|
||||
-
|
||||
message: "#^Cannot cast string|void to string\\.$#"
|
||||
count: 2
|
||||
|
@@ -16,8 +16,7 @@ class WorkflowsCreateFromTemplateTest extends AutomationTest {
|
||||
$countBefore = count($storage->getWorkflows());
|
||||
$this->post(self::ENDPOINT_PATH, [
|
||||
'json' => [
|
||||
'name' => 'Testing workflow from template',
|
||||
'template' => 'delayed-email-after-signup'
|
||||
'slug' => 'simple-welcome-email'
|
||||
],
|
||||
]);
|
||||
$countAfter = count($storage->getWorkflows());
|
||||
@@ -28,8 +27,7 @@ class WorkflowsCreateFromTemplateTest extends AutomationTest {
|
||||
$storage = ContainerWrapper::getInstance()->get(WorkflowStorage::class);
|
||||
$this->post(self::ENDPOINT_PATH, [
|
||||
'json' => [
|
||||
'name' => 'Testing workflow from template',
|
||||
'template' => 'delayed-email-after-signup'
|
||||
'slug' => 'simple-welcome-email'
|
||||
],
|
||||
]);
|
||||
$allWorkflows = $storage->getWorkflows();
|
||||
|
Reference in New Issue
Block a user