where('status', WorkflowStatus::ACTIVE)->execute(); foreach ($workflows as $workflow) { $hooks = $workflow->getHooks(); foreach ($hooks as $hook) { /** @var array{':triggerGroup'?:string} $data */ $triggerIsRegex = \stripos($data['@triggerGroup'], '/') === 0; $matched = false; $matched = $triggerIsRegex ? \preg_match($data['@triggerGroup'], $hook) === 1 : $data['@triggerGroup'] === $hook; if ($matched) { $this->runWorkflow($workflow, $hook, $data); } elseif (\stripos($hook, '/') === 0) { $matched = \preg_match($hook, $data['@triggerGroup']) === 1; } } } } /** * Api method to make a call to the cli app * * @param WorkflowTemplate $workflow Workflow template * @param string $hook Event hook * @param array $data Event data * * @return void * * @api * * @since 1.0.0 */ public function runWorkflow(WorkflowTemplate $workflow, string $hook, array $data) : void { include $workflow->source->getAbsolutePath(); } /** * Method which creates a workflow instance * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param array $data Generic data * * @return RenderableInterface Response can be rendered * * @since 1.0.0 * @codeCoverageIgnore */ public function cliWorkflowInstanceCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface { $view = new View($this->app->l11nManager, $request, $response); if (!empty($val = $this->validateInstanceCreate($request))) { $response->header->status = RequestStatusCode::R_400; $this->createInvalidCreateResponse($request, $response, $val); } $instance = $this->createInstanceFromRequest($request); $this->createModel($request->header->account, $instance, WorkflowInstanceAbstractMapper::class, 'instance', $request->getOrigin()); $this->startInstance($request, $response, $instance); $new = clone $instance; $new->end = new \DateTimeImmutable('now'); $this->updateModel($request->header->account, $instance, $new, WorkflowInstanceAbstractMapper::class, 'instance', $request->getOrigin()); $view->setTemplate('/Modules/Workflow/Theme/Cli/empty-command'); return $view; } /** * Validate template create request * * @param RequestAbstract $request Request * * @return array * * @since 1.0.0 */ private function validateInstanceCreate(RequestAbstract $request) : array { $val = []; if (($val['id'] = !$request->hasData('-id'))) { return $val; } return []; } /** * Method to create instance from request. * * @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 */ private function createInstanceFromRequest(RequestAbstract $request) : WorkflowInstanceAbstract { /** @var \Modules\Workflow\Models\WorkflowTemplate $template */ $template = WorkflowTemplateMapper::get() ->where('id', (int) $request->getData('-id')) ->execute(); $instance = new WorkflowInstance(); $instance->template = $template; return $instance; } /** * Start a workflow instance * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param WorkflowInstanceAbstract $instance Workflow instance * * @return void * * @since 1.0.0 */ private function startInstance(RequestAbstract $request, ResponseAbstract $response, WorkflowInstanceAbstract $instance) : void { $actionString = \file_get_contents(__DIR__ . '/../Definitions/actions.json'); if ($actionString === false) { return; } $actions = \json_decode($actionString, true); if (!\is_array($actions)) { return; } foreach ($instance->template->schema as $e) { if ($e['id'] === $request->getDataString('-trigger')) { $this->runWorkflowElement($request, $response, $actions, $instance, $e); break; } } } /** * Run a workflow element * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param array $actions All available actions * @param WorkflowInstanceAbstract $instance Current workflow instance * @param array $element Workflow element to run * * @return void * * @since 1.0.0 */ public function runWorkflowElement( RequestAbstract $request, ResponseAbstract $response, array $actions, WorkflowInstanceAbstract $instance, array $element ) : void { if (isset($actions[(int) $element['id']]) && $actions[(int) $element['id']]['function'] !== '' ) { $this->app->moduleManager ->get($actions[(int) $element['id']]['module'], $actions[(int) $element['id']]['function_type']) ->{$actions[(int) $element['id']]['function']}($request, $response, [$element]); } // @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($request, $response, $actions, $instance, $child); } } }