1206 lines
50 KiB
PHP
1206 lines
50 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
class upgradeTao extends upgradeModel
|
|
{
|
|
/**
|
|
* 获取中间表分组ID。
|
|
* Get dataview group ID.
|
|
*
|
|
* @param string $name
|
|
* @access protected
|
|
* @return int
|
|
*/
|
|
protected function getDataviewGroupID(string $name): int
|
|
{
|
|
$groupID = $this->dao->select('id')->from(TABLE_MODULE)->where('type')->eq('dataview')->andWhere('name')->eq($name)->fetch('id');
|
|
if(empty($groupID))
|
|
{
|
|
$group = new stdclass();
|
|
$group->root = 0;
|
|
$group->name = $name;
|
|
$group->parent = 0;
|
|
$group->grade = 1;
|
|
$group->order = 10;
|
|
$group->type = 'dataview';
|
|
|
|
$this->dao->insert(TABLE_MODULE)->data($group)->exec();
|
|
$groupID = $this->dao->lastInsertID();
|
|
$this->dao->update(TABLE_MODULE)->set("`path` = CONCAT(',', `id`, ',')")->where('id')->eq($groupID)->exec();
|
|
}
|
|
return $groupID;
|
|
}
|
|
|
|
/**
|
|
* 将内置透视表转化为中间表。
|
|
* Convert built-in dataset to dataview.
|
|
*
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function convertBuiltInDataSet(): void
|
|
{
|
|
$this->loadModel('dataset');
|
|
$this->loadModel('dataview');
|
|
$dataview = new stdclass();
|
|
$dataview->group = $this->getDataviewGroupID($this->lang->dataview->builtIn);
|
|
$dataview->createdBy = 'system';
|
|
$dataview->createdDate = helper::now();
|
|
|
|
foreach($this->lang->dataset->tables as $code => $dataset)
|
|
{
|
|
$sameCodeList = $this->dao->select('*')->from(TABLE_DATAVIEW)->where('code')->eq($code)->fetchAll();
|
|
if(!empty($sameCodeList)) continue;
|
|
|
|
$dataview->name = $dataset['name'];
|
|
$dataview->code = $code;
|
|
$dataview->view = 'ztv_' . $code;
|
|
|
|
$table = $this->dataset->getTableInfo($code);
|
|
$dataview->sql = $this->dataset->getTableData($table->schema, 'id_desc', 100, true);
|
|
|
|
$fields = array();
|
|
foreach($table->schema->fields as $key => $field)
|
|
{
|
|
$relatedField = '';
|
|
if($field['type'] == 'object' && isset($field['show']))
|
|
{
|
|
$key = str_replace('.', '_', $field['show']);
|
|
$relatedField = substr($field['show'], strpos($field['show'], '.') + 1);
|
|
$relatedObject = isset($field['object']) ? $field['object'] : '';
|
|
if(!empty($relatedObject) && isset($table->schema->objects[$relatedObject]))
|
|
{
|
|
foreach($table->schema->objects[$relatedObject] as $fieldID => $fieldName)
|
|
{
|
|
if($fieldID == $relatedField) continue;
|
|
|
|
$addField = "{$relatedObject}_{$fieldID}";
|
|
$fields[$addField] = array();
|
|
$fields[$addField]['name'] = isset($fieldName['name']) ? $fieldName['name'] : $addField;
|
|
$fields[$addField]['field'] = $fieldID;
|
|
$fields[$addField]['object'] = $relatedObject;
|
|
$fields[$addField]['type'] = 'object';
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!isset($fields[$key])) $fields[$key] = array();
|
|
$fields[$key]['name'] = $field['name'];
|
|
$fields[$key]['field'] = empty($relatedField) ? $key : $relatedField;
|
|
$fields[$key]['object'] = isset($field['object']) ? $field['object'] : $code;
|
|
$fields[$key]['type'] = $field['type'];
|
|
}
|
|
$dataview->fields = json_encode($fields);
|
|
|
|
$this->dao->insert(TABLE_DATAVIEW)->data($dataview)->exec();
|
|
$dataviewID = $this->dao->lastInsertID();
|
|
if(!empty($dataview->view) && !empty($dataview->sql)) $this->dataview->createViewInDB($dataviewID, $dataview->view, $dataview->sql);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将自定义透视表转化为中间表。
|
|
* Convert custom dataset to dataview.
|
|
*
|
|
* @param array $customDataset
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function convertCustomDataSet(array $customDataset): void
|
|
{
|
|
$dataview = new stdclass();
|
|
$dataview->group = $this->getDataviewGroupID($this->lang->dataview->default);
|
|
|
|
foreach($customDataset as $datasetID => $dataset)
|
|
{
|
|
$dataview->name = $dataset->name;
|
|
$dataview->code = 'custom_' . $datasetID;
|
|
$dataview->view = 'ztv_custom_' . $datasetID;
|
|
$dataview->sql = $dataset->sql;
|
|
$dataview->fields = $dataset->fields;
|
|
$dataview->createdBy = $dataset->createdBy;
|
|
$dataview->createdDate = $dataset->createdDate;
|
|
$dataview->deleted = $dataset->deleted;
|
|
|
|
$this->dao->insert(TABLE_DATAVIEW)->data($dataview)->exec();
|
|
$dataviewID = $this->dao->lastInsertID();
|
|
if(!empty($dataview->view) && !empty($dataview->sql)) $this->dataview->createViewInDB($dataviewID, $dataview->view, $dataview->sql);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取标准的版本 sql 语句。
|
|
* Get standard sqls by version.
|
|
*
|
|
* @param string $version
|
|
* @access protected
|
|
* @return string
|
|
*/
|
|
protected function getStandardSQLs(string $version): string
|
|
{
|
|
if(empty($version)) $version = $this->config->installedVersion;
|
|
|
|
$version = str_replace('.', '_', $version);
|
|
$openVersion = $this->getOpenVersion($version);
|
|
$openVersion = str_replace('_', '.', $openVersion);
|
|
$checkVersion = version_compare($openVersion, '16.5', '<') ? str_replace('_', '.', $version) : $openVersion;
|
|
|
|
$standardSQL = $this->app->getAppRoot() . 'db' . DS . 'standard' . DS . 'zentao' . $checkVersion . '.sql';
|
|
if(!file_exists($standardSQL)) return '';
|
|
$sqls = file_get_contents($standardSQL);
|
|
|
|
if(empty($this->config->isINT))
|
|
{
|
|
$xStandardSQL = $this->app->getAppRoot() . 'db' . DS . 'standard' . DS . 'xuanxuan' . $openVersion . '.sql';
|
|
if(file_exists($xStandardSQL)) $sqls .= "\n" . file_get_contents($xStandardSQL);
|
|
}
|
|
return $sqls;
|
|
}
|
|
|
|
/**
|
|
* 根据 sql 语句获取数据库中的字段。
|
|
* Get fields in database by sql.
|
|
*
|
|
* @param string $sql
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function getFieldsBySQL(string $sql): array
|
|
{
|
|
$return = array('fields' => array(), 'lines' => array(), 'table' => '', 'tableExists' => true, 'changeEngineSQL' => '');
|
|
$lines = explode("\n", $sql);
|
|
|
|
/* If table name isn't exist, skip it. . */
|
|
$createHead = array_shift($lines);
|
|
preg_match_all('/CREATE TABLE `([^`]*)`/', $createHead, $out);
|
|
if(!isset($out[1][0])) return array_values($return);
|
|
|
|
$return['table'] = str_replace('zt_', $this->config->db->prefix, $out[1][0]);
|
|
try
|
|
{
|
|
$dbCreateSQL = $this->dbh->query("SHOW CREATE TABLE `{$return['table']}`")->fetch(PDO::FETCH_ASSOC);
|
|
$dbSQLLines = explode("\n", $dbCreateSQL['Create Table']);
|
|
$dbSQLFoot = array_pop($dbSQLLines);
|
|
preg_match_all('/ENGINE=(\w+) /', $dbSQLFoot, $out);
|
|
$dbEngine = isset($out[1][0]) ? $out[1][0] : 'InnoDB';
|
|
|
|
array_shift($dbSQLLines);
|
|
foreach($dbSQLLines as $dbSQLLine)
|
|
{
|
|
$dbSQLLine = trim($dbSQLLine);
|
|
if(!preg_match('/^`([^`]*)` /', $dbSQLLine)) continue; // Skip no describe field line.
|
|
|
|
$dbSQLLine = rtrim($dbSQLLine, ',');
|
|
$dbSQLLine = str_replace('utf8 COLLATE utf8_general_ci', 'utf8', $dbSQLLine);
|
|
$dbSQLLine = preg_replace('/ DEFAULT (\-?\d+\.?\d*)$/', " DEFAULT '$1'", $dbSQLLine);
|
|
list($field) = explode(' ', $dbSQLLine);
|
|
$return['fields'][$field] = rtrim($dbSQLLine, ',');
|
|
}
|
|
}
|
|
catch(PDOException $e)
|
|
{
|
|
$errorInfo = $e->errorInfo;
|
|
$errorCode = $errorInfo[1];
|
|
if($errorCode == '1146') $return['tableExists'] = false; // If table is not extists, try create this table by create sql.
|
|
}
|
|
|
|
/* If the table engine in the database isn't the standard engine, change the table engine in the database to the standard engine. */
|
|
$createFoot = array_pop($lines);
|
|
preg_match_all('/ENGINE=(\w+) /', $createFoot, $out);
|
|
$stdEngine = isset($out[1][0]) ? $out[1][0] : 'InnoDB';
|
|
if($stdEngine != $dbEngine) $return['changeEngineSQL'] = "ALTER TABLE `{$return['table']}` ENGINE='{$stdEngine}'";
|
|
|
|
$return['lines'] = $lines;
|
|
return array_values($return);
|
|
}
|
|
|
|
/**
|
|
* 根据标准 sql 语句修改数据库中的字段。
|
|
* Change fields in database by standard sql.
|
|
*
|
|
* @param string $stdLine
|
|
* @param string $dbLine
|
|
* @access protected
|
|
* @return string
|
|
*/
|
|
protected function changeField(string $stdLine, string $dbLine): string
|
|
{
|
|
/* Get configs. */
|
|
$stdConfigs = explode(' ', $stdLine);
|
|
$dbConfigs = explode(' ', $dbLine);
|
|
if($stdConfigs[1] != $dbConfigs[1])
|
|
{
|
|
/* Get field type. */
|
|
$stdType = $stdConfigs[1];
|
|
$dbType = $dbConfigs[1];
|
|
$stdLength = 0;
|
|
$dbLength = 0;
|
|
|
|
/* Get field type and length. */
|
|
preg_match_all('/^(\w+)(\((\d+)\))?$/', $stdConfigs[1], $stdOutput);
|
|
if(!empty($stdOutput[1][0])) $stdType = $stdOutput[1][0];
|
|
if(!empty($stdOutput[3][0])) $stdLength = $stdOutput[3][0];
|
|
preg_match_all('/^(\w+)(\((\d+)\))?$/', $dbConfigs[1], $dbOutput);
|
|
if(!empty($dbOutput[1][0])) $dbType = $dbOutput[1][0];
|
|
if(!empty($dbOutput[3][0])) $dbLength = $dbOutput[3][0];
|
|
|
|
$stdIsInt = stripos($stdType, 'int') !== false;
|
|
$stdIsVarchar = stripos($stdType, 'varchar') !== false;
|
|
$stdIsText = stripos($stdType, 'text') !== false;
|
|
$dbIsInt = stripos($dbType, 'int') !== false;
|
|
$dbIsText = stripos($dbType, 'text') !== false;
|
|
/* If the type in database is int and the length of type is empty, get the length from the config. */
|
|
if($dbIsInt && $dbLength == 0)
|
|
{
|
|
$intFieldLengths = zget($this->config->upgrade->dbFieldLengths, $dbConfigs[2] == 'unsigned' ? 'unsigned' : 'int', array());
|
|
$dbLength = zget($intFieldLengths, $dbType, 0);
|
|
}
|
|
if($dbLength > $stdLength) $stdConfigs[1] = $dbConfigs[1]; // If the length in database is longer than the length in standard, use the length in database.
|
|
if($stdIsInt && $dbIsText) $stdConfigs[1] = $dbConfigs[1]; // If the type in standard is int and the type in database is text, use text as the type.
|
|
if($stdIsVarchar && $dbIsText) $stdConfigs[1] = $dbConfigs[1]; // If the type in standard is varchar and the type in database is text, use text as the type.
|
|
/* If both of the type in standard and in database are text, get the length from the config. */
|
|
if($stdIsText && $dbIsText)
|
|
{
|
|
$textFieldLengths = $this->config->upgrade->dbFieldLengths['text'];
|
|
if($textFieldLengths[$stdType] < $textFieldLengths[$dbType]) $stdConfigs[1] = $dbConfigs[1];
|
|
}
|
|
if(stripos($stdConfigs[1], 'int') === false && $stdConfigs[2] == 'unsigned') unset($stdConfigs[2]);
|
|
|
|
$stdLine = implode(' ', $stdConfigs);
|
|
if($stdLine == $dbLine) return ''; // If the sql is same, won't change it.
|
|
}
|
|
return $stdLine;
|
|
}
|
|
|
|
/**
|
|
* 获取查询关联到发布的动作的sql。
|
|
* Get sql of query action linked to release.
|
|
*
|
|
* @access protected
|
|
* @return string
|
|
*/
|
|
protected function getLinked2releaseActionsSql()
|
|
{
|
|
return $this->dao->select('objectID, extra, max(`date`) as date, action')
|
|
->from(TABLE_ACTION)
|
|
->where('objectType')->eq('story')
|
|
->andWhere('action')->eq('linked2release')
|
|
->groupBy('objectID,extra,action')
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* 获取关联分支记录相关的数据。
|
|
* Get data linked to release.
|
|
*
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function getReleasedStorys()
|
|
{
|
|
$linked2releaseActions = $this->getLinked2releaseActionsSql();
|
|
|
|
return $this->dao->select('t2.id, t1.date')
|
|
->from("($linked2releaseActions)")->alias('t1')
|
|
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.objectID = t2.id')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t2.product = t3.id')
|
|
->leftJoin(TABLE_RELEASE)->alias('t4')->on('t1.extra = t4.id')
|
|
->where('t2.deleted')->eq('0')
|
|
->andWhere('t3.deleted')->eq('0')
|
|
->andWhere('t2.stage', true)->eq('released')
|
|
->orWhere('t2.closedReason')->eq('done')
|
|
->markRight(1)
|
|
->fetchAll();
|
|
}
|
|
|
|
/**
|
|
* 在工作流表中插入内置模块数据。
|
|
* Create buildin modules to TABLE_WORKFLOW.
|
|
*
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function createModules2Workflow(): void
|
|
{
|
|
$data = new stdclass();
|
|
$data->vision = 'rnd';
|
|
$data->buildin = 1;
|
|
$data->createdBy = isset($this->app->user) ? $this->app->user->account : 'admin';
|
|
$data->createdDate = helper::now();
|
|
$data->status = 'normal';
|
|
foreach($this->config->workflow->buildin->modules as $app => $appModules)
|
|
{
|
|
$data->app = $app;
|
|
foreach($appModules as $module => $options)
|
|
{
|
|
$this->app->loadLang($module);
|
|
|
|
$data->module = $module;
|
|
$data->name = isset($this->lang->$module->common) ? $this->lang->$module->common : $module;
|
|
$data->table = str_replace('`', '', zget($options, 'table', ''));
|
|
$data->navigator = zget($options, 'navigator', 'secondary');
|
|
if($module == 'story') $data->name = $this->lang->searchObjects['story'];
|
|
if($module == 'execution') $data->name = $this->lang->workflow->execution;
|
|
|
|
$modelField = $this->dao->select('id')->from(TABLE_WORKFLOW)->where('app')->eq($app)->andWhere('module')->eq($module)->andWhere('vision')->eq('rnd')->fetch('id');
|
|
if(!$modelField) $this->dao->insert(TABLE_WORKFLOW)->data($data)->exec();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 在工作流操作表中插入内置模块操作数据。
|
|
* Create buildin modules actions to TABLE_WORKFLOWACTION.
|
|
*
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function createActions2Workflow(): void
|
|
{
|
|
$actions = $this->config->workflowaction->buildin->actions;
|
|
$actionTypes = $this->config->workflowaction->buildin->types;
|
|
$actionMethods = $this->config->workflowaction->buildin->methods;
|
|
$actionOpens = $this->config->workflowaction->buildin->opens;
|
|
$actionLayouts = $this->config->workflowaction->buildin->layouts;
|
|
$actionPositions = $this->config->workflowaction->buildin->positions;
|
|
$actionShows = $this->config->workflowaction->buildin->shows;
|
|
|
|
$data = new stdclass();
|
|
$data->buildin = 1;
|
|
$data->role = 'buildin';
|
|
$data->extensionType = 'none';
|
|
$data->createdBy = isset($this->app->user) ? $this->app->user->account : 'admin';
|
|
$data->createdDate = helper::now();
|
|
foreach($actions as $module => $moduleActions)
|
|
{
|
|
$data->module = $module;
|
|
foreach($moduleActions as $action)
|
|
{
|
|
$data->action = $action;
|
|
|
|
/* Use default action name if not set flow action name. */
|
|
$name = '';
|
|
if(isset($this->lang->$module->$action)) $name = $this->lang->$module->$action;
|
|
if(empty($name) && in_array($action, array_keys($this->config->flowAction)))
|
|
{
|
|
$methodName = $this->config->flowAction[$action];
|
|
if(isset($this->lang->$module->$methodName)) $name = $this->lang->$module->$methodName;
|
|
}
|
|
if(empty($name) && isset($this->lang->workflowaction->default->actions[$action])) $name = $this->lang->workflowaction->default->actions[$action];
|
|
if(empty($name)) $name = $action;
|
|
$data->name = $name;
|
|
|
|
$data->method = $data->action;
|
|
$data->open = 'normal';
|
|
$data->layout = 'normal';
|
|
$data->type = 'single';
|
|
$data->position = 'browseandview';
|
|
$data->show = 'direct';
|
|
|
|
if(isset($actionMethods[$module][$action])) $data->method = $actionMethods[$module][$action];
|
|
if(isset($actionOpens[$module][$action])) $data->open = $actionOpens[$module][$action];
|
|
if(isset($actionLayouts[$module][$action])) $data->layout = $actionLayouts[$module][$action];
|
|
if(isset($actionTypes[$module][$action])) $data->type = $actionTypes[$module][$action];
|
|
if(isset($actionPositions[$module][$action])) $data->position = $actionPositions[$module][$action];
|
|
if(isset($actionShows[$module][$action])) $data->show = $actionShows[$module][$action];
|
|
|
|
$actionField = $this->dao->select('id')->from(TABLE_WORKFLOWACTION)->where('module')->eq($module)->andWhere('action')->eq($action)->andWhere('vision')->eq('rnd')->fetch('id');
|
|
if(!$actionField) $this->dao->insert(TABLE_WORKFLOWACTION)->data($data)->exec();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 在工作流布局表中插入内置模块布局数据。
|
|
* Insert layouts of buildin modules to TABLE_WORKFLOWLAYOUT.
|
|
*
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function createLayouts2Workflow(): void
|
|
{
|
|
$data = new stdclass();
|
|
foreach($this->config->workflowlayout->buildin->layouts as $module => $moduleLayouts)
|
|
{
|
|
$data->module = $module;
|
|
foreach($moduleLayouts as $action => $layoutFields)
|
|
{
|
|
$order = 1;
|
|
$data->action = $action;
|
|
foreach($layoutFields as $field => $options)
|
|
{
|
|
$data->field = $field;
|
|
$data->width = zget($options, 'width', 0);
|
|
$data->mobileShow = zget($options, 'mobileShow', 0);
|
|
$data->order = $order++;
|
|
|
|
if($data->width == 'auto') $data->width = 0;
|
|
|
|
$layoutField = $this->dao->select('id')->from(TABLE_WORKFLOWLAYOUT)->where('module')->eq($module)->andWhere('action')->eq($action)->andWhere('field')->eq($field)->andWhere('vision')->eq('rnd')->fetch('id');
|
|
if(!$layoutField) $this->dao->insert(TABLE_WORKFLOWLAYOUT)->data($data)->exec();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 为项目创建项目主库。
|
|
* Create doc lib for project.
|
|
*
|
|
* @param object $project
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function createProjectDocLib(object $project): void
|
|
{
|
|
$this->app->loadLang('doc');
|
|
|
|
$lib = new stdclass();
|
|
$lib->project = $project->id;
|
|
$lib->name = $this->lang->doclib->main['project'];
|
|
$lib->type = 'project';
|
|
$lib->main = '1';
|
|
$lib->acl = $project->acl != 'program' ? $project->acl : 'custom';
|
|
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
|
}
|
|
|
|
/**
|
|
* 获取没有合并的冲刺。
|
|
* Get sprints has not been merged.
|
|
*
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function getNoMergedSprints(): array
|
|
{
|
|
return $this->dao->select('*')->from(TABLE_PROJECT)
|
|
->where('project')->eq(0)
|
|
->andWhere('vision')->eq('rnd')
|
|
->andWhere('type')->eq('sprint')
|
|
->andWhere('deleted')->eq(0)
|
|
->fetchAll('id', false);
|
|
}
|
|
|
|
/**
|
|
* 更新文件对象。
|
|
* Update file objects.
|
|
*
|
|
* @param string $type
|
|
* @param int $lastID
|
|
* @param int $limit
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function updateFileObjects(string $type, int $lastID, int $limit)
|
|
{
|
|
/* Get type editor, fields, and query conditions. */
|
|
$cond = array();
|
|
$editorFields = array();
|
|
$editor = $this->config->upgrade->editors[$type];
|
|
$fields = explode(',', $editor['fields']);
|
|
foreach($fields as $field)
|
|
{
|
|
if(strpos($field, '`') !== false)
|
|
{
|
|
$cond[] = $field . " like '%data/upload/%'";
|
|
$editorFields[] = $field;
|
|
}
|
|
else
|
|
{
|
|
$idField = $field;
|
|
}
|
|
}
|
|
|
|
/* Get objects. */
|
|
$objects = $this->dao->select($editor['fields'])->from($editor['table'])
|
|
->where($idField)->gt($lastID)
|
|
->beginIF($cond)->andWhere('(' . join(' OR ', $cond) . ')')->fi()
|
|
->orderBy($idField)
|
|
->limit($limit)
|
|
->fetchAll($idField);
|
|
foreach($objects as $object)
|
|
{
|
|
$files = array();
|
|
/* Get files in the editor fields. */
|
|
foreach($editorFields as $field)
|
|
{
|
|
$field = trim($field, '`');
|
|
preg_match_all('/"\/?data\/upload\/.*1\/([0-9]{6}\/[^"]+)"/', $object->{$field}, $output);
|
|
foreach($output[1] as $path) $files[$path] = $path;
|
|
}
|
|
/* If the file exists, update the file. */
|
|
if($files) $this->dao->update(TABLE_FILE)->set('objectType')->eq($type)->set('objectID')->eq($object->{$idField})->set('extra')->eq('editor')->where('pathname')->in($files)->exec();
|
|
}
|
|
|
|
return array(count($objects), isset($object) ? $object->{$idField} : 0);
|
|
}
|
|
|
|
/**
|
|
* 通过已有的产品获取未关联项目的相关数据,并且关联到项目。
|
|
* Get data from product and relate to project.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $productIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function updateProjectByProduct(int $projectID, array $productIdList): void
|
|
{
|
|
if(empty($productIdList)) return;
|
|
|
|
$this->dao->update(TABLE_BUG)->set('project')->eq($projectID)->where('product')->in($productIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_TESTREPORT)->set('project')->eq($projectID)->where('product')->in($productIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_TESTSUITE)->set('project')->eq($projectID)->where('product')->in($productIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_RELEASE)->set('project')->eq($projectID)->where('product')->in($productIdList)->exec();
|
|
}
|
|
|
|
/**
|
|
* 通过已有的执行获取为关联项目的相关数据,并且关联到项目。
|
|
* Get data from product and relate to project.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $productIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function updateProjectByExecution(int $projectID, array $sprintIdList): void
|
|
{
|
|
$this->dao->update(TABLE_TASK)->set('project')->eq($projectID)->where('execution')->in($sprintIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_BUILD)->set('project')->eq($projectID)->where('execution')->in($sprintIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_BUG)->set('project')->eq($projectID)->where('execution')->in($sprintIdList)->exec();
|
|
$this->dao->update(TABLE_DOC)->set('project')->eq($projectID)->where("lib IN(SELECT id from " . TABLE_DOCLIB . " WHERE type = 'execution' and execution " . helper::dbIN($sprintIdList) . ')')->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_DOCLIB)->set('project')->eq($projectID)->where('type')->eq('execution')->andWhere('execution')->in($sprintIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_TESTTASK)->set('project')->eq($projectID)->where('execution')->in($sprintIdList)->andWhere('project')->eq(0)->exec();
|
|
$this->dao->update(TABLE_EFFORT)->set('project')->eq($projectID)->where('execution')->in($sprintIdList)->andWhere('objectType')->eq('task')->exec();
|
|
}
|
|
|
|
/**
|
|
* 将执行下的所有需求相关转移到项目下。
|
|
* Move all stories under execution to project.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $sprintIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function moveSprintStoryToProject(int $projectID, array $sprintIdList): void
|
|
{
|
|
$sprintStories = $this->dao->select('*')->from(TABLE_PROJECTSTORY)
|
|
->where('project')->in($sprintIdList)
|
|
->fetchAll();
|
|
|
|
foreach($sprintStories as $sprintStory)
|
|
{
|
|
$projectStory = $sprintStory;
|
|
$projectStory->project = $projectID;
|
|
$this->dao->replace(TABLE_PROJECTSTORY)->data($projectStory)->exec();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将执行下的所有用例关联关系转移到项目下。
|
|
* Move all cases under execution to project.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $sprintIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function moveSprintCaseToProject(int $projectID, array $sprintIdList): void
|
|
{
|
|
$projectCases = $this->dao->select('`case`,product,project,count,version')->from(TABLE_PROJECTCASE)
|
|
->where('project')->in($sprintIdList)
|
|
->fetchAll();
|
|
|
|
foreach($projectCases as $projectCase)
|
|
{
|
|
$projectCase->project = $projectID;
|
|
$projectCase->order = $projectCase->case * 5;
|
|
$this->dao->replace(TABLE_PROJECTCASE)->data($projectCase)->exec();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将执行下虽有的测试用例相关都转移到项目下。
|
|
*
|
|
* @param int $projectID
|
|
* @param array $sprintIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function moveAllTestTaskToProject(int $projectID, array $sprintIdList): void
|
|
{
|
|
$sprintCases = $this->dao->select('t2.case,t2.version,t1.product,t1.execution as project')
|
|
->from(TABLE_TESTTASK)->alias('t1')
|
|
->leftJoin(TABLE_TESTRUN)->alias('t2')->on('t1.id = t2.task')
|
|
->where('t1.execution')->in($sprintIdList)
|
|
->fetchAll();
|
|
|
|
foreach($sprintCases as $sprintCase)
|
|
{
|
|
$sprintCase->case = (int)$sprintCase->case;
|
|
$sprintCase->version = (int)$sprintCase->version;
|
|
$this->dao->replace(TABLE_PROJECTCASE)->data($sprintCase)->exec();
|
|
|
|
$sprintCase->order = $sprintCase->case * 5;
|
|
$sprintCase->project = $projectID;
|
|
$this->dao->replace(TABLE_PROJECTCASE)->data($sprintCase)->exec();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将项目的信息同步给所有的执行。
|
|
* Sync project info to all executions.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $sprintIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function syncProjectInfoForSprints(int $projectID, array $sprintIdList, int $programID, bool $isProjectType = false): void
|
|
{
|
|
$project = $this->dao->findById($projectID)->from(TABLE_PROJECT)->fetch();
|
|
$sprints = $this->dao->select('id, type, acl, begin, end')->from(TABLE_PROJECT)->where('id')->in($sprintIdList)->fetchAll();
|
|
$minBeginDate = $project->begin;
|
|
$maxEndDate = $project->end;
|
|
|
|
foreach($sprints as $sprint)
|
|
{
|
|
$data = new stdclass();
|
|
$data->project = $projectID;
|
|
$data->parent = $projectID;
|
|
$data->grade = 1;
|
|
$data->path = ",{$projectID},{$sprint->id},";
|
|
$data->type = 'sprint';
|
|
$data->acl = $sprint->acl == 'custom' ? 'private' : $sprint->acl;
|
|
|
|
$this->dao->update(TABLE_PROJECT)->data($data)->where('id')->eq($sprint->id)->exec();
|
|
|
|
$minBeginDate = ($sprint->begin < $minBeginDate) ? $sprint->begin : $minBeginDate;
|
|
$maxEndDate = $sprint->end > $maxEndDate ? $sprint->end : $maxEndDate;
|
|
}
|
|
|
|
if($isProjectType)
|
|
{
|
|
list($minRealBegan, $maxRealEnd) = $this->getMaxAndMinDateByAction($projectID, $sprintIdList);
|
|
$this->updateProjectTime($project, $minRealBegan, $maxRealEnd, $minBeginDate, $maxEndDate, $projectID, $programID);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据历史记录获取项目的最小开始时间和最大结束时间。
|
|
* Get min begin date and max end date by action.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $sprintIdList
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function getMaxAndMinDateByAction(int $projectID, array $sprintIdList): array
|
|
{
|
|
|
|
$linkedSprintIdList = $this->dao->select('id')->from(TABLE_PROJECT)->where('project')->eq($projectID)->fetchPairs();
|
|
$linkedSprintIdList += $sprintIdList;
|
|
$minRealBegan = $this->dao->select('date')->from(TABLE_ACTION)->where('objectID')->in($linkedSprintIdList)->andWhere('objectType')->eq('project')->andWhere('action')->eq('started')->orderBy('date_asc')->fetch('date');
|
|
$maxRealEnd = $this->dao->select('date')->from(TABLE_ACTION)->where('objectID')->in($linkedSprintIdList)->andWhere('objectType')->eq('project')->andWhere('action')->eq('closed')->orderBy('date_desc')->fetch('date');
|
|
|
|
return array($minRealBegan, $maxRealEnd);
|
|
}
|
|
|
|
/**
|
|
* 更新项目以及项目所属项目集的时间相关数据。
|
|
* Update project and program time.
|
|
*
|
|
* @param object $project
|
|
* @param string $minRealBegan
|
|
* @param string $maxRealEnd
|
|
* @param string $minBeginDate
|
|
* @param string $maxEndDate
|
|
* @param int $projectID
|
|
* @param int $programID
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function updateProjectTime(object $project, string $minRealBegan, string $maxRealEnd, string $minBeginDate, string $maxEndDate, int $projectID, int $programID): void
|
|
{
|
|
$data = new stdClass();
|
|
$data->realBegan = $minRealBegan ? substr($minRealBegan, 0, 10) : '0000-00-00';
|
|
|
|
$projectStatus = $this->dao->select('status')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch('status');
|
|
if($projectStatus == 'closed')
|
|
{
|
|
$data->realEnd = substr($maxRealEnd, 0, 10);
|
|
$data->closedDate = $maxRealEnd;
|
|
}
|
|
|
|
if($minBeginDate != $project->begin || $maxEndDate != $project->end)
|
|
{
|
|
$data->begin = $minBeginDate;
|
|
$data->end = $maxEndDate;
|
|
$data->days = $this->computeDaysDelta($data->begin, $data->end);
|
|
}
|
|
|
|
if(helper::isZeroDate($data->realBegan)) unset($data->realBegan);
|
|
if(isset($data->realEnd) and helper::isZeroDate($data->realEnd)) unset($data->realEnd);
|
|
if(isset($data->closedDate) and helper::isZeroDate($data->closedDate)) unset($data->closedDate);
|
|
if(isset($data->begin) and helper::isZeroDate($data->begin)) unset($data->begin);
|
|
if(isset($data->end) and helper::isZeroDate($data->end)) unset($data->end);
|
|
if(empty(get_object_vars($data))) return;
|
|
|
|
$this->dao->update(TABLE_PROJECT)->data($data)->where('id')->eq($projectID)->exec();
|
|
$this->dao->update(TABLE_PROGRAM)->data($data)->where('id')->eq($programID)->exec();
|
|
}
|
|
|
|
/**
|
|
* 设置项目和产品的关联关系。
|
|
* Set relation between project and product.
|
|
*
|
|
* @param int $projectID
|
|
* @param array $productIdList
|
|
* @param array $sprintIdList
|
|
* @access protected
|
|
* @return void
|
|
*/
|
|
protected function setProjectProductsRelation(int $projectID, array $productIdList, array $sprintIdList): void
|
|
{
|
|
$sprintProducts = $this->dao->select('product,branch,plan')->from(TABLE_PROJECTPRODUCT)->where('project')->in($sprintIdList)->andWhere('product')->in($productIdList)->fetchGroup('product', 'branch');
|
|
$projectProducts = $this->dao->select('product,branch,plan')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->andWhere('product')->in($productIdList)->fetchGroup('product', 'branch');
|
|
|
|
foreach($productIdList as $productID)
|
|
{
|
|
$data = new stdclass();
|
|
$data->project = $projectID;
|
|
$data->product = $productID;
|
|
if(isset($sprintProducts[$productID]))
|
|
{
|
|
foreach($sprintProducts[$productID] as $branchID => $sprintProduct)
|
|
{
|
|
$data->plan = $sprintProduct->plan;
|
|
$data->branch = $branchID;
|
|
if(isset($projectProducts[$productID][$branchID]) and !empty($projectProducts[$productID][$branchID]->plan))
|
|
{
|
|
$data->plan .= ',' . $projectProducts[$productID][$branchID]->plan;
|
|
$data->plan = implode(',', array_unique(array_filter(explode(',', $data->plan))));
|
|
}
|
|
$this->dao->replace(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$data->plan = 0;
|
|
$data->branch = 0;
|
|
$this->dao->replace(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 为作为项目升级构建项目数据。
|
|
* Build project data when auto upgrading.
|
|
*
|
|
* @param object $sprint
|
|
* @param int $programID
|
|
* @param string $fromMode
|
|
* @param string $account
|
|
* @param string $now
|
|
* @access protected
|
|
* @return object
|
|
*/
|
|
protected function buildProjectInAutoUpgrade(object $sprint, int $programID, string $fromMode, string $account, string $now): object
|
|
{
|
|
$project = new stdclass();
|
|
$project->name = $sprint->name;
|
|
$project->desc = $sprint->desc;
|
|
$project->type = 'project';
|
|
$project->model = 'scrum';
|
|
$project->parent = $programID;
|
|
$project->status = $sprint->status;
|
|
$project->begin = $sprint->begin;
|
|
$project->end = isset($sprint->end) ? $sprint->end : LONG_TIME;
|
|
$project->realBegan = zget($sprint, 'realBegan', '');
|
|
$project->realEnd = zget($sprint, 'realEnd', '');
|
|
$project->PM = $sprint->PM;
|
|
$project->auth = 'extend';
|
|
$project->openedBy = $account;
|
|
$project->openedDate = $now;
|
|
$project->openedVersion = $this->config->version;
|
|
$project->lastEditedBy = $account;
|
|
$project->lastEditedDate = $now;
|
|
$project->grade = 2;
|
|
$project->acl = $sprint->acl == 'open' ? 'open' : 'private';
|
|
$project->storyType = 'story';
|
|
|
|
if($fromMode == 'classic')
|
|
{
|
|
$project->multiple = '0';
|
|
$project->code = $sprint->code;
|
|
$project->team = $sprint->team;
|
|
$project->openedBy = $sprint->openedBy;
|
|
$project->openedDate = $sprint->openedDate;
|
|
}
|
|
|
|
if(helper::isZeroDate($project->realBegan)) unset($project->realBegan);
|
|
if(helper::isZeroDate($project->realEnd)) unset($project->realEnd);
|
|
|
|
return $project;
|
|
}
|
|
|
|
/**
|
|
* 检查创建项目时的必填字段。
|
|
* Check fields required when create program.
|
|
*
|
|
* @param object $data
|
|
* @param string $projectType
|
|
* @access protected
|
|
* @return bool
|
|
*/
|
|
protected function checkProgramRequired(object $data, string $projectType): bool
|
|
{
|
|
if(empty($data->programName))
|
|
{
|
|
dao::$errors['programName'][] = sprintf($this->lang->error->notempty, $this->lang->upgrade->programName);
|
|
return false;
|
|
}
|
|
|
|
if(empty($data->longTime) && empty($data->end) && isset($data->begin))
|
|
{
|
|
dao::$errors['end'][] = sprintf($this->lang->error->notempty, $this->lang->upgrade->end);
|
|
return false;
|
|
}
|
|
|
|
if(isset($data->projectName) && $projectType == 'execution' && empty($data->projectName))
|
|
{
|
|
dao::$errors['projectName'][] = sprintf($this->lang->error->notempty, $this->lang->upgrade->projectName);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 获取重复的项目名称。
|
|
* Get duplicate project name.
|
|
*
|
|
* @param array $projectIdList
|
|
* @access protected
|
|
* @return string
|
|
*/
|
|
protected function getDuplicateProjectName(array $projectIdList): string
|
|
{
|
|
$projectPairs = $this->dao->select('id, name')->from(TABLE_EXECUTION)->where('deleted')->eq('0')->andWhere('id')->in($projectIdList)->fetchPairs();
|
|
$projectNames = array();
|
|
$duplicateList = '';
|
|
foreach($projectPairs as $projectID => $projectName)
|
|
{
|
|
if(isset($projectNames[$projectName]))
|
|
{
|
|
$duplicateList .= "$projectID,";
|
|
$duplicateList .= "{$projectNames[$projectName]},";
|
|
continue;
|
|
}
|
|
|
|
$projectNames[$projectName] = $projectID;
|
|
}
|
|
|
|
return $duplicateList;
|
|
}
|
|
|
|
/**
|
|
* 获取工作流组列表
|
|
* Get workflow group list for process.
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function getWorkflowGroupForProcess()
|
|
{
|
|
return $this->dao->select('id,projectModel,projectType,main')->from(TABLE_WORKFLOWGROUP)
|
|
->where('projectModel')->in('scrum,waterfall,agileplus,waterfallplus')
|
|
->andWhere('deleted')->eq('0')
|
|
->fetchAll('id');
|
|
}
|
|
|
|
/**
|
|
* 处理使用内置数据的流程。
|
|
* Handle buildin workflow group.
|
|
*
|
|
* @param object $group 流程对象
|
|
* @param int $groupID 流程ID
|
|
* @param array $classifyModule 分类模块数组
|
|
* @return array
|
|
*/
|
|
protected function handleBuildinWorkflowGroup(object $group, int $groupID, array $classifyModule)
|
|
{
|
|
$this->dao->update(TABLE_PROCESS)->set('workflowGroup')->eq($groupID)->where('model')->eq($group->projectModel)->exec();
|
|
|
|
/* 更新活动的流程。 */
|
|
$processList = $this->dao->select('id')->from(TABLE_PROCESS)->where('workflowGroup')->eq($groupID)->andWhere('deleted')->eq('0')->fetchPairs();
|
|
$this->dao->update(TABLE_ACTIVITY)->set('workflowGroup')->eq($groupID)->where('process')->in(array_keys($processList))->exec();
|
|
|
|
$this->migrateOutputToDeliverable($group);
|
|
|
|
$classifyModule[$groupID] = $this->migrateClassifyToModule($group, $groupID);
|
|
|
|
return $classifyModule;
|
|
}
|
|
|
|
/**
|
|
* 将过程分类从语言表迁移到模块表
|
|
* Migrate process classify from language table to module table.
|
|
*
|
|
* @param object $group 流程对象
|
|
* @param int $groupID 流程ID
|
|
* @return array
|
|
*/
|
|
protected function migrateClassifyToModule(object $group, int $groupID)
|
|
{
|
|
$this->app->loadLang('process');
|
|
$classifyKey = $group->projectModel == 'waterfall' ? 'classify' : $group->projectModel . 'Classify';
|
|
$classifyList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('process')->andWhere('section')->eq($classifyKey)->fetchPairs();
|
|
if(empty($classifyList)) $classifyList = $this->lang->process->classifyList;
|
|
|
|
$orderList = array('project' => 10, 'engineering' => 20, 'support' => 30);
|
|
|
|
$classifyModule = array();
|
|
$customOrder = 40;
|
|
foreach($classifyList as $key => $value)
|
|
{
|
|
$order = isset($orderList[$key]) ? $orderList[$key] : $customOrder;
|
|
$moduleID = $this->createProcessModule($groupID, $key, $value, $order);
|
|
$classifyModule[$key] = $moduleID;
|
|
if(!isset($orderList[$key])) $customOrder += 10;
|
|
}
|
|
|
|
return $classifyModule;
|
|
}
|
|
|
|
/**
|
|
* 创建过程模块。
|
|
* Create process module.
|
|
*
|
|
* @param int $groupID 流程ID
|
|
* @param string $key 模块标识
|
|
* @param string $name 模块名称
|
|
* @param int $order 排序
|
|
* @return int
|
|
*/
|
|
protected function createProcessModule(int $groupID, string $key, string $name, int $order)
|
|
{
|
|
$module = new stdclass();
|
|
$module->root = $groupID;
|
|
$module->branch = '0';
|
|
$module->name = $name;
|
|
$module->grade = '1';
|
|
$module->order = $order;
|
|
$module->type = 'process';
|
|
$module->extra = $key;
|
|
|
|
$this->dao->insert(TABLE_MODULE)->data($module)->exec();
|
|
$moduleID = $this->dao->lastInsertID();
|
|
$this->dao->update(TABLE_MODULE)->set('path')->eq(",$moduleID,")->where('id')->eq($moduleID)->exec();
|
|
|
|
return $moduleID;
|
|
}
|
|
|
|
/**
|
|
* 处理需要复制过程和活动的流程。
|
|
* Handle need copy workflow group.
|
|
*
|
|
* @param object $group 流程对象
|
|
* @param int $groupID 流程ID
|
|
* @param array $classifyModule 分类模块数组
|
|
*/
|
|
protected function handleNeedCopyWorkflowGroup(object $group, int $groupID, array $classifyModule)
|
|
{
|
|
$projectIdList = $this->dao->select('id')->from(TABLE_PROJECT)->where('workflowGroup')->eq($group->id)->fetchPairs();
|
|
$processList = $this->dao->select('*')->from(TABLE_PROCESS)->where('model')->eq($group->projectModel)->andWhere('deleted')->eq('0')->fetchAll('id');
|
|
$activityGroup = $this->dao->select('*')->from(TABLE_ACTIVITY)->where('process')->in(array_keys($processList))->andWhere('deleted')->eq('0')->fetchGroup('process', 'id');
|
|
$outputGroup = $this->dao->select('t1.*')->from(TABLE_ZOUTPUT)
|
|
->alias('t1')->leftJoin(TABLE_ACTIVITY)
|
|
->alias('t2')->on('t1.activity = t2.id')
|
|
->where('t2.process')->in(array_keys($processList))
|
|
->andWhere('t1.deleted')->eq('0')
|
|
->fetchGroup('activity', 'id');
|
|
|
|
foreach($processList as $process)
|
|
{
|
|
$this->copyProcessWithActivities($process, $groupID, $activityGroup, $outputGroup, $projectIdList);
|
|
}
|
|
|
|
$classifyModule[$groupID] = $this->migrateClassifyToModule($group, $groupID);
|
|
|
|
return $classifyModule;
|
|
}
|
|
|
|
/**
|
|
* 复制过程及其活动。
|
|
* Copy process and activities.
|
|
*
|
|
* @param object $process 过程对象
|
|
* @param int $groupID 流程ID
|
|
* @param array $activityGroup 活动分组
|
|
* @param array $outputGroup 文档分组
|
|
* @param array $projectIdList 项目ID列表
|
|
*/
|
|
protected function copyProcessWithActivities(object $process, int $groupID, array $activityGroup, array $outputGroup, array $projectIdList)
|
|
{
|
|
$activityList = zget($activityGroup, $process->id, array());
|
|
unset($process->id);
|
|
$process->workflowGroup = $groupID;
|
|
$process->model = '';
|
|
$process->editedBy = '';
|
|
$process->editedDate = null;
|
|
$process->assignedDate = null;
|
|
$this->dao->insert(TABLE_PROCESS)->data($process)->exec();
|
|
$processID = $this->dao->lastInsertID();
|
|
|
|
foreach($activityList as $activity)
|
|
{
|
|
$this->copyActivity($activity, $processID, $groupID, $outputGroup, $projectIdList);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 复制活动。
|
|
* Copy activity.
|
|
*
|
|
* @param object $activity 活动对象
|
|
* @param int $processID 过程ID
|
|
* @param int $groupID 流程ID
|
|
* @param array $outputGroup 文档分组
|
|
* @param array $projectIdList 项目ID列表
|
|
*/
|
|
protected function copyActivity(object $activity, int $processID, int $groupID, array $outputGroup, array $projectIdList)
|
|
{
|
|
$outputList = zget($outputGroup, $activity->id, array());
|
|
|
|
$oldActivityID = $activity->id;
|
|
unset($activity->id);
|
|
|
|
$activity->process = $processID;
|
|
$activity->optional = !empty($activity->optional) ? $activity->optional : 'no';
|
|
$activity->workflowGroup = $groupID;
|
|
$activity->editedBy = '';
|
|
$activity->editedDate = null;
|
|
$activity->assignedDate = null;
|
|
$this->dao->insert(TABLE_ACTIVITY)->data($activity)->exec();
|
|
|
|
$newActivityID = $this->dao->lastInsertID();
|
|
|
|
$this->dao->update(TABLE_AUDITPLAN)->set('objectID')->eq($newActivityID)->where('objectID')->eq($oldActivityID)->andWhere('objectType')->eq('activity')->andWhere('project')->in($projectIdList)->exec();
|
|
$this->dao->update(TABLE_AUDITCL)->set('objectID')->eq($newActivityID)->where('objectID')->eq($oldActivityID)->andWhere('workflowGroup')->eq($groupID)->andWhere('objectType')->eq('activity')->exec();
|
|
$this->dao->update(TABLE_PROGRAMACTIVITY)->set('activity')->eq($newActivityID)->where('activity')->eq($oldActivityID)->andWhere('project')->in($projectIdList)->exec();
|
|
|
|
$idMap = array();
|
|
foreach($outputList as $output)
|
|
{
|
|
$oldID = $output->id;
|
|
unset($output->id);
|
|
$output->activity = $newActivityID;
|
|
$output->editedBy = '';
|
|
$output->editedDate = null;
|
|
$this->dao->insert(TABLE_ZOUTPUT)->data($output)->exec();
|
|
$newOutputID = $this->dao->lastInsertID();
|
|
|
|
$idMap[$oldID] = $newOutputID;
|
|
}
|
|
|
|
foreach($idMap as $oldID => $newOutputID)
|
|
{
|
|
$this->dao->update(TABLE_AUDITCL)->set('objectID')->eq($newOutputID)->where('objectID')->eq($oldID)->andWhere('workflowGroup')->eq($groupID)->andWhere('objectType')->eq('zoutput')->exec();
|
|
$this->dao->update(TABLE_AUDITPLAN)->set('objectID')->eq($newOutputID)->where('objectID')->eq($oldID)->andWhere('objectType')->eq('zoutput')->andWhere('project')->in($projectIdList)->exec();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 将过程文档迁移到交付物。
|
|
* Migrate process output to deliverable.
|
|
*
|
|
* @param object $group
|
|
* @return void
|
|
*/
|
|
public function migrateOutputToDeliverable(object $group): void
|
|
{
|
|
$outputList = $this->dao->select('t1.*')->from(TABLE_ZOUTPUT)
|
|
->alias('t1')->leftJoin(TABLE_ACTIVITY)
|
|
->alias('t2')->on('t1.activity = t2.id')
|
|
->where('t2.workflowGroup')->eq($group->id)
|
|
->andWhere('t1.deleted')->eq('0')
|
|
->fetchAll('id');
|
|
|
|
if(empty($outputList)) return;
|
|
|
|
$otherModule = $this->dao->select('id')->from(TABLE_MODULE)->where('root')->eq($group->id)->andWhere('type')->eq('deliverable')->andWhere('deleted')->eq('0')->andWhere('extra')->eq('other')->fetch('id');
|
|
|
|
$deliverable = new stdclass();
|
|
$deliverable->template = '[]';
|
|
$deliverable->status = 'hidden';
|
|
$deliverable->workflowGroup = $group->id;
|
|
$deliverable->module = $otherModule;
|
|
$deliverable->builtin = 1;
|
|
$deliverable->deleted = '1';
|
|
|
|
$idMap = array();
|
|
foreach($outputList as $output)
|
|
{
|
|
$deliverable->name = $output->name;
|
|
$deliverable->activity = $output->activity;
|
|
$deliverable->trimmable = $output->optional == 'yes' ? '1' : '0';
|
|
|
|
$this->dao->insert(TABLE_DELIVERABLE)->data($deliverable)->exec();
|
|
$deliverableID = $this->dao->lastInsertID();
|
|
|
|
$idMap[$output->id] = $deliverableID;
|
|
}
|
|
|
|
$projectIdList = $this->dao->select('id')->from(TABLE_PROJECT)->where('workflowGroup')->eq($group->id)->fetchPairs();
|
|
|
|
$projectOutputList = $this->dao->select('id,output')->from(TABLE_PROGRAMOUTPUT)->where('project')->in($projectIdList)->andWhere('output')->in(array_keys($idMap))->fetchPairs();
|
|
foreach($projectOutputList as $id => $outputID)
|
|
{
|
|
$newID = $idMap[$outputID];
|
|
$this->dao->update(TABLE_PROGRAMOUTPUT)->set('output')->eq($newID)->where('id')->eq($id)->exec();
|
|
}
|
|
|
|
$auditplans = $this->dao->select('id,objectID')->from(TABLE_AUDITPLAN)
|
|
->where('objectType')->eq('zoutput')
|
|
->andWhere('objectID')->in(array_keys($idMap))
|
|
->andWhere('project')->in($projectIdList)
|
|
->fetchPairs();
|
|
|
|
foreach($auditplans as $id => $objectID)
|
|
{
|
|
$newID = $idMap[$objectID];
|
|
$this->dao->update(TABLE_AUDITPLAN)->set('objectID')->eq($newID)->where('id')->eq($id)->exec();
|
|
}
|
|
|
|
$auditcls = $this->dao->select('id, objectID')->from(TABLE_AUDITCL)
|
|
->where('objectType')->eq('zoutput')
|
|
->andWhere('workflowGroup')->eq($group->id)
|
|
->andWhere('objectID')->in(array_keys($outputList))
|
|
->andWhere('deleted')->eq('0')
|
|
->fetchPairs();
|
|
|
|
foreach($auditcls as $id => $objectID)
|
|
{
|
|
$newID = $idMap[$objectID];
|
|
$this->dao->update(TABLE_AUDITCL)->set('objectID')->eq($newID)->where('id')->eq($id)->exec();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新过程的模块分类。
|
|
* Update process modules.
|
|
*
|
|
* @param array $classifyModule
|
|
*/
|
|
protected function updateProcessModules(array $classifyModule)
|
|
{
|
|
foreach($classifyModule as $groupID => $modules)
|
|
{
|
|
foreach($modules as $key => $moduleID)
|
|
{
|
|
$this->dao->update(TABLE_PROCESS)->set('module')->eq($moduleID)->where('workflowGroup')->eq($groupID)->andWhere('type')->eq($key)->exec();
|
|
}
|
|
}
|
|
}
|
|
}
|