public function executeCommand(ProcessEngine $engine) { $name = $this->builder->getName(); if ($this->builder->count() < 1) { throw new \RuntimeException(sprintf('Cannot deploy "%s" because it does not contain any resources', $name)); } $id = UUID::createRandom(); $sql = "\tINSERT INTO `#__bpmn_deployment`\n\t\t\t\t\t\t(`id`, `name`, `deployed_at`)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t(:id, :name, :time)\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $id); $stmt->bindValue('name', $name); $stmt->bindValue('time', time()); $stmt->execute(); $engine->info('Created deployment "{name}" with identifier <{id}>', ['name' => $name, 'id' => (string) $id]); $sql = "\tINSERT INTO `#__bpmn_resource`\n\t\t\t\t\t\t(`id`, `deployment_id`, `name`, `data`)\n\t\t\t\t\tVALUES\n\t\t\t\t\t\t(:id, :deployment, :name, :data)\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('deployment', $id); $parser = new DiagramLoader(); foreach ($this->builder as $name => $stream) { $in = $stream->getContents(); $resourceId = UUID::createRandom(); $stmt->bindValue('id', $resourceId); $stmt->bindValue('name', $name); $stmt->bindValue('data', new BinaryData($in)); $stmt->execute(); $engine->debug('Deployed resource "{name}" with identifer <{resourceId}>', ['name' => $name, 'resourceId' => (string) $resourceId]); if ($this->builder->isProcessResource($name)) { foreach ($parser->parseDiagramString($in) as $process) { $engine->pushCommand(new DeployBusinessProcessCommand($process, $id, $resourceId)); } } } return $id; }
/** * {@inheritdoc} */ public function executeJob(Job $job, VirtualExecution $execution, ProcessEngine $engine) { if ($execution->isTerminated()) { throw new \RuntimeException(sprintf('%s is terminated', $execution)); } $data = (array) $job->getHandlerData(); $command = $data[self::PARAM_COMMAND]; if (!$command instanceof CommandInterface) { throw new \RuntimeException(sprintf('Expecting command, given %s', is_object($command) ? get_class($command) : gettype($command))); } // Move execution to start node if param is set. if (array_key_exists(self::PARAM_NODE_ID, $data)) { $execution->setNode($execution->getProcessModel()->findNode($data[self::PARAM_NODE_ID])); $engine->debug('Moved {execution} to node "{node}"', ['execution' => (string) $execution, 'node' => $execution->getNode()->getId()]); } $engine->debug('Executing async command {cmd} using {execution}', ['cmd' => get_class($command), 'execution' => (string) $execution]); $engine->pushCommand($command); }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $task = $engine->getTaskService()->createTaskQuery()->taskId($this->taskId)->findOne(); $sql = "\tDELETE FROM `#__bpmn_user_task`\r\n\t\t\t\t\tWHERE `id` = :id\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $task->getId()); $stmt->execute(); $engine->debug('Removed user task "{task}" with id {id}', ['task' => $task->getName(), 'id' => (string) $task->getId()]); }
public function executeCommand(ProcessEngine $engine) { $sql = "\tSELECT `revision`\r\n\t\t\t\t\tFROM `#__bpmn_process_definition`\r\n\t\t\t\t\tWHERE `process_key` = :key\r\n\t\t\t\t\tORDER BY `revision` DESC\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('key', $this->builder->getKey()); $stmt->setLimit(1); $stmt->execute(); $revision = $stmt->fetchNextColumn(0); $model = $this->builder->build(); $id = $model->getId(); $time = time(); $sql = "\tINSERT INTO `#__bpmn_process_definition`\r\n\t\t\t\t\t\t(`id`, `deployment_id`, `resource_id`, `process_key`, `revision`, `definition`, `name`, `deployed_at`)\r\n\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t(:id, :deployment, :resource, :key, :revision, :model, :name, :deployed)\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $id); $stmt->bindValue('deployment', $this->deploymentId); $stmt->bindValue('resource', $this->resourceId); $stmt->bindValue('key', $this->builder->getKey()); $stmt->bindValue('revision', $revision + 1); $stmt->bindValue('model', new BinaryData(serialize($model), 3)); $stmt->bindValue('name', $model->getTitle()); $stmt->bindValue('deployed', $time); $stmt->execute(); $sql = "\tDELETE FROM `#__bpmn_process_subscription`\r\n\t\t\t\t\tWHERE `definition_id` IN (\r\n\t\t\t\t\t\tSELECT `id`\r\n\t\t\t\t\t\tFROM `#__bpmn_process_definition`\r\n\t\t\t\t\t\tWHERE `process_key` = :key\r\n\t\t\t\t\t)\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('key', $this->builder->getKey()); $stmt->execute(); $engine->info('Deployed business process {key} revision {revision} using id {id}', ['key' => $this->builder->getKey(), 'revision' => $revision + 1, 'id' => (string) $id]); foreach ($model->findStartNodes() as $node) { $behavior = $node->getBehavior(); if ($behavior instanceof MessageStartEventBehavior && !$behavior->isSubProcessStart()) { $sql = "\tINSERT INTO `#__bpmn_process_subscription`\r\n\t\t\t\t\t\t\t\t(`id`, `definition_id`, `flags`, `name`)\r\n\t\t\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t\t\t(:id, :def, :flags, :message)\r\n\t\t\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', UUID::createRandom()); $stmt->bindValue('def', $id); $stmt->bindValue('flags', EventSubscription::TYPE_MESSAGE); $stmt->bindValue('message', $behavior->getMessageName()); $stmt->execute(); $engine->debug('Process {process} subscribed to message <{message}>', ['process' => $this->builder->getKey(), 'message' => $behavior->getMessageName()]); } if ($behavior instanceof SignalStartEventBehavior && !$behavior->isSubProcessStart()) { $sql = "\tINSERT INTO `#__bpmn_process_subscription`\r\n\t\t\t\t\t\t\t\t(`id`, `definition_id`, `flags`, `name`)\r\n\t\t\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t\t\t(:id, :def, :flags, :message)\r\n\t\t\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', UUID::createRandom()); $stmt->bindValue('def', $id); $stmt->bindValue('flags', EventSubscription::TYPE_SIGNAL); $stmt->bindValue('message', $behavior->getSignalName()); $stmt->execute(); $engine->debug('Process {process} subscribed to signal <{signal}>', ['process' => $this->builder->getKey(), 'signal' => $behavior->getSignalName()]); } } return new ProcessDefinition($id, $this->builder->getKey(), $revision + 1, $model, $model->getTitle(), new \DateTimeImmutable('@' . $time), $this->deploymentId); }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $task = $engine->getTaskService()->createTaskQuery()->taskId($this->taskId)->findOne(); $engine->notify(new UserTaskCompletedEvent($task, $engine)); $sql = "\tDELETE FROM `#__bpmn_user_task`\r\n\t\t\t\t\tWHERE `id` = :id\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $this->taskId); $stmt->execute(); $engine->debug('Completed user task "{task}" with id {id}', ['task' => $task->getName(), 'id' => (string) $task->getId()]); $executionId = $task->getExecutionId(); if ($executionId !== NULL) { $engine->findExecution($executionId)->signal('user-task', unserialize($this->variables)); } }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $task = $engine->getTaskService()->createTaskQuery()->taskId($this->taskId)->findOne(); if (!$task->isClaimed()) { throw new \RuntimeException(sprintf('User task %s is not claimed', $task->getId())); } $sql = "\tUPDATE `#__bpmn_user_task`\r\n\t\t\t\t\tSET `claimed_at` = :time,\r\n\t\t\t\t\t\t`claimed_by` = :assignee\r\n\t\t\t\t\tWHERE `id` = :id\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('time', NULL); $stmt->bindValue('assignee', NULL); $stmt->bindValue('id', $task->getId()); $stmt->execute(); $task = $engine->getTaskService()->createTaskQuery()->taskId($this->taskId)->findOne(); $engine->notify(new UserTaskUnclaimedEvent($task, $engine)); $engine->debug('User task "{task}" unclaimed', ['task' => $task->getName()]); }
/** * {@inheritdoc} */ protected function executeCommand(ProcessEngine $engine) { $execution = $engine->findExecution($this->job->getExecutionId()); $engine->debug('Executing job <{job}> using handler "{handler}" ({impl}) within {execution}', ['job' => (string) $this->job->getId(), 'handler' => $this->handler->getType(), 'impl' => get_class($this->handler), 'execution' => (string) $execution]); try { $this->handler->executeJob($this->job, $execution, $engine); // Delete job when it has been completed successfully. $engine->getConnection()->delete('#__bpmn_job', ['id' => $this->job->getId()]); } catch (\Exception $e) { $engine->warning('Job <{job}> failed with exception {exception}: "{message}"', ['job' => (string) $this->job->getId(), 'exception' => get_class($e), 'message' => $e->getMessage()]); $stmt = $engine->prepareQuery("\n\t\t\t\tUPDATE `#__bpmn_job`\n\t\t\t\tSET `retries` = `retries` - 1,\n\t\t\t\t\t`scheduled_at` = NULL,\n\t\t\t\t\t`lock_owner` = NULL,\n\t\t\t\t\t`locked_at` = NULL,\n\t\t\t\t\t`exception_type` = :type,\n\t\t\t\t\t`exception_message` = :message,\n\t\t\t\t\t`exception_data` = :data\n\t\t\t\tWHERE `id` = :id\n\t\t\t"); $stmt->bindValue('id', $this->job->getId()); $stmt->bindValue('type', get_class($e)); $stmt->bindValue('message', (string) $e->getMessage()); $stmt->bindValue('data', new BinaryData(serialize($e->getTraceAsString()))); $stmt->execute(); } }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $id = UUID::createRandom(); $activityId = NULL; if ($this->executionId !== NULL) { $activityId = $engine->findExecution($this->executionId)->getNode()->getId(); } $sql = "\tINSERT INTO `#__bpmn_user_task`\r\n\t\t\t\t\t\t(`id`, `execution_id`, `name`, `documentation`, `activity`, `created_at`, `priority`, `due_at`)\r\n\t\t\t\t\tVALUES\r\n\t\t\t\t\t\t(:id, :eid, :name, :doc, :activity, :created, :priority, :due)\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('id', $id); $stmt->bindValue('eid', $this->executionId); $stmt->bindValue('name', $this->name); $stmt->bindValue('doc', $this->documentation); $stmt->bindValue('activity', $activityId); $stmt->bindValue('created', time()); $stmt->bindValue('priority', $this->priority); $stmt->bindValue('due', $this->dueDate); $stmt->execute(); $engine->debug('Created user task "{task}" with id {id}', ['task' => $this->name, 'id' => (string) $id]); $task = $engine->getTaskService()->createTaskQuery()->taskId($id)->findOne(); $engine->notify(new UserTaskCreatedEvent($task, $engine)); return $task; }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $sql = "\tSELECT s.`id`, s.`execution_id`, s.`activity_id`, s.`node`\r\n\t\t\t\t\tFROM `#__bpmn_event_subscription` AS s\r\n\t\t\t\t\tINNER JOIN `#__bpmn_execution` AS e ON (e.`id` = s.`execution_id`)\r\n\t\t\t\t\tWHERE s.`name` = :message\r\n\t\t\t\t\tAND s.`flags` = :flags\r\n\t\t\t\t\tAND s.`execution_id` = :eid\r\n\t\t\t\t\tORDER BY e.`depth` DESC, s.`created_at`\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('message', $this->messageName); $stmt->bindValue('flags', EventSubscription::TYPE_MESSAGE); $stmt->bindValue('eid', $this->executionId); $stmt->setLimit(1); $stmt->execute(); $row = $stmt->fetchNextRow(); if ($row === false) { throw new \RuntimeException(sprintf('Execution %s has not subscribed to message %s', $this->executionId, $this->messageName)); } $execution = $engine->findExecution($this->executionId); $delegation = []; if ($row['node'] !== NULL) { $delegation['nodeId'] = $row['node']; } // Delete timer jobs: $stmt = $engine->prepareQuery("\r\n\t\t\tSELECT `job_id`\r\n\t\t\tFROM `#__bpmn_event_subscription`\r\n\t\t\tWHERE `execution_id` = :eid\r\n\t\t\tAND `activity_id` = :aid\r\n\t\t\tAND `flags` = :flags\r\n\t\t\tAND `job_id` IS NOT NULL\r\n\t\t"); $stmt->bindValue('eid', $execution->getId()); $stmt->bindValue('aid', $row['activity_id']); $stmt->bindValue('flags', EventSubscription::TYPE_TIMER); $stmt->transform('job_id', new UUIDTransformer()); $stmt->execute(); $management = $engine->getManagementService(); foreach ($stmt->fetchColumns('job_id') as $jobId) { $management->removeJob($jobId); } $sql = "\tDELETE FROM `#__bpmn_event_subscription`\r\n\t\t\t\t\tWHERE `execution_id` = :eid\r\n\t\t\t\t\tAND `activity_id` = :aid\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('eid', $execution->getId()); $stmt->bindValue('aid', $row['activity_id']); $count = $stmt->execute(); $message = sprintf('Cleared {count} event subscription%s related to activity <{activity}> within {execution}', $count == 1 ? '' : 's'); $engine->debug($message, ['count' => $count, 'activity' => $row['activity_id'], 'execution' => (string) $execution]); $execution->signal($this->messageName, unserialize($this->variables), $delegation); }
/** * {@inheritdoc} */ public function executeCommand(ProcessEngine $engine) { $sql = "\tSELECT s.`id`, s.`execution_id`, s.`activity_id`, s.`node`\r\n\t\t\t\t\tFROM `#__bpmn_event_subscription` AS s\r\n\t\t\t\t\tINNER JOIN `#__bpmn_execution` AS e ON (e.`id` = s.`execution_id`)\r\n\t\t\t\t\tWHERE s.`name` = :signal\r\n\t\t\t\t\tAND s.`flags` = :flags\r\n\t\t\t\t\tORDER BY e.`depth` DESC\r\n\t\t"; if ($this->executionId !== NULL) { $sql .= ' AND s.`execution_id` = :eid'; } $stmt = $engine->prepareQuery($sql); $stmt->bindValue('signal', $this->signal); $stmt->bindValue('flags', EventSubscription::TYPE_SIGNAL); if ($this->executionId !== NULL) { $stmt->bindValue('eid', $this->executionId); } $stmt->transform('execution_id', new UUIDTransformer()); $stmt->execute(); $ids = []; $executions = []; $delegations = []; foreach ($stmt->fetchRows() as $row) { $execution = $executions[] = $engine->findExecution($row['execution_id']); $ids[(string) $execution->getId()] = [$execution->getId(), $row['activity_id']]; if ($row['node'] !== NULL) { $delegations[(string) $execution->getId()] = ['nodeId' => $row['node']]; } } if (!empty($ids)) { $sql = "SELECT `job_id` FROM `#__bpmn_event_subscription` WHERE `flags` = :flags AND `job_id` IS NOT NULL AND ("; $where = []; $params = ['flags' => EventSubscription::TYPE_TIMER]; foreach (array_values($ids) as $i => $tmp) { $where[] = sprintf("(`execution_id` = :e%u AND `activity_id` = :a%u)", $i, $i); $params['e' . $i] = $tmp[0]; $params['a' . $i] = $tmp[1]; } $stmt = $engine->prepareQuery($sql . implode(' OR ', $where) . ')'); $stmt->bindAll($params); $stmt->transform('job_id', new UUIDTransformer()); $stmt->execute(); $management = $engine->getManagementService(); foreach ($stmt->fetchColumns('job_id') as $jobId) { $management->removeJob($jobId); } unset($params['flags']); $stmt = $engine->prepareQuery("DELETE FROM `#__bpmn_event_subscription` WHERE " . implode(' OR ', $where)); $stmt->bindAll($params); $count = $stmt->execute(); $message = sprintf('Cleared {count} event subscription%s related to signal <{signal}>', $count == 1 ? '' : 's'); $engine->debug($message, ['count' => $count, 'signal' => $this->signal === NULL ? 'NULL' : $this->signal]); } $vars = unserialize($this->variables); foreach ($executions as $execution) { $id = (string) $execution->getId(); $execution->signal($this->signal, $vars, empty($delegations[$id]) ? [] : $delegations[$id]); } // Include signal start events subscriptions. $sql = "\tSELECT s.`name` AS signal_name, d.* \r\n\t\t\t\t\tFROM `#__bpmn_process_subscription` AS s\r\n\t\t\t\t\tINNER JOIN `#__bpmn_process_definition` AS d ON (d.`id` = s.`definition_id`)\r\n\t\t\t\t\tWHERE s.`flags` = :flags\r\n\t\t\t\t\tAND s.`name` = :name\r\n\t\t"; $stmt = $engine->prepareQuery($sql); $stmt->bindValue('flags', EventSubscription::TYPE_SIGNAL); $stmt->bindValue('name', $this->signal); $stmt->transform('id', new UUIDTransformer()); $stmt->transform('deployment_id', new UUIDTransformer()); $stmt->execute(); $source = $this->sourceExecutionId === NULL ? NULL : $engine->findExecution($this->sourceExecutionId); while ($row = $stmt->fetchNextRow()) { $definition = new ProcessDefinition($row['id'], $row['process_key'], $row['revision'], unserialize(BinaryData::decode($row['definition'])), $row['name'], new \DateTimeImmutable('@' . $row['deployed_at']), $row['deployment_id']); $engine->pushCommand(new StartProcessInstanceCommand($definition, $definition->findSignalStartEvent($row['signal_name']), $source === NULL ? NULL : $source->getBusinessKey(), $vars)); } if ($source !== NULL) { $source->signal(); } }