protected function bindEncodedParams() { foreach ($this->params as $k => $v) { $encoded = false; foreach ($this->encoders as $encoder) { $result = $encoder->encodeParam($this->conn, $v, $encoded); if ($encoded) { $v = $result; break; } } if ($v instanceof StreamInterface) { if (!$v->isReadable()) { throw new \InvalidArgumentException('Input stream must be readable to be used as DB input param'); } // FIXME: This is a workaround for PHP7 crashing with Sqlite LOB params bound to input streams... if ($this->conn->getDriverName() == DB::DRIVER_SQLITE && defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION > 5) { $this->stmt->bindValue($k, $v->getContents()); } else { $this->stmt->bindValue($k, (new StreamWrapper($v))->getResource(), \PDO::PARAM_LOB); } } elseif ($v instanceof UUID) { switch ($this->conn->getDriverName()) { case DB::DRIVER_MSSQL: case DB::DRIVER_POSTGRESQL: $this->stmt->bindValue($k, (string) $v); break; default: $this->stmt->bindValue($k, $v->toBinary()); } } else { $this->stmt->bindValue($k, $v); } } }
/** * {@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]; }