Пример #1
0
 public function getContents()
 {
     $stmt = $this->deployment->getProcessEngine()->prepareQuery("\n\t\t\tSELECT `data` FROM `#__bpmn_resource` WHERE `id` = :id\n\t\t");
     $stmt->bindValue('id', $this->id);
     $stmt->execute();
     if (false === ($row = $stmt->fetchNextRow())) {
         throw new \OutOfBoundsException(sprintf('Resource %s not found in repository', $this->id));
     }
     return BinaryData::decode($row['data']);
 }
Пример #2
0
 protected function unserializeProcessDefinition(array $row)
 {
     return new ProcessDefinition($row['id'], $row['process_key'], $row['revision'], unserialize(BinaryData::decode($row['definition'])), $row['name'], new \DateTimeImmutable('@' . $row['deployed_at']), $row['deployment_id'], $row['resource_id']);
 }
Пример #3
0
 /**
  * {@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();
     }
 }
Пример #4
0
 /**
  * {@inheritdoc}
  */
 public function findExecution(UUID $id)
 {
     static $injectVars = NULL;
     if ($injectVars === NULL) {
         $injectVars = new \ReflectionMethod(VirtualExecution::class, 'injectVariablesLocal');
         $injectVars->setAccessible(true);
     }
     $ref = (string) $id;
     if (isset($this->executions[$ref])) {
         return $this->executions[$ref];
     }
     // Need to select multiple rows as one process instance may span over different process definitions (using CallActivity)
     $sql = "\tSELECT DISTINCT e.`process_id`, d.`id` as definition_id, d.`definition`\r\n\t\t\t\t\tFROM `#__bpmn_execution` AS e\r\n\t\t\t\t\tINNER JOIN `#__bpmn_process_definition` AS d ON (d.`id` = e.`definition_id`)\r\n\t\t\t\t\tWHERE e.`process_id` = (\r\n\t\t\t\t\t\tSELECT `process_id` FROM `#__bpmn_execution` WHERE `id` = :eid\r\n\t\t\t\t\t)\r\n\t\t";
     $stmt = $this->conn->prepare($sql);
     $stmt->bindValue('eid', $id);
     $stmt->transform('process_id', new UUIDTransformer());
     $stmt->transform('definition_id', new UUIDTransformer());
     $stmt->execute();
     $rows = $stmt->fetchRows();
     if (empty($rows)) {
         throw new \OutOfBoundsException(sprintf('Execution not found: "%s"', $ref));
     }
     $processId = $rows[0]['process_id'];
     $definitions = [];
     foreach ($rows as $row) {
         $definitions[(string) $row['definition_id']] = unserialize(BinaryData::decode($row['definition']));
     }
     // Select (and lock) all execution rows of the process instance using a pessimistic lock.
     $sql = "\tSELECT e.*\r\n\t\t\t\t\tFROM `#__bpmn_execution` AS e\r\n\t\t\t\t\tWHERE e.`process_id` = :pid\r\n\t\t";
     switch ($this->conn->getDriverName()) {
         case DB::DRIVER_MYSQL:
         case DB::DRIVER_POSTGRESQL:
             $sql .= " FOR UPDATE";
     }
     $stmt = $this->conn->prepare($sql);
     $stmt->bindAll(['pid' => $processId]);
     $stmt->transform('id', new UUIDTransformer());
     $stmt->transform('pid', new UUIDTransformer());
     $stmt->transform('process_id', new UUIDTransformer());
     $stmt->transform('definition_id', new UUIDTransformer());
     $stmt->execute();
     $variables = [];
     $executions = [];
     $parents = [];
     while ($row = $stmt->fetchNextRow()) {
         $id = $row['id'];
         $pid = $row['pid'];
         $defId = (string) $row['definition_id'];
         if (empty($definitions[$defId])) {
             throw new \OutOfBoundsException(sprintf('Missing process definition "%s" referenced from execution "%s"', $defId, $id));
         }
         $definition = $definitions[$defId];
         if ($pid !== NULL) {
             $parents[(string) $id] = (string) $pid;
         }
         $state = (int) $row['state'];
         $active = (double) $row['active'];
         $node = $row['node'] === NULL ? NULL : $definition->findNode($row['node']);
         $transition = $row['transition'] === NULL ? NULL : $definition->findTransition($row['transition']);
         $businessKey = $row['business_key'];
         $variables[(string) $id] = [];
         $exec = $executions[(string) $id] = new VirtualExecution($id, $this, $definition);
         $exec->setBusinessKey($businessKey);
         $exec->setExecutionState($state);
         $exec->setNode($node);
         $exec->setTransition($transition);
         $exec->setTimestamp($active);
     }
     foreach ($parents as $id => $pid) {
         $executions[$id]->setParentExecution($executions[$pid]);
     }
     if (!empty($variables)) {
         $params = [];
         foreach (array_keys($variables) as $i => $k) {
             $params['p' . $i] = new UUID($k);
         }
         $placeholders = implode(', ', array_map(function ($p) {
             return ':' . $p;
         }, array_keys($params)));
         $sql = "\tSELECT `execution_id`, `name`, `value_blob`\r\n\t\t\t\t\t\tFROM `#__bpmn_execution_variables`\r\n\t\t\t\t\t\tWHERE `execution_id` IN ({$placeholders})\r\n\t\t\t";
         $stmt = $this->conn->prepare($sql);
         $stmt->bindAll($params);
         $stmt->transform('execution_id', new UUIDTransformer());
         $stmt->execute();
         while (false !== ($row = $stmt->fetchNextRow())) {
             $variables[(string) $row['execution_id']][$row['name']] = unserialize(BinaryData::decode($row['value_blob']));
         }
     }
     foreach ($variables as $id => $vars) {
         $injectVars->invoke($executions[$id], $vars);
     }
     foreach ($executions as $execution) {
         $execution->setSyncState(Execution::SYNC_STATE_NO_CHANGE);
         $this->executions[(string) $execution->getId()] = $execution;
     }
     if (empty($this->executions[$ref])) {
         throw new \OutOfBoundsException(sprintf('Execution not found: "%s"', $ref));
     }
     return $this->executions[$ref];
 }
Пример #5
0
 protected function unserializeJob(array $row)
 {
     $job = new Job($row['id'], $row['execution_id'], $row['handler_type'], unserialize(BinaryData::decode($row['handler_data'])), new \DateTimeImmutable('@' . $row['created_at']), $row['retries'], $row['lock_owner']);
     $job->setExternalId($row['external_id']);
     if ($row['scheduled_at'] !== NULL) {
         $job->setScheduledAt(new \DateTimeImmutable('@' . $row['scheduled_at'], new \DateTimeZone('UTC')));
     }
     if ($row['run_at'] !== NULL) {
         $job->setRunAt(new \DateTimeImmutable('@' . $row['run_at'], new \DateTimeZone('UTC')));
     }
     if ($row['locked_at'] !== NULL) {
         $job->setLockedAt(new \DateTimeImmutable('@' . $row['locked_at'], new \DateTimeZone('UTC')));
     }
     $job->setExceptionType($row['exception_type']);
     $job->setExceptionMessage($row['exception_message']);
     if ($row['exception_data'] !== NULL) {
         $job->setExceptionData(unserialize(BinaryData::decode($row['exception_data'])));
     }
     $locked = false;
     if ($row['lock_owner'] !== NULL && $row['locked_at'] !== NULL) {
         if ($row['locked_at'] > time() - $this->engine->getJobExecutor()->getLockTimeout()) {
             $locked = true;
         }
     }
     $job->setLocked($locked);
     return $job;
 }
Пример #6
0
 protected function unserializeExecution(array $row)
 {
     $def = new ProcessDefinition($row['def_id'], $row['def_key'], $row['def_rev'], unserialize(BinaryData::decode($row['def_data'])), $row['def_name'], new \DateTimeImmutable('@' . $row['def_deployed']), $row['deployment_id']);
     return new Execution($def, $row['id'], $row['process_id'], $row['pid'], $row['node'], $row['state'], $row['business_key']);
 }
 protected function unserializeProcess(array $row)
 {
     $process = new HistoricProcessInstance($row['id'], $row['definition_id'], $row['process_key'], $row['start_activity'], $row['started_at'], unserialize(BinaryData::decode($row['vars'])));
     $process->setBusinessKey($row['business_key']);
     $process->setEndActivityId($row['end_activity']);
     $process->setEndedAt($row['ended_at']);
     if ($row['duration'] !== NULL) {
         $process->setDuration((double) $row['duration'] / 1000 + 0.001);
     }
     return $process;
 }