Add hook and basic handler for automation triggers

For now trigger keys are stored in the workflow as a JSON array.
This is not optimal in case someone has many workflows but as
workflows are user-created it's unlinkely someone will have thousands
of them. We can consider adding a workflow_triggers table as well.

[MAILPOET-4136]
This commit is contained in:
Jan Jakes
2022-03-07 11:59:54 +01:00
committed by Veljko V
parent 933ee0c8c8
commit a191c691f5
6 changed files with 80 additions and 0 deletions

View File

@ -0,0 +1,46 @@
<?php declare(strict_types = 1);
namespace MailPoet\Automation\Engine\Control;
use MailPoet\Automation\Engine\Exceptions;
use MailPoet\Automation\Engine\Hooks;
use MailPoet\Automation\Engine\Storage\WorkflowStorage;
use MailPoet\Automation\Engine\WordPress;
use MailPoet\Automation\Engine\Workflows\Trigger;
class TriggerHandler {
/** @var ActionScheduler */
private $actionScheduler;
/** @var WordPress */
private $wordPress;
/** @var WorkflowStorage */
private $workflowStorage;
public function __construct(
ActionScheduler $actionScheduler,
WordPress $wordPress,
WorkflowStorage $workflowStorage
) {
$this->actionScheduler = $actionScheduler;
$this->wordPress = $wordPress;
$this->workflowStorage = $workflowStorage;
}
public function initialize(): void {
$this->wordPress->addAction(Hooks::TRIGGER, [$this, 'processTrigger']);
}
public function processTrigger(Trigger $trigger): void {
$workflows = $this->workflowStorage->getActiveWorkflowsByTrigger($trigger);
foreach ($workflows as $workflow) {
$step = $workflow->getTrigger($trigger->getKey());
if (!$step) {
throw Exceptions::workflowTriggerNotFound($workflow->getId(), $trigger->getKey());
}
// TODO: create new workflow run
}
}
}

View File

@ -3,6 +3,7 @@
namespace MailPoet\Automation\Engine;
use MailPoet\Automation\Engine\API\API;
use MailPoet\Automation\Engine\Control\TriggerHandler;
use MailPoet\Automation\Engine\Storage\WorkflowStorage;
class Engine {
@ -12,6 +13,9 @@ class Engine {
/** @var Registry */
private $registry;
/** @var TriggerHandler */
private $triggerHandler;
/** @var WordPress */
private $wordPress;
@ -21,11 +25,13 @@ class Engine {
public function __construct(
API $api,
Registry $registry,
TriggerHandler $triggerHandler,
WordPress $wordPress,
WorkflowStorage $workflowStorage
) {
$this->api = $api;
$this->registry = $registry;
$this->triggerHandler = $triggerHandler;
$this->wordPress = $wordPress;
$this->workflowStorage = $workflowStorage;
}
@ -35,6 +41,7 @@ class Engine {
require_once __DIR__ . '/../../../vendor/woocommerce/action-scheduler/action-scheduler.php';
$this->api->initialize();
$this->triggerHandler->initialize();
$this->wordPress->doAction(Hooks::INITIALIZE, [$this->registry]);
$this->registerActiveTriggerHooks();

View File

@ -3,6 +3,7 @@
namespace MailPoet\Automation\Engine;
use MailPoet\Automation\Engine\Exceptions\InvalidStateException;
use MailPoet\Automation\Engine\Exceptions\NotFoundException;
use MailPoet\Automation\Engine\Exceptions\UnexpectedValueException;
class Exceptions {
@ -10,6 +11,7 @@ class Exceptions {
private const DATABASE_ERROR = 'mailpoet_automation_database_error';
private const API_METHOD_NOT_ALLOWED = 'mailpoet_automation_api_method_not_allowed';
private const API_NO_JSON_BODY = 'mailpoet_automation_api_no_json_body';
private const WORKFLOW_TRIGGER_NOT_FOUND = 'mailpoet_automation_workflow_trigger_not_found';
public function __construct() {
throw new InvalidStateException(
@ -41,4 +43,10 @@ class Exceptions {
->withErrorCode(self::API_NO_JSON_BODY)
->withMessage(__('No JSON body passed.', 'mailpoet'));
}
public static function workflowTriggerNotFound(int $workflowId, string $key): NotFoundException {
return NotFoundException::create()
->withErrorCode(self::WORKFLOW_TRIGGER_NOT_FOUND)
->withMessage(__(sprintf("Workflow trigger with key '%s' not found in workflow ID '%s'.", $key, $workflowId), 'mailpoet'));
}
}

View File

@ -4,4 +4,5 @@ namespace MailPoet\Automation\Engine;
class Hooks {
public const INITIALIZE = 'mailpoet/automation/initialize';
public const TRIGGER = 'mailpoet/automation/trigger';
}

View File

@ -3,6 +3,7 @@
namespace MailPoet\Automation\Engine\Storage;
use MailPoet\Automation\Engine\Exceptions;
use MailPoet\Automation\Engine\Workflows\Trigger;
use MailPoet\Automation\Engine\Workflows\Workflow;
use wpdb;
@ -45,4 +46,20 @@ class WorkflowStorage {
}
return array_unique($triggerKeys);
}
/** @return Workflow[] */
public function getActiveWorkflowsByTrigger(Trigger $trigger): array {
$query = strval(
$this->wpdb->prepare(
"SELECT * FROM $this->table WHERE status = %s AND trigger_keys LIKE %s",
Workflow::STATUS_ACTIVE,
'%' . $this->wpdb->esc_like($trigger->getKey()) . '%'
)
);
$data = $this->wpdb->get_results($query, ARRAY_A);
return array_map(function (array $workflowData) {
return Workflow::fromArray($workflowData);
}, (array)$data);
}
}

View File

@ -108,6 +108,7 @@ class ContainerConfigurator implements IContainerConfigurator {
$container->autowire(\MailPoet\Automation\Engine\API\Endpoints\SystemDatabaseEndpoint::class)->setPublic(true);
$container->autowire(\MailPoet\Automation\Engine\API\Endpoints\WorkflowsEndpoint::class)->setPublic(true);
$container->autowire(\MailPoet\Automation\Engine\Builder\CreateWorkflowController::class)->setPublic(true);
$container->autowire(\MailPoet\Automation\Engine\Control\TriggerHandler::class)->setPublic(true);
$container->autowire(\MailPoet\Automation\Engine\Engine::class)->setPublic(true);
$container->autowire(\MailPoet\Automation\Engine\Migrations\Migrator::class)->setPublic(true);
$container->autowire(\MailPoet\Automation\Engine\Registry::class)->setPublic(true);