PMCORE-1203 Help on how batch routing feature works and help to debug the code with a client

This commit is contained in:
Roly Rudy Gutierrez Pinto
2020-03-20 11:26:49 -04:00
parent 67df02497f
commit 2fdcc30aad
15 changed files with 771 additions and 356 deletions

View File

@@ -1,6 +1,8 @@
<?php
use Illuminate\Support\Facades\DB;
use ProcessMaker\Core\MultiProcOpen;
use ProcessMaker\Commands\PopulateTableReport;
use ProcessMaker\Model\Application;
/**
@@ -207,168 +209,110 @@ class ReportTables
//we have to do the propel connection
$database = $this->chooseDB($connectionShortName);
$connection = Propel::getConnection($database);
$statement = $connection->createStatement();
if ($type == 'GRID') {
$aux = explode('-', $grid);
$grid = $aux[0];
}
$case = new Cases();
try {
switch (DB_ADAPTER) {
case 'mysql':
$applications = Application::getByProUid($proUid);
foreach ($applications as $application) {
$appData = $case->unserializeData($application->APP_DATA);
DB::delete("DELETE FROM `{$tableName}` WHERE APP_UID = '{$application->APP_UID}'");
if ($type == 'NORMAL') {
$query = 'INSERT INTO `' . $tableName . '` (';
$query .= '`APP_UID`,`APP_NUMBER`';
foreach ($fields as $field) {
$query .= ',`' . $field['sFieldName'] . '`';
}
$query .= ") VALUES ('" . $application->APP_UID . "'," . $application->APP_NUMBER;
$applicationTableName = (new Application())->getTable();
$deleteQuery = "TRUNCATE TABLE `{$tableName}` ";
DB::delete($deleteQuery);
$applications = Application::getByProUid($proUid);
$i = 1;
$queryValues = "";
$numberRecords = 1000;
$n = count($applications);
foreach ($applications as $application) {
$appData = $case->unserializeData($application->APP_DATA);
if ($type == 'NORMAL') {
$query = 'INSERT INTO `' . $tableName . '` (';
$query .= '`APP_UID`,`APP_NUMBER`';
foreach ($fields as $field) {
$query .= ',`' . $field['sFieldName'] . '`';
}
$headQuery = $query . ") VALUES ";
$query = "('" . $application->APP_UID . "'," . $application->APP_NUMBER;
foreach ($fields as $field) {
switch ($field['sType']) {
case 'number':
$query .= ',' . (isset($appData[$field['sFieldName']]) ? (float) str_replace(',', '', $appData[$field['sFieldName']]) : '0');
break;
case 'char':
case 'text':
if (!isset($appData[$field['sFieldName']])) {
$appData[$field['sFieldName']] = '';
}
$string = $appData[$field['sFieldName']];
if (is_array($string)) {
$string = implode($string, ",");
}
$query .= ",'" . (isset($appData[$field['sFieldName']]) ? mysqli_real_escape_string($connection->getResource(), $string) : '') . "'";
break;
case 'date':
$value = (isset($appData[$field['sFieldName']]) && trim($appData[$field['sFieldName']])) != '' ? "'" . $appData[$field['sFieldName']] . "'" : 'NULL';
$query .= "," . $value;
break;
}
}
$query .= ')';
$queryValues = $queryValues . $query . ",";
if ($i % $numberRecords === 0 || $i === $n) {
$queryValues = rtrim($queryValues, ",");
$query = $headQuery . $queryValues;
$queryValues = "";
$workspace = config("system.workspace");
$processesManager = new MultiProcOpen();
$processesManager->chunk(1, 1, function($size, $start, $limit) use ($query, $workspace) {
return new PopulateTableReport($workspace, $query);
});
}
} else {
if (isset($appData[$grid])) {
$query = 'INSERT INTO `' . $tableName . '` (';
$query .= '`APP_UID`,`APP_NUMBER`,`ROW`';
foreach ($fields as $field) {
$query .= ',`' . $field['sFieldName'] . '`';
}
$headQuery = $query . ") VALUES ";
foreach ($appData[$grid] as $indexRow => $gridRow) {
$query = "('" . $application->APP_UID . "'," . (int) $application->APP_NUMBER . ',' . $indexRow;
foreach ($fields as $field) {
switch ($field['sType']) {
case 'number':
$query .= ',' . (isset($appData[$field['sFieldName']]) ? (float) str_replace(',', '', $appData[$field['sFieldName']]) : '0');
$query .= ',' . (isset($gridRow[$field['sFieldName']]) ? (float) str_replace(',', '', $gridRow[$field['sFieldName']]) : '0');
break;
case 'char':
case 'text':
if (!isset($appData[$field['sFieldName']])) {
$appData[$field['sFieldName']] = '';
if (!isset($gridRow[$field['sFieldName']])) {
$gridRow[$field['sFieldName']] = '';
}
$string = $appData[$field['sFieldName']];
if (is_array($string)) {
$string = implode($string, ",");
}
$query .= ",'" . (isset($appData[$field['sFieldName']]) ? mysqli_real_escape_string($connection->getResource(), $string) : '') . "'";
$stringEscape = mysqli_real_escape_string($connection->getResource(), $gridRow[$field['sFieldName']]);
$query .= ",'" . (isset($gridRow[$field['sFieldName']]) ? $stringEscape : '') . "'";
break;
case 'date':
$value = (isset($appData[$field['sFieldName']]) && trim($appData[$field['sFieldName']])) != '' ? "'" . $appData[$field['sFieldName']] . "'" : 'NULL';
$value = (isset($gridRow[$field['sFieldName']]) && trim($gridRow[$field['sFieldName']])) != '' ? "'" . $gridRow[$field['sFieldName']] . "'" : 'NULL';
$query .= "," . $value;
break;
}
}
$query .= ')';
DB::insert($query);
} else {
if (isset($appData[$grid])) {
foreach ($appData[$grid] as $indexRow => $gridRow) {
$query = 'INSERT INTO `' . $tableName . '` (';
$query .= '`APP_UID`,`APP_NUMBER`,`ROW`';
foreach ($fields as $field) {
$query .= ',`' . $field['sFieldName'] . '`';
}
$query .= ") VALUES ('" . $application->APP_UID . "'," . (int) $application->APP_NUMBER . ',' . $indexRow;
foreach ($fields as $field) {
switch ($field['sType']) {
case 'number':
$query .= ',' . (isset($gridRow[$field['sFieldName']]) ? (float) str_replace(',', '', $gridRow[$field['sFieldName']]) : '0');
break;
case 'char':
case 'text':
if (!isset($gridRow[$field['sFieldName']])) {
$gridRow[$field['sFieldName']] = '';
}
$stringEscape = mysqli_real_escape_string($connection->getResource(), $gridRow[$field['sFieldName']]);
$query .= ",'" . (isset($gridRow[$field['sFieldName']]) ? $stringEscape : '') . "'";
break;
case 'date':
$value = (isset($gridRow[$field['sFieldName']]) && trim($gridRow[$field['sFieldName']])) != '' ? "'" . $gridRow[$field['sFieldName']] . "'" : 'NULL';
$query .= "," . $value;
break;
}
}
$query .= ')';
DB::insert($query);
}
}
$queryValues = $queryValues . $query . ",";
}
if ($i % $numberRecords === 0 || $i === $n) {
$queryValues = rtrim($queryValues, ",");
$query = $headQuery . $queryValues;
$queryValues = "";
$workspace = config("system.workspace");
$processesManager = new MultiProcOpen();
$processesManager->chunk(1, 1, function($size, $start, $limit) use ($query, $workspace) {
return new PopulateTableReport($workspace, $query);
});
}
}
break;
/**
* For SQLServer code
* Note: It is only possible to create Report Tables in MySQL databases. The list will only show connections to those databases even if the project has connections to other DBMS.
* This section is not used and has been marked for deletion.
* @link https://wiki.processmaker.com/3.0/Report_Tables#Creating_Report_Tables
* @deprecated
*/
case 'mssql':
$criteria = new Criteria('workflow');
$criteria->add(ApplicationPeer::PRO_UID, $proUid);
$criteria->addAscendingOrderByColumn(ApplicationPeer::APP_NUMBER);
$dataset = ApplicationPeer::doSelectRS($criteria);
$dataset->setFetchmode(ResultSet::FETCHMODE_ASSOC);
$dataset->next();
while ($row = $dataset->getRow()) {
$appData = unserialize($row['APP_DATA']);
//verify use mssql
mysqli_query(
$connection->getResource(), 'DELETE FROM [' . $tableName . "] WHERE APP_UID = '" . $row['APP_UID'] . "'"
);
if ($type == 'NORMAL') {
$query = 'INSERT INTO [' . $tableName . '] (';
$query .= '[APP_UID],[APP_NUMBER]';
foreach ($fields as $field) {
$query .= ',[' . $field['sFieldName'] . ']';
}
$query .= ") VALUES ('" . $row['APP_UID'] . "'," . (int) $row['APP_NUMBER'];
foreach ($fields as $field) {
switch ($field['sType']) {
case 'number':
$query .= ',' . (isset($appData[$field['sFieldName']]) ? (float) str_replace(',', '', $appData[$field['sFieldName']]) : '0');
break;
case 'char':
case 'text':
if (!isset($appData[$field['sFieldName']])) {
$appData[$field['sFieldName']] = '';
}
$stringEscape = mysqli_real_escape_string($connection->getResource(), $appData[$field['sFieldName']]);
$query .= ",'" . (isset($appData[$field['sFieldName']]) ? $stringEscape : '') . "'";
break;
case 'date':
$query .= ",'" . (isset($appData[$field['sFieldName']]) ? $appData[$field['sFieldName']] : '') . "'";
break;
}
}
$query .= ')';
$rs = $statement->executeQuery($query);
} else {
if (isset($appData[$grid])) {
foreach ($appData[$grid] as $indexRow => $gridRow) {
$query = 'INSERT INTO [' . $tableName . '] (';
$query .= '`APP_UID`,`APP_NUMBER`,`ROW`';
foreach ($fields as $field) {
$query .= ',[' . $field['sFieldName'] . ']';
}
$query .= ") VALUES ('" . $row['APP_UID'] . "'," . (int) $row['APP_NUMBER'] . ',' . $indexRow;
foreach ($fields as $field) {
switch ($field['sType']) {
case 'number':
$query .= ',' . (isset($gridRow[$field['sFieldName']]) ? (float) str_replace(',', '', $gridRow[$field['sFieldName']]) : '0');
break;
case 'char':
case 'text':
if (!isset($gridRow[$field['sFieldName']])) {
$gridRow[$field['sFieldName']] = '';
}
$stringEscape = mysqli_real_escape_string($connection->getResource(), $gridRow[$field['sFieldName']]);
$query .= ",'" . (isset($gridRow[$field['sFieldName']]) ? $stringEscape : '') . "'";
break;
case 'date':
$query .= ",'" . (isset($gridRow[$field['sFieldName']]) ? $gridRow[$field['sFieldName']] : '') . "'";
break;
}
}
$query .= ')';
$rs = $statement->executeQuery($query);
}
}
}
$dataset->next();
}
break;
}
$i = $i + 1;
}
} catch (Exception $oError) {
throw ($oError);

View File

@@ -9,6 +9,8 @@ use ProcessMaker\ChangeLog\ChangeLog;
use ProcessMaker\Core\Installer;
use ProcessMaker\Core\ProcessesManager;
use ProcessMaker\Core\System;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\Fields;
use ProcessMaker\Plugins\Adapters\PluginAdapter;
use ProcessMaker\Project\Adapter\BpmnWorkflow;
use ProcessMaker\Upgrade\RunProcessUpgradeQuery;
@@ -4821,4 +4823,167 @@ class WorkspaceTools
$database = $this->getDatabase($rbac);
$database->executeQuery($query, true);
}
/**
* This method regenerates data report with the APP_DATA data.
* @param string $tableName
* @param string $type
* @param string $processUid
* @param string $gridKey
* @param string $addTabUid
* @param string $className
* @param string $pathWorkspace
* @param int $start
* @param int $limit
* @throws Exception
*/
public function generateDataReport(
$tableName,
$type = 'NORMAL',
$processUid = '',
$gridKey = '',
$addTabUid = '',
$className = '',
$pathWorkspace,
int $start = 0,
int $limit = 10)
{
$this->initPropel();
$dbHost = explode(':', $this->dbHost);
config(['database.connections.workflow.host' => $dbHost[0]]);
config(['database.connections.workflow.database' => $this->dbName]);
config(['database.connections.workflow.username' => $this->dbUser]);
config(['database.connections.workflow.password' => $this->dbPass]);
if (count($dbHost) > 1) {
config(['database.connections.workflow.port' => $dbHost[1]]);
}
//require file
set_include_path(get_include_path() . PATH_SEPARATOR . $pathWorkspace);
if (!file_exists($pathWorkspace . 'classes/' . $className . '.php')) {
throw new Exception("ERROR: " . $pathWorkspace . 'classes/' . $className . '.php' . " class file doesn't exit!");
}
require_once 'classes/model/AdditionalTables.php';
require_once $pathWorkspace . 'classes/' . $className . '.php';
//get fields
$fieldTypes = [];
if ($addTabUid != '') {
$fields = Fields::where('ADD_TAB_UID', '=', $addTabUid)->get();
foreach ($fields as $field) {
switch ($field->FLD_TYPE) {
case 'FLOAT':
case 'DOUBLE':
case 'INTEGER':
$fieldTypes[] = [$field->FLD_NAME => $field->FLD_TYPE];
break;
default:
break;
}
}
}
$context = Bootstrap::getDefaultContextLog();
$case = new Cases();
//select cases for this Process, ordered by APP_NUMBER
$applications = Application::where('PRO_UID', '=', $processUid)
->orderBy('APP_NUMBER', 'asc')
->offset($start)
->limit($limit)
->get();
foreach ($applications as $application) {
//getting the case data
$appData = $case->unserializeData($application->APP_DATA);
//quick fix, map all empty values as NULL for Database
foreach ($appData as $appDataKey => $appDataValue) {
if (is_array($appDataValue) && count($appDataValue)) {
$j = key($appDataValue);
$appDataValue = is_array($appDataValue[$j]) ? $appDataValue : $appDataValue[$j];
}
if (is_string($appDataValue)) {
foreach ($fieldTypes as $key => $fieldType) {
foreach ($fieldType as $fieldTypeKey => $fieldTypeValue) {
if (strtoupper($appDataKey) == $fieldTypeKey) {
$appData[$appDataKey] = validateType($appDataValue, $fieldTypeValue);
unset($fieldTypeKey);
}
}
}
// normal fields
if (trim($appDataValue) === '') {
$appData[$appDataKey] = null;
}
} else {
// grids
if (is_array($appData[$appDataKey])) {
foreach ($appData[$appDataKey] as $dIndex => $dRow) {
if (is_array($dRow)) {
foreach ($dRow as $k => $v) {
if (is_string($v) && trim($v) === '') {
$appData[$appDataKey][$dIndex][$k] = null;
}
}
}
}
}
}
}
//populate data
if ($type === 'GRID') {
list($gridName, $gridUid) = explode('-', $gridKey);
$gridData = isset($appData[$gridName]) ? $appData[$gridName] : [];
foreach ($gridData as $i => $gridRow) {
try {
$obj = new $className();
$obj->fromArray($appData, BasePeer::TYPE_FIELDNAME);
$obj->setAppUid($application->APP_UID);
$obj->setAppNumber($application->APP_NUMBER);
if (method_exists($obj, 'setAppStatus')) {
$obj->setAppStatus($application->APP_STATUS);
}
$obj->fromArray(array_change_key_case($gridRow, CASE_UPPER), BasePeer::TYPE_FIELDNAME);
$obj->setRow($i);
$obj->save();
} catch (Exception $e) {
$context["message"] = $e->getMessage();
$context["tableName"] = $tableName;
$context["appUid"] = $application->APP_UID;
Bootstrap::registerMonolog("sqlExecution", 500, "Sql Execution", $context, $context["workspace"], "processmaker.log");
}
unset($obj);
}
} else {
try {
$obj = new $className();
$obj->fromArray(array_change_key_case($appData, CASE_UPPER), BasePeer::TYPE_FIELDNAME);
$obj->setAppUid($application->APP_UID);
$obj->setAppNumber($application->APP_NUMBER);
if (method_exists($obj, 'setAppStatus')) {
$obj->setAppStatus($application->APP_STATUS);
}
$obj->save();
} catch (Exception $e) {
$context["message"] = $e->getMessage();
$context["tableName"] = $tableName;
$context["appUid"] = $application->APP_UID;
Bootstrap::registerMonolog("sqlExecution", 500, "Sql Execution", $context, $context["workspace"], "processmaker.log");
}
unset($obj);
}
}
}
/**
* This method populates the table with a query string.
* @param string $query
* @param boolean $rbac
*/
public function populateTableReport($query, $rbac)
{
$database = $this->getDatabase($rbac);
$database->executeQuery($query, true);
}
}

View File

@@ -1,23 +1,12 @@
<?php
/**
* AdditionalTables.php
* @package workflow.engine.classes.model
*/
require_once 'classes/model/om/BaseAdditionalTables.php';
use Illuminate\Support\Facades\DB;
use ProcessMaker\Commands\GenerateDataReport;
use ProcessMaker\Core\MultiProcOpen;
use ProcessMaker\Model\Application;
use ProcessMaker\Model\Fields;
/**
* Skeleton subclass for representing a row from the 'ADDITIONAL_TABLES' table.
*
*
*
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
* <juliocesar@colosa.com, julces2000@gmail.com>
*
* @package workflow.engine.classes.model
*/
require_once 'classes/model/om/BaseAdditionalTables.php';
function validateType($value, $type)
{
@@ -740,136 +729,34 @@ class AdditionalTables extends BaseAdditionalTables
*/
public function populateReportTable($tableName, $sConnection = 'rp', $type = 'NORMAL', $processUid = '', $gridKey = '', $addTabUid = '')
{
$this->className = $this->getPHPName($tableName);
$this->classPeerName = $this->className . 'Peer';
if (!file_exists(PATH_WORKSPACE . 'classes/' . $this->className . '.php')) {
throw new Exception("ERROR: " . PATH_WORKSPACE . 'classes/' . $this->className . '.php' . " class file doesn't exit!");
}
require_once PATH_WORKSPACE . 'classes/' . $this->className . '.php';
//get fields
$fieldTypes = [];
if ($addTabUid != '') {
$criteria = new Criteria('workflow');
$criteria->add(FieldsPeer::ADD_TAB_UID, $addTabUid);
$dataset = FieldsPeer::doSelectRS($criteria);
$dataset->setFetchmode(ResultSet::FETCHMODE_ASSOC);
while ($dataset->next()) {
$row = $dataset->getRow();
switch ($row['FLD_TYPE']) {
case 'FLOAT':
case 'DOUBLE':
case 'INTEGER':
$fieldTypes[] = array($row['FLD_NAME'] => $row['FLD_TYPE']);
break;
default:
break;
}
}
}
//remove old applications references
$connection = Propel::getConnection($sConnection);
$statement = $connection->createStatement();
$sql = "TRUNCATE " . $tableName;
$statement->executeQuery($sql);
$case = new Cases();
$context = Bootstrap::getDefaultContextLog();
//select cases for this Process, ordered by APP_NUMBER
$criteria = new Criteria('workflow');
$criteria->add(ApplicationPeer::PRO_UID, $processUid);
$criteria->addAscendingOrderByColumn(ApplicationPeer::APP_NUMBER);
$dataset = ApplicationPeer::doSelectRS($criteria);
$dataset->setFetchmode(ResultSet::FETCHMODE_ASSOC);
while ($dataset->next()) {
$row = $dataset->getRow();
//getting the case data
$appData = $case->unserializeData($row['APP_DATA']);
//quick fix, map all empty values as NULL for Database
foreach ($appData as $appDataKey => $appDataValue) {
if (is_array($appDataValue) && count($appDataValue)) {
$j = key($appDataValue);
$appDataValue = is_array($appDataValue[$j]) ? $appDataValue : $appDataValue[$j];
}
if (is_string($appDataValue)) {
foreach ($fieldTypes as $key => $fieldType) {
foreach ($fieldType as $fieldTypeKey => $fieldTypeValue) {
if (strtoupper($appDataKey) == $fieldTypeKey) {
$appData[$appDataKey] = validateType($appDataValue, $fieldTypeValue);
unset($fieldTypeKey);
}
}
}
// normal fields
if (trim($appDataValue) === '') {
$appData[$appDataKey] = null;
}
} else {
// grids
if (is_array($appData[$appDataKey])) {
foreach ($appData[$appDataKey] as $dIndex => $dRow) {
if (is_array($dRow)) {
foreach ($dRow as $k => $v) {
if (is_string($v) && trim($v) === '') {
$appData[$appDataKey][$dIndex][$k] = null;
}
}
}
}
}
}
}
//populate data
$className = $this->className;
if ($type === 'GRID') {
list($gridName, $gridUid) = explode('-', $gridKey);
$gridData = isset($appData[$gridName]) ? $appData[$gridName] : [];
foreach ($gridData as $i => $gridRow) {
try {
$obj = new $className();
$obj->fromArray($appData, BasePeer::TYPE_FIELDNAME);
$obj->setAppUid($row['APP_UID']);
$obj->setAppNumber($row['APP_NUMBER']);
if (method_exists($obj, 'setAppStatus')) {
$obj->setAppStatus($row['APP_STATUS']);
}
$obj->fromArray(array_change_key_case($gridRow, CASE_UPPER), BasePeer::TYPE_FIELDNAME);
$obj->setRow($i);
$obj->save();
} catch (Exception $e) {
$context["message"] = $e->getMessage();
$context["tableName"] = $tableName;
$context["appUid"] = $row['APP_UID'];
Bootstrap::registerMonolog("sqlExecution", 500, "Sql Execution", $context, $context["workspace"], "processmaker.log");
}
unset($obj);
}
} else {
try {
$obj = new $className();
$obj->fromArray(array_change_key_case($appData, CASE_UPPER), BasePeer::TYPE_FIELDNAME);
$obj->setAppUid($row['APP_UID']);
$obj->setAppNumber($row['APP_NUMBER']);
if (method_exists($obj, 'setAppStatus')) {
$obj->setAppStatus($row['APP_STATUS']);
}
$obj->save();
} catch (Exception $e) {
$context["message"] = $e->getMessage();
$context["tableName"] = $tableName;
$context["appUid"] = $row['APP_UID'];
Bootstrap::registerMonolog("sqlExecution", 500, "Sql Execution", $context, $context["workspace"], "processmaker.log");
}
unset($obj);
}
}
$this->className = $className = $this->getPHPName($tableName);
$this->classPeerName = $classPeerName = $className . 'Peer';
DB::statement("TRUNCATE " . $tableName);
$workspace = config("system.workspace");
$pathWorkspace = PATH_WORKSPACE;
$n = Application::count();
$processesManager = new MultiProcOpen();
$processesManager->chunk($n, 1000, function($size, $start, $limit) use(
$workspace,
$tableName,
$type,
$processUid,
$gridKey,
$addTabUid,
$className,
$pathWorkspace) {
return new GenerateDataReport(
$workspace,
$tableName,
$type,
$processUid,
$gridKey,
$addTabUid,
$className,
$pathWorkspace,
$start,
$limit);
});
}
/**