diff --git a/gulliver/system/class.database_mysql.php b/gulliver/system/class.database_mysql.php index 870ba954f..53888a4ae 100644 --- a/gulliver/system/class.database_mysql.php +++ b/gulliver/system/class.database_mysql.php @@ -519,13 +519,15 @@ class database extends database_base } /** - * execute a sql query + * Execute a sql query * * @param string $query + * @param bool $throwError + * * @return array * @throws Exception */ - public function executeQuery($query) + public function executeQuery($query, $throwError = false) { $this->logQuery($query); @@ -545,7 +547,11 @@ class database extends database_base return $result; } catch (Exception $exception) { $this->logQuery($exception->getMessage()); - return []; + if ($throwError) { + throw $exception; + } else { + return []; + } } } diff --git a/workflow/engine/bin/tasks/cliUpgrade.php b/workflow/engine/bin/tasks/cliUpgrade.php index 7fec63fd0..36aa2e37d 100644 --- a/workflow/engine/bin/tasks/cliUpgrade.php +++ b/workflow/engine/bin/tasks/cliUpgrade.php @@ -36,6 +36,8 @@ CLI::taskArg('workspace'); /*----------------------------------********---------------------------------*/ CLI::taskRun("run_unify_database"); /*----------------------------------********---------------------------------*/ +CLI::taskName('upgrade-query'); +CLI::taskRun('runUpgradeQuery'); /** * Execute the upgrade @@ -299,3 +301,25 @@ function run_unify_database($args) $flag = G::isPMUnderUpdating(0); } /*----------------------------------********---------------------------------*/ + +/** + * Execute a query, used internally for upgrade process + * + * @param array $options + */ +function runUpgradeQuery($options) +{ + // Initializing variables + $workspaceName = $options[0]; + $query = base64_decode($options[1]); + $isRbac = (bool)$options[2]; + + // Creating a new instance of the extended class + $workspace = new WorkspaceTools($workspaceName); + + // Execute the query + $workspace->upgradeQuery($query, $isRbac); + + // Terminate without error + exit('success'); +} diff --git a/workflow/engine/classes/WorkspaceTools.php b/workflow/engine/classes/WorkspaceTools.php index 3c70f78b0..d190b9c1f 100644 --- a/workflow/engine/classes/WorkspaceTools.php +++ b/workflow/engine/classes/WorkspaceTools.php @@ -4623,4 +4623,16 @@ class WorkspaceTools } } } + + /** + * Execute a query, used internally for the upgrade process + * + * @param string $query + * @param bool $rbac + */ + public function upgradeQuery($query, $rbac) + { + $database = $this->getDatabase($rbac); + $database->executeQuery($query, true); + } } diff --git a/workflow/engine/src/ProcessMaker/Core/ProcessesManager.php b/workflow/engine/src/ProcessMaker/Core/ProcessesManager.php new file mode 100644 index 000000000..bff0c5d96 --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Core/ProcessesManager.php @@ -0,0 +1,98 @@ +processes = $processes; + } + + /** + * Get the list of terminated processes + * + * @return array + */ + public function getTerminated() + { + return $this->terminated; + } + + /** + * Get the list of processes with errors + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Set the sleep time after each statuses revision + * + * @param int $sleepTime + */ + public function setSleepTime($sleepTime) + { + $this->sleepTime = $sleepTime; + } + + /** + * Run the processes + */ + public function run() + { + // Start all processes + foreach ($this->processes as $process) { + $process->run(); + } + + // Manage the processes + $this->manage(); + } + + /** + * Manage all started processes + */ + private function manage() + { + do { + // Check all remaining processes + foreach ($this->processes as $index => $process) { + // If the process has finished, save the info and destroy it + if ($process->getStatus() === RunProcess::TERMINATED || $process->getStatus() === RunProcess::ERROR) { + $processInfo = ['command' => $process->getCommand(), 'rawAnswer' => $process->getRawAnswer()]; + if ($process->getStatus() === RunProcess::TERMINATED) { + // Processes completed successfully + $this->terminated[] = $processInfo; + } else { + // Processes completed with errors + $this->errors[] = $processInfo; + } + + // Destroy the process + unset($this->processes[$index]); + } + } + + // Waiting... + sleep($this->sleepTime); + } while (!empty($this->processes)); + } +} diff --git a/workflow/engine/src/ProcessMaker/Core/RunProcess.php b/workflow/engine/src/ProcessMaker/Core/RunProcess.php new file mode 100644 index 000000000..8f2a0287f --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Core/RunProcess.php @@ -0,0 +1,146 @@ +command = $command; + } + + /** + * Class destructor, the resource created should be closed + */ + public function __destruct() + { + if (is_resource($this->resource)) { + proc_close($this->resource); + } + } + + /** + * Get the command + * + * @return string + */ + public function getCommand() + { + return $this->command; + } + + /** + * Get the raw response + * + * @return string|null + */ + public function getRawAnswer() + { + return $this->rawAnswer; + } + + /** + * Get the status + * + * @return string + */ + public function getStatus() + { + // If already exist a status return this value + if ($this->status !== null) { + return $this->status; + } + + // If doesn't exists a resource the process is not running + if (!is_resource($this->resource)) { + return self::NOT_RUNNING; + } + + // If the process is running return this value + if ($this->isRunning()) { + return self::RUNNING; + } + + // If the process is not running, parse the response to determine the status + $this->rawAnswer = stream_get_contents($this->pipes[1]); + $this->status = $this->parseAnswer(); + + return $this->status; + } + + /** + * Get the exit code + * + * @return string|null + */ + public function getExitCode() + { + return $this->exitCode; + } + + /** + * Run the command + */ + public function run() + { + $this->resource = proc_open($this->command, $this->descriptors, $this->pipes); + } + + /** + * Process is running? + * + * @return bool + */ + public function isRunning() + { + // Get the process status + $status = proc_get_status($this->resource); + + // If process is not running get the exit code + if ($status['running'] === false) { + $this->exitCode = $status['exitcode']; + } + + return $status['running']; + } + + /** + * Process the raw response and compare with the expected answer in order to determine the status + * + * @return string + */ + public function parseAnswer() + { + return $this->rawAnswer === self::EXPECTED_ANSWER ? self::TERMINATED : self::ERROR; + } +} diff --git a/workflow/engine/src/ProcessMaker/Upgrade/RunProcessUpgradeQuery.php b/workflow/engine/src/ProcessMaker/Upgrade/RunProcessUpgradeQuery.php new file mode 100644 index 000000000..e1295c0e4 --- /dev/null +++ b/workflow/engine/src/ProcessMaker/Upgrade/RunProcessUpgradeQuery.php @@ -0,0 +1,61 @@ +workspace = $workspace; + $this->sql = $sql; + $this->isRbac = $isRbac; + + // Build the command and send to the parent class + parent::__construct($this->buildCommand()); + } + + /** + * Override the parent method in order to compare the raw response with the SUCCESS value + * + * @return string + */ + public function parseAnswer() + { + return $this->getRawAnswer() === self::SUCCESS ? parent::TERMINATED : parent::ERROR; + } + + /** + * Build the command to execute a query for the upgrade process + * + * @return string + */ + private function buildCommand() + { + return sprintf(self::CMD, $this->workspace, base64_encode($this->sql), + ($this->isRbac ? self::RBAC : self::NO_RBAC)); + } +} \ No newline at end of file