/** * DB connection for meta data. * * @param ConnectionInterface $conn */ public function __construct(ConnectionInterface $conn) { parent::__construct(); $this->conn = $conn; if (mt_rand(0, 100) > 95) { $stmt = $conn->prepare("DELETE FROM `#__webdav_lock` WHERE `expires_at` < :time"); $stmt->bindValue('time', time()); $stmt->execute(); } }
/** * {@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]; }