From 94f57e6121b86c33c5f88e00823fad3be3fcf509 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 21 Apr 2023 19:13:03 +0000 Subject: [PATCH] prepare workflows --- Admin/Install/Workflow.install.json | 31 ++++++++++++++------- Controller/ApiController.php | 43 +++++++++++++++++++++++++++++ Controller/CliController.php | 42 ++++++++++++++++++---------- Docs/workflow_components.md | 11 +++++++- Models/WorkflowInstance.php | 27 ++++++++++++++++++ 5 files changed, 128 insertions(+), 26 deletions(-) create mode 100644 Models/WorkflowInstance.php diff --git a/Admin/Install/Workflow.install.json b/Admin/Install/Workflow.install.json index 3e3a8c6..1df7ed0 100755 --- a/Admin/Install/Workflow.install.json +++ b/Admin/Install/Workflow.install.json @@ -21,8 +21,9 @@ "en": "Check condition", "de": "Überprüfe Bedingung" }, - "function_type": "API", + "function_type": "Api", "function": "apiValidateCondition", + "module": "Workflow", "inputs": [ "field_name", "field_value", @@ -181,8 +182,9 @@ "en": "Takes input data and forwards the data to another action. Check the outputs and inputs of the actions to create the correct mapping.", "de": "Übernimmt Eingangsdaten und leitet diese an eine andere Aktion weiter. Überprüfe die Ausgaben und Eingaben der jeweiligen Aktionen um die korrekten Verknüpfungen zu erstellen." }, - "function_type": "API", + "function_type": "Api", "function": "apiAdapter", + "module": "Workflow", "inputs": [ "map", "{*}" @@ -217,8 +219,9 @@ "en": "Listens to trigger", "de": "Wartet auf Trigger" }, - "function_type": "API", + "function_type": "Api", "function": "apiListenToTrigger", + "module": "Workflow", "inputs": [ "type", "trigger", @@ -328,8 +331,9 @@ "en": "Takes input data and forwards the data to another action. Check the outputs and inputs of the actions to create the correct mapping.", "de": "Übernimmt Eingangsdaten und leitet diese an eine andere Aktion weiter. Überprüfe die Ausgaben und Eingaben der jeweiligen Aktionen um die korrekten Verknüpfungen zu erstellen." }, - "function_type": "API", + "function_type": "Api", "function": "apiRun", + "module": "Workflow", "inputs": [ "map", "{*}" @@ -359,13 +363,18 @@ } }, "1005500005": { - "name": "Timed Trigger", + "name": "Timed Trigger (Job/Task)", "description": { - "en": "Timed trigger", - "de": "Wartet auf Trigger" + "en": "Timed trigger (Job/Task)", + "de": "Zeitgesteuerter Trigger (Job/Task)" }, - "function_type": "API", + "function_type": "Api", "function": "apiRun", + "module": "Workflow", + "function_install": { + "module": "Workflow", + "function": "installTimedTrigger" + }, "inputs": [ "interval", "{*}" @@ -398,8 +407,9 @@ "en": "Cli action", "de": "Konsolenbefehl" }, - "function_type": "API", + "function_type": "Api", "function": "apiRun", + "module": "Workflow", "inputs": [ "cmd", "{*}" @@ -432,8 +442,9 @@ "en": "Workflow script", "de": "Workflow Script" }, - "function_type": "API", + "function_type": "Api", "function": "apiRun", + "module": "Workflow", "inputs": [ "{*}" ], diff --git a/Controller/ApiController.php b/Controller/ApiController.php index ba6850a..44d2f9d 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -35,9 +35,12 @@ use phpOMS\Message\NotificationLevel; use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; use phpOMS\Model\Message\FormValidation; +use phpOMS\System\File\FileUtils; use phpOMS\System\MimeType; use phpOMS\Utils\Parser\Markdown\Markdown; use phpOMS\Utils\StringUtils; +use phpOMS\Utils\TaskSchedule\SchedulerFactory; +use phpOMS\Utils\TaskSchedule\TaskFactory; use phpOMS\Views\View; /** @@ -495,9 +498,49 @@ final class ApiController extends Controller $this->createDatabaseForTemplate($template); } + // perform other workflow installation actions + $actions = \json_decode(\file_get_contents(__DIR__ . '/../Definitions/actions.json'), true); + $this->installWorkflowModel($template, $actions); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Template', 'Template successfully created', $template); } + private function installWorkflowModel(WorkflowTemplate $template, array $actions) : void + { + $schema = $template->schema; + foreach ($schema as $primary) { + $id = $primary['id'] ?? ''; + + if (!isset($actions[$id]['function_install'])) { + continue; + } + + $this->app->moduleManager->get($actions[$id]['function_install']['module'])->{$actions[$id]['function_install']['function_install_function']}($template); + } + } + + public function installTimedTrigger(WorkflowTemplate $template) : void + { + $id = 'Workflow-' . $template->getId(); + $scheduler = SchedulerFactory::create(); + + if (!empty($scheduler->getAllByName($id))) { + return; + } + + $job = TaskFactory::create($id); + + $job->interval = $template->schema['settings']['interval'] ?? ''; + $job->command = 'php ' + . FileUtils::absolute(__DIR__ . '/../../../Cli/cli.php') + . ' /workflow/instance -id ' + . $template->getId() + . ' -trigger 1005500005'; + + $scheduler->create($job); + $scheduler->reload(); + } + /** * Parse and replace placeholder elements * diff --git a/Controller/CliController.php b/Controller/CliController.php index 0d2eb10..5943d9c 100755 --- a/Controller/CliController.php +++ b/Controller/CliController.php @@ -14,7 +14,9 @@ declare(strict_types=1); namespace Modules\Workflow\Controller; +use Modules\Workflow\Models\WorkflowInstance; use Modules\Workflow\Models\WorkflowInstanceAbstract; +use Modules\Workflow\Models\WorkflowInstanceAbstractMapper; use Modules\Workflow\Models\WorkflowStatus; use Modules\Workflow\Models\WorkflowTemplate; use Modules\Workflow\Models\WorkflowTemplateMapper; @@ -122,6 +124,21 @@ final class CliController extends Controller return $view; } + public function runWorkflowElement(array $actions, WorkflowTemplate $template, WorkflowInstanceAbstract $instance, array $element) : void + { + if (isset($actions[$element['id']])) { + $result = $this->app->moduleManager + ->get($actions[$element['id']]['modules'], $actions[$element['id']]['function_type']) + ->{$actions[$element['id']]['function']}($template); + } + + // @todo: currently all children are executed one after another, maybe consider parallel execution + foreach ($element['children'] as $child) { + // @todo: pass previous results (probably needs a populator for input variables based on previous output variables) + $this->runWorkflowElement($actions, $template, $instance, $child); + } + } + /** * Validate template create request * @@ -134,7 +151,7 @@ final class CliController extends Controller private function validateInstanceCreate(RequestAbstract $request) : array { $val = []; - if (($val['j'] = !$request->hasData('j'))) { + if (($val['id'] = !$request->hasData('id'))) { return $val; } @@ -147,6 +164,8 @@ final class CliController extends Controller * @param RequestAbstract $request Request * * @return WorkflowInstanceAbstract + * + * @todo: How to handle workflow instances which are not saved in the database and are continued? * * @since 1.0.0 */ @@ -154,28 +173,21 @@ final class CliController extends Controller { /** @var \Modules\Workflow\Models\WorkflowTemplate $template */ $template = WorkflowTemplateMapper::get() - ->where('id', (int) $request->getData('j')) + ->where('id', (int) $request->getData('id')) ->execute(); - $controller = null; + $instance = new WorkflowInstance(); - $files = $template->source->getSources(); - foreach ($files as $tMedia) { - $lowerPath = \strtolower($tMedia->getPath()); + $actions = \json_decode(\file_get_contents(__DIR__ . '/../Definitions/actions.json'), true); - switch (true) { - case StringUtils::endsWith($lowerPath, 'WorkflowController.php'): - require_once $lowerPath; + foreach ($template->schema as $e) { + if ($e['id'] === $request->getDataString('trigger')) { + $this->runWorkflowElement($actions, $template, $instance, $e); - $controller = new WorkflowController($this->app, $template); - break; + break; } } - /** @var \Modules\Workflow\Models\WorkflowControllerInterface $controller */ - $instance = $controller->createInstanceFromRequest($request, $template); - $controller->createInstanceDbModel($instance); - return $instance; } } diff --git a/Docs/workflow_components.md b/Docs/workflow_components.md index 2326e8e..68fb803 100755 --- a/Docs/workflow_components.md +++ b/Docs/workflow_components.md @@ -14,4 +14,13 @@ A `States.php` file contains all workflow states. This is especially important i The `Workflow.php` file is the heart of every workflow. This file is responsible for executing state driven actions and it can also be seen as the API for a workflow. All workflow related actions will be forwarded to this file and can be handled inside including database queries. -## \ No newline at end of file +## + + +1. Workflow gets installed with a trigger (either hook or cron job) +2. Trigger is fired +3. Hook loads CliApplication::installWorkflowTemplate with template ID, action ID and Hook +4. Installer creates WorkflowInstance Model +5. Installer calls CliApplication::runWorkflow with template, action ID, Hook, instance, and element for every element on this level. +6. runWorkflow executes the element by calling the respective function +7. runWorkflow calls itself with all child elements diff --git a/Models/WorkflowInstance.php b/Models/WorkflowInstance.php new file mode 100644 index 0000000..7fc7426 --- /dev/null +++ b/Models/WorkflowInstance.php @@ -0,0 +1,27 @@ +