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']); }
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']); }
/** * {@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(); } }
/** * {@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]; }
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; }
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; }