From 4f0b716a014cb2b90ede226ce01efc14f4ccf363 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Wed, 27 Sep 2023 15:00:42 +0800 Subject: [PATCH] * Rewrite story view page. Code for task #102973. --- framework/model.class.php | 1 + module/build/model.php | 5 +- module/build/test/model/getstorybuilds.php | 29 +++ module/common/model.php | 108 +---------- module/common/tao.php | 176 ++++++++++++++++++ .../common/test/model/getpreandnextobject.php | 36 ++++ module/common/test/model/removeduplicate.php | 2 +- .../common/test/tao/fetchpreandnextobject.php | 49 +++++ module/common/test/tao/getpreandnextsql.php | 31 +++ .../test/tao/querylistforpreandnext.php | 35 ++++ .../test/tao/searchpreandnextfromlist.php | 21 +++ module/release/model.php | 5 +- .../release/test/model/getstoryreleases.php | 27 +++ module/story/control.php | 50 +---- module/story/model.php | 2 +- module/story/test/model/mergereviewer.php | 53 ++++-- module/story/zen.php | 52 ++++++ 17 files changed, 510 insertions(+), 172 deletions(-) create mode 100644 module/build/test/model/getstorybuilds.php create mode 100644 module/common/tao.php create mode 100644 module/common/test/model/getpreandnextobject.php create mode 100644 module/common/test/tao/fetchpreandnextobject.php create mode 100644 module/common/test/tao/getpreandnextsql.php create mode 100644 module/common/test/tao/querylistforpreandnext.php create mode 100644 module/common/test/tao/searchpreandnextfromlist.php create mode 100644 module/release/test/model/getstoryreleases.php diff --git a/framework/model.class.php b/framework/model.class.php index 9bb6dd15d1..d8db052415 100644 --- a/framework/model.class.php +++ b/framework/model.class.php @@ -234,6 +234,7 @@ class model extends baseModel */ public function fetchByID(int $objectID, string $moduleName = ''): object|bool { + if(empty($objectID)) return false; if(empty($moduleName)) $moduleName = $this->getModuleName(); $table = $this->config->objectTables[$moduleName]; diff --git a/module/build/model.php b/module/build/model.php index e2957fab74..d6942b7727 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -247,11 +247,12 @@ class buildModel extends model * @access public * @return array */ - public function getStoryBuilds($storyID) + public function getStoryBuilds(int $storyID): array { + if(empty($storyID)) return array(); return $this->dao->select('*')->from(TABLE_BUILD) ->where('deleted')->eq(0) - ->andWhere("CONCAT(stories, ',')")->like("%,$storyID,%") + ->andWhere("CONCAT(',', stories, ',')")->like("%,$storyID,%") ->orderBy('id_desc') ->fetchAll('id'); } diff --git a/module/build/test/model/getstorybuilds.php b/module/build/test/model/getstorybuilds.php new file mode 100644 index 0000000000..50a7d719a7 --- /dev/null +++ b/module/build/test/model/getstorybuilds.php @@ -0,0 +1,29 @@ +#!/usr/bin/env php +builds->range('``'); +$build->stories->range('1-20{2}'); +$build->createdBy->range('admin'); +$build->createdDate->range('`' . date('Y-m-d H:i:s') . '`'); +$build->gen(20); + +/** + +title=测试 buildModel->getStoryBuilds(); +cid=1 +pid=1 + +项目版本查询 >> 项目版本版本7 +执行版本查询 >> 执行版本版本17 +无id查询 >> 0 +图片字段传字符串测试 >> 17 + +*/ + +global $tester; +$build = $tester->loadModel('build'); +r(count($build->getStoryBuilds(1))) && p() && e('2'); //项目版本查询 diff --git a/module/common/model.php b/module/common/model.php index c75e0dc6ea..57c3ac2a50 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -2140,14 +2140,13 @@ EOF; /** * Get the previous and next object. * - * @param string $type story|task|bug|case + * @param string $type story|task|bug|case * @param int $objectID * @access public * @return object */ - public function getPreAndNextObject($type, $objectID) + public function getPreAndNextObject(string $type, int $objectID): object { - /* Get SQL. */ $queryCondition = $type . 'QueryCondition'; $typeOnlyCondition = $type . 'OnlyCondition'; $queryCondition = $this->session->$queryCondition; @@ -2157,105 +2156,10 @@ EOF; $preAndNextObject->next = ''; if(empty($queryCondition)) return $preAndNextObject; - $table = $this->config->objectTables[$type]; - $orderBy = $type . 'OrderBy'; - $orderBy = $this->session->$orderBy; - $select = ''; - if($this->session->$typeOnlyCondition) - { - if(strpos($orderBy, 'priOrder') !== false) $select .= ", IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder"; - if(strpos($orderBy, 'severityOrder') !== false) $select .= ", IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder"; - $queryCondition = str_replace('t4.status', 'status', $queryCondition); - - $sql = $this->dao->select("*$select")->from($table) - ->where($queryCondition) - ->beginIF($orderBy != false)->orderBy($orderBy)->fi() - ->get(); - } - else - { - $sql = $queryCondition . (empty($orderBy) ? '' : " ORDER BY $orderBy"); - } - - /* Get objectIDList. */ - $objectIdListKey = $type . 'BrowseList'; - $existsObjectList = $this->session->$objectIdListKey; - if(empty($existsObjectList) or $existsObjectList['sql'] != $sql) - { - $queryObjects = $this->dao->query($sql); - $objectList = array(); - $key = 'id'; - while($queryObjects && $object = $queryObjects->fetch()) - { - if(!$this->session->$typeOnlyCondition and $type == 'testcase' and isset($object->case)) $key = 'case'; - $id = $object->$key; - $objectList[$id] = $id; - } - - $this->session->set($objectIdListKey, array('sql' => $sql, 'idkey' => $key, 'objectList' => $objectList), $this->app->tab); - $existsObjectList = $this->session->$objectIdListKey; - } - - $preObj = false; - if(isset($existsObjectList['objectList'])) - { - foreach($existsObjectList['objectList'] as $id) - { - /* Get next object. */ - if($preObj === true) - { - $preAndNextObject->next = $id; - break; - } - - /* Get pre object. */ - if($id == $objectID) - { - if($preObj) $preAndNextObject->pre = $preObj; - $preObj = true; - } - if($preObj !== true) $preObj = $id; - } - - if(empty($queryCondition) or $this->session->$typeOnlyCondition) - { - if(!empty($preAndNextObject->pre)) $preAndNextObject->pre = $this->dao->select('*')->from($table)->where('id')->eq($preAndNextObject->pre)->fetch(); - if(!empty($preAndNextObject->next)) $preAndNextObject->next = $this->dao->select('*')->from($table)->where('id')->eq($preAndNextObject->next)->fetch(); - } - else - { - $isObject = false; - $objects = array(); - $key = $existsObjectList['idkey']; - $queryObjects = $this->dao->query($existsObjectList['sql']); - while($object = $queryObjects->fetch()) - { - $objects[$object->$key] = $object; - if(!empty($preAndNextObject->pre) and is_numeric($preAndNextObject->pre) and $object->$key == $preAndNextObject->pre) $preAndNextObject->pre = $object; - if(!empty($preAndNextObject->next) and is_numeric($preAndNextObject->next) and $object->$key == $preAndNextObject->next) $preAndNextObject->next = $object; - if((empty($preAndNextObject->pre) or is_object($preAndNextObject->pre)) and (empty($preAndNextObject->next) or is_object($preAndNextObject->next))) - { - $isObject = true; - break; - } - } - - /* If the pre object or next object is number type, then continue to find the pre or next. */ - if(!$isObject) - { - $objectIdList = array_keys($objects); - $objectIdIndex = array_search($objectID, $objectIdList); - if(is_numeric($preAndNextObject->pre)) - { - $preAndNextObject->pre = $objectIdIndex - 1 >= 0 ? $objects[$objectIdList[$objectIdIndex - 1]] : ''; - } - if(is_numeric($preAndNextObject->next)) - { - $preAndNextObject->next = $objectIdIndex + 1 < count($objectIdList) ? $objects[$objectIdList[$objectIdIndex + 1]] : ''; - } - } - } - } + $sql = $this->commonTao->getPreAndNextSQL($type); + $objectList = $this->commonTao->queryListForPreAndNext($type, $sql); + $preAndNextObject = $this->commonTao->searchPreAndNextFromList($objectID, $objectList); + $preAndNextObject = $this->commonTao->fetchPreAndNextObject($type, $objectID, $preAndNextObject); return $preAndNextObject; } diff --git a/module/common/tao.php b/module/common/tao.php new file mode 100644 index 0000000000..55662a6dc2 --- /dev/null +++ b/module/common/tao.php @@ -0,0 +1,176 @@ + + * @package common + * @link https://www.zentao.net + */ +class commonTao extends commonModel +{ + /** + * Get SQL for preAndNext. + * + * @param string $type + * @access protected + * @return string + */ + protected function getPreAndNextSQL(string $type): string + { + $queryCondition = $type . 'QueryCondition'; + $typeOnlyCondition = $type . 'OnlyCondition'; + $queryCondition = $this->session->$queryCondition; + $table = zget($this->config->objectTables, $type, ''); + if(empty($table)) return ''; + + $orderBy = $type . 'OrderBy'; + $orderBy = $this->session->$orderBy; + $select = ''; + if($this->session->$typeOnlyCondition) + { + if($orderBy and str_contains($orderBy, 'priOrder')) $select .= ", IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder"; + if($orderBy and str_contains($orderBy, 'severityOrder')) $select .= ", IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder"; + $queryCondition = str_replace('t4.status', 'status', $queryCondition); + + $sql = $this->dao->select("*$select")->from($table) + ->where($queryCondition) + ->beginIF($orderBy != false)->orderBy($orderBy)->fi() + ->get(); + } + else + { + $sql = $queryCondition . (empty($orderBy) ? '' : " ORDER BY $orderBy"); + } + + return $sql; + } + + /** + * Query list for preAndNext. + * + * @param string $type + * @param string $sql + * @access protected + * @return array + */ + protected function queryListForPreAndNext(string $type, string $sql): array + { + $objectIdListKey = strtolower($type . $this->app->getModuleName() . $this->app->getMethodName()) . 'BrowseList'; + $existsObjectList = $this->session->$objectIdListKey; + if(empty($existsObjectList) or trim($existsObjectList['sql']) != trim($sql)) + { + $queryObjects = $this->dao->query($sql); + $objectList = array(); + $key = 'id'; + if($queryObjects) + { + while($object = $queryObjects->fetch()) + { + if(!$this->session->$typeOnlyCondition and $type == 'testcase' and isset($object->case)) $key = 'case'; + $id = $object->$key; + $objectList[$id] = $id; + } + } + + $this->session->set($objectIdListKey, array('sql' => $sql, 'idkey' => $key, 'objectList' => $objectList), $this->app->tab); + $existsObjectList = $this->session->$objectIdListKey; + } + + return $existsObjectList; + } + + /** + * Search preAndNext from list. + * + * @param int $objectID + * @param array $objectList + * @access protected + * @return object + */ + protected function searchPreAndNextFromList(int $objectID, array $objectList): object + { + $preAndNextObject = new stdClass(); + $preAndNextObject->pre = ''; + $preAndNextObject->next = ''; + if(!isset($objectList['objectList'])) return $preAndNextObject; + + $preObj = false; + foreach($objectList['objectList'] as $id) + { + /* Get next object. */ + if($preObj === true) + { + $preAndNextObject->next = $id; + break; + } + + /* Get pre object. */ + if($id == $objectID) + { + if($preObj) $preAndNextObject->pre = $preObj; + $preObj = true; + } + if($preObj !== true) $preObj = $id; + } + return $preAndNextObject; + } + + /** + * Fetch preAndNextObject. + * + * @param string $type + * @param int $objectID + * @param object $preAndNextObject + * @access protected + * @return object + */ + protected function fetchPreAndNextObject(string $type, int $objectID, object $preAndNextObject): object + { + $queryCondition = $type . 'QueryCondition'; + $typeOnlyCondition = $type . 'OnlyCondition'; + $objectIdListKey = strtolower($type . $this->app->getModuleName() . $this->app->getMethodName()) . 'BrowseList'; + $queryCondition = $this->session->$queryCondition; + $existsObjectList = $this->session->$objectIdListKey; + $table = zget($this->config->objectTables, $type, ''); + + if(empty($table)) return $preAndNextObject; + if(empty($preAndNextObject->pre) and empty($preAndNextObject->next)) return $preAndNextObject; + if(empty($queryCondition) or $this->session->$typeOnlyCondition) + { + if(!empty($preAndNextObject->pre)) $preAndNextObject->pre = $this->dao->select('*')->from($table)->where('id')->eq($preAndNextObject->pre)->fetch(); + if(!empty($preAndNextObject->next)) $preAndNextObject->next = $this->dao->select('*')->from($table)->where('id')->eq($preAndNextObject->next)->fetch(); + return $preAndNextObject; + } + + $searched = false; + $objects = array(); + $key = $existsObjectList['idkey']; + $queryObjects = $this->dao->query($existsObjectList['sql']); + while($object = $queryObjects->fetch()) + { + $objects[$object->$key] = $object; + if(!empty($preAndNextObject->pre) and is_numeric($preAndNextObject->pre) and $object->$key == $preAndNextObject->pre) $preAndNextObject->pre = $object; + if(!empty($preAndNextObject->next) and is_numeric($preAndNextObject->next) and $object->$key == $preAndNextObject->next) $preAndNextObject->next = $object; + if((empty($preAndNextObject->pre) or is_object($preAndNextObject->pre)) and (empty($preAndNextObject->next) or is_object($preAndNextObject->next))) + { + $searched = true; + break; + } + } + + /* If the pre object or next object is number type, then continue to find the pre or next. */ + if(!$searched) + { + $objectIdList = array_keys($objects); + $objectIdIndex = (int)array_search($objectID, $objectIdList); + if(is_numeric($preAndNextObject->pre)) $preAndNextObject->pre = $objectIdIndex - 1 >= 0 ? $objects[$objectIdList[$objectIdIndex - 1]] : ''; + if(is_numeric($preAndNextObject->next)) $preAndNextObject->next = $objectIdIndex + 1 < count($objectIdList) ? $objects[$objectIdList[$objectIdIndex + 1]] : ''; + } + + return $preAndNextObject; + } +} + diff --git a/module/common/test/model/getpreandnextobject.php b/module/common/test/model/getpreandnextobject.php new file mode 100644 index 0000000000..311e4f271a --- /dev/null +++ b/module/common/test/model/getpreandnextobject.php @@ -0,0 +1,36 @@ +#!/usr/bin/env php +gen(10); + +/** + +title=测试 commonModel->getPreAndNextObject(); +cid=1 +pid=1 + +*/ + +global $tester; +$tester->loadModel('common'); + +r((array)$tester->common->getPreAndNextObject('', 3)) && p('pre,next') && e('~~,~~'); +r((array)$tester->common->getPreAndNextObject('story', 3)) && p('pre,next') && e('~~,~~'); + +$tester->common->app->moduleName = 'product'; +$tester->common->app->methodName = 'browse'; +$_SESSION['storyQueryCondition'] = 'id < 5'; +$_SESSION['storyOnlyCondition'] = true; +$_SESSION['storyOrderBy'] = 'id'; + +$preAndNextObject = $tester->common->getPreAndNextObject('story', 3); +r($preAndNextObject->pre) && p('id') && e('2'); +r($preAndNextObject->next) && p('id') && e('4'); + +$_SESSION['storyQueryCondition'] = 'SELECT * FROM `zt_story` WHERE id <= 4'; +$_SESSION['storyOnlyCondition'] = false; +$preAndNextObject = $tester->common->getPreAndNextObject('story', 3); +r($preAndNextObject->pre) && p('id') && e('2'); +r($preAndNextObject->next) && p('id') && e('4'); diff --git a/module/common/test/model/removeduplicate.php b/module/common/test/model/removeduplicate.php index 55e0eeadcc..6354e6a160 100644 --- a/module/common/test/model/removeduplicate.php +++ b/module/common/test/model/removeduplicate.php @@ -30,7 +30,7 @@ $doc->gen(1); /** -title=测试 storyModel->activate(); +title=测试 commonModel->removeDuplicate(); cid=1 pid=1 diff --git a/module/common/test/tao/fetchpreandnextobject.php b/module/common/test/tao/fetchpreandnextobject.php new file mode 100644 index 0000000000..950b02f010 --- /dev/null +++ b/module/common/test/tao/fetchpreandnextobject.php @@ -0,0 +1,49 @@ +#!/usr/bin/env php +gen(10); + +/** + +title=测试 commonTao->fetchPreAndNextObject(); +cid=1 +pid=1 + +*/ + +global $tester; +$tester->loadModel('common'); + +$_SESSION['storyQueryCondition'] = 'id < 40'; +$_SESSION['storyOnlyCondition'] = true; + +$preAndNextObject = new stdclass(); +$preAndNextObject->pre = ''; +$preAndNextObject->next = ''; +r((array)$tester->common->fetchPreAndNextObject('', 3, $preAndNextObject)) && p('pre,next') && e('~~,~~'); +r((array)$tester->common->fetchPreAndNextObject('story', 3, $preAndNextObject)) && p('pre,next') && e('~~,~~'); + +$preAndNextObject->pre = 2; +$preAndNextObject->next = 4; +$preAndNextObject = $tester->common->fetchPreAndNextObject('story', 3, $preAndNextObject); +r($preAndNextObject->pre) && p('id') && e('2'); +r($preAndNextObject->next) && p('id') && e('4'); + +$tester->common->app->moduleName = 'product'; +$tester->common->app->methodName = 'browse'; +$_SESSION['storyOnlyCondition'] = false; +$_SESSION['storyproductbrowseBrowseList'] = array('sql' => 'SELECT * FROM `zt_story` WHERE id <= 5', 'idkey' => 'id', 'objectList' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4)); + +$preAndNextObject->pre = 2; +$preAndNextObject->next = 4; +$preAndNextObject = $tester->common->fetchPreAndNextObject('story', 3, $preAndNextObject); +r($preAndNextObject->pre) && p('id') && e('2'); +r($preAndNextObject->next) && p('id') && e('4'); + +$preAndNextObject->pre = 0; +$preAndNextObject->next = 6; +$preAndNextObject = $tester->common->fetchPreAndNextObject('story', 3, $preAndNextObject); +r($preAndNextObject->pre) && p('id') && e('2'); +r($preAndNextObject->next) && p('id') && e('4'); diff --git a/module/common/test/tao/getpreandnextsql.php b/module/common/test/tao/getpreandnextsql.php new file mode 100644 index 0000000000..1d08f99cb1 --- /dev/null +++ b/module/common/test/tao/getpreandnextsql.php @@ -0,0 +1,31 @@ +#!/usr/bin/env php +getPreAndNextSQL(); +cid=1 +pid=1 + +*/ + +global $tester; +$tester->loadModel('common'); + +$_SESSION['storyQueryCondition'] = 'id < 40'; +$_SESSION['storyOnlyCondition'] = true; +r(trim($tester->common->getPreAndNextSQL('story'))) && p() && e('SELECT * FROM `zt_story` WHERE id < 40'); + +$_SESSION['storyOrderBy'] = 'id desc, priOrder, severityOrder'; +r(trim($tester->common->getPreAndNextSQL('story'))) && p() && e('SELECT *, IF(`pri` = 0, 256, `pri`) as priOrder, IF(`severity` = 0, 256, `severity`) as severityOrder FROM `zt_story` WHERE id < 40 ORDER BY `id` desc,`priOrder`,`severityOrder`'); + + +$_SESSION['storyQueryCondition'] = 'SELECT t1.* FROM `zt_story` AS t1 LEFT JOIN `zt_storyspec` AS t2 on t1.id=t2.story WHERE t1.id < 40 AND t1.version = t2.version'; +$_SESSION['storyOnlyCondition'] = false; +unset($_SESSION['storyOrderBy']); +r(trim($tester->common->getPreAndNextSQL('story'))) && p() && e('SELECT t1.* FROM `zt_story` AS t1 LEFT JOIN `zt_storyspec` AS t2 on t1.id=t2.story WHERE t1.id < 40 AND t1.version = t2.version'); + +$_SESSION['storyOrderBy'] = 't1.id desc'; +r(trim($tester->common->getPreAndNextSQL('story'))) && p() && e('SELECT t1.* FROM `zt_story` AS t1 LEFT JOIN `zt_storyspec` AS t2 on t1.id=t2.story WHERE t1.id < 40 AND t1.version = t2.version ORDER BY t1.id desc'); diff --git a/module/common/test/tao/querylistforpreandnext.php b/module/common/test/tao/querylistforpreandnext.php new file mode 100644 index 0000000000..d18d9b92c4 --- /dev/null +++ b/module/common/test/tao/querylistforpreandnext.php @@ -0,0 +1,35 @@ +#!/usr/bin/env php +gen(10); + +/** + +title=测试 commonTao->queryListForPreAndNext(); +cid=1 +pid=1 + +*/ + +global $tester; +$tester->loadModel('common'); + +$_SESSION['storyQueryCondition'] = 'id < 5'; +$_SESSION['storyOnlyCondition'] = true; +$sql = $tester->common->getPreAndNextSQL('story'); +$list = $tester->common->queryListForPreAndNext('story', $sql); +r(implode('|', $list['objectList'])) && p() && e('1|2|3|4'); + +$_SESSION['storyQueryCondition'] = 'id <= 5'; +$sql = $tester->common->getPreAndNextSQL('story'); +$list = $tester->common->queryListForPreAndNext('story', $sql); +r(implode('|', $list['objectList'])) && p() && e('1|2|3|4|5'); + +$tester->common->app->tab = 'my'; +$tester->common->app->moduleName = 'product'; +$tester->common->app->methodName = 'browse'; +$_SESSION['app-my']['storyproductbrowseBrowseList'] = array('sql' => 'SELECT * FROM `zt_story` WHERE id <= 5', 'idkey' => 'id', 'objectList' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4)); +$list = $tester->common->queryListForPreAndNext('story', $sql); +r(implode('|', $list['objectList'])) && p() && e('1|2|3|4'); diff --git a/module/common/test/tao/searchpreandnextfromlist.php b/module/common/test/tao/searchpreandnextfromlist.php new file mode 100644 index 0000000000..1fa95c49b1 --- /dev/null +++ b/module/common/test/tao/searchpreandnextfromlist.php @@ -0,0 +1,21 @@ +#!/usr/bin/env php +searchPreAndNextFromList(); +cid=1 +pid=1 + +*/ + +global $tester; +$tester->loadModel('common'); + +$objectList = array('sql' => 'SELECT * FROM `zt_story` WHERE id < 5', 'idkey' => 'id', 'objectList' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4)); + +r((array)$tester->common->searchPreAndNextFromList(0, array())) && p('pre,next') && e('~~,~~'); +r((array)$tester->common->searchPreAndNextFromList(3, array())) && p('pre,next') && e('~~,~~'); +r((array)$tester->common->searchPreAndNextFromList(3, $objectList)) && p('pre,next') && e('2,4'); diff --git a/module/release/model.php b/module/release/model.php index 17c2aab0a3..8a2358cd74 100644 --- a/module/release/model.php +++ b/module/release/model.php @@ -171,11 +171,12 @@ class releaseModel extends model * @access public * @return array */ - public function getStoryReleases($storyID) + public function getStoryReleases(int $storyID): array { + if(empty($storyID)) return array(); return $this->dao->select('*')->from(TABLE_RELEASE) ->where('deleted')->eq(0) - ->andWhere("CONCAT(stories, ',')")->like("%,$storyID,%") + ->andWhere("CONCAT(',', stories, ',')")->like("%,$storyID,%") ->orderBy('id_desc') ->fetchAll('id'); } diff --git a/module/release/test/model/getstoryreleases.php b/module/release/test/model/getstoryreleases.php new file mode 100644 index 0000000000..ebdb0a28f9 --- /dev/null +++ b/module/release/test/model/getstoryreleases.php @@ -0,0 +1,27 @@ +#!/usr/bin/env php +stories->range('1-20{2}'); +$build->createdBy->range('admin'); +$build->createdDate->range('`' . date('Y-m-d H:i:s') . '`'); +$build->gen(20); + +/** + +title=测试 buildModel->getStoryBuilds(); +cid=1 +pid=1 + +项目版本查询 >> 项目版本版本7 +执行版本查询 >> 执行版本版本17 +无id查询 >> 0 +图片字段传字符串测试 >> 17 + +*/ +global $tester; +$release = $tester->loadModel('release'); +r(count($release->getStoryReleases(1))) && p() && e('2'); //项目版本查询 diff --git a/module/story/control.php b/module/story/control.php index 02ee746a0a..ed33cc92f4 100755 --- a/module/story/control.php +++ b/module/story/control.php @@ -485,60 +485,16 @@ class story extends control $this->app->loadLang('bug'); $this->commonAction($storyID, $param); - - $bugs = $this->dao->select('id,title,status,pri,severity')->from(TABLE_BUG)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->fetchAll(); - $fromBug = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->eq($story->fromBug)->fetch(); - $cases = $this->dao->select('id,title,status,pri')->from(TABLE_CASE)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->fetchAll(); - $linkedMRs = $this->loadModel('mr')->getLinkedMRPairs($storyID, 'story'); - $linkedCommits = $this->loadModel('repo')->getCommitsByObject($storyID, 'story'); - $modulePath = $this->tree->getParents($story->module); - $storyModule = empty($story->module) ? '' : $this->tree->getById($story->module); - $linkedStories = isset($story->linkStoryTitles) ? array_keys($story->linkStoryTitles) : array(); - $storyProducts = $this->dao->select('id,product')->from(TABLE_STORY)->where('id')->in($linkedStories)->fetchPairs(); - - $this->view->hiddenPlan = false; - $this->view->hiddenURS = false; - if(!empty($product->shadow)) - { - $projectInfo = $this->dao->select('t2.model, t2.multiple')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t1.product')->eq($product->id) - ->andWhere('t2.type')->eq('project') - ->fetch(); - - if($projectInfo->model == 'waterfall') $this->view->hiddenPlan = true; - if($projectInfo->model == 'kanban') - { - $this->view->hiddenPlan = true; - $this->view->hiddenURS = true; - } - if(!$projectInfo->multiple) $this->view->hiddenPlan = true; - } + $this->storyZen->getLinkedObjects($story); + $this->storyZen->setHiddenFieldsForView($product); if($product->type != 'normal') $this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]); - $reviewers = $this->story->getReviewerPairs($storyID, $story->version); - $execution = empty($story->execution) ? array() : $this->dao->findById($story->execution)->from(TABLE_EXECUTION)->fetch(); - $project = $param ? $this->dao->findById($param)->from(TABLE_PROJECT)->fetch() : array(); - $this->view->title = "STORY #$story->id $story->title - $product->name"; $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id); - $this->view->twins = !empty($story->twins) ? $this->story->getByList($story->twins) : array(); - $this->view->bugs = $bugs; - $this->view->fromBug = $fromBug; - $this->view->cases = $cases; - $this->view->story = $story; - $this->view->linkedMRs = $linkedMRs; - $this->view->linkedCommits = $linkedCommits; $this->view->users = $this->user->getPairs('noletter'); - $this->view->reviewers = $reviewers; - $this->view->relations = $this->story->getStoryRelation($story->id, $story->type); $this->view->executions = $this->execution->getPairs(0, 'all', 'nocode'); - $this->view->execution = $execution; - $this->view->project = $project; - $this->view->storyModule = $storyModule; - $this->view->modulePath = $modulePath; - $this->view->storyProducts = $storyProducts; + $this->view->project = $this->project->fetchByID($param); $this->view->version = $version; $this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('story', $storyID); $this->view->builds = $this->loadModel('build')->getStoryBuilds($storyID); diff --git a/module/story/model.php b/module/story/model.php index 26ac222eba..42b7ca8950 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -3342,7 +3342,7 @@ class storyModel extends model * @access public * @return array|object */ - public function mergeReviewer($stories, $isObject = false) + public function mergeReviewer(object|array $stories, $isObject = false) { $rawQuery = $this->dao->get(); if($isObject) diff --git a/module/story/test/model/mergereviewer.php b/module/story/test/model/mergereviewer.php index dd658bc503..338646b89f 100755 --- a/module/story/test/model/mergereviewer.php +++ b/module/story/test/model/mergereviewer.php @@ -4,31 +4,50 @@ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/story.class.php'; su('admin'); +$story = zdTable('story'); +$story->product->range(1); +$story->plan->range('0,1,0{100}'); +$story->duplicateStory->range('0,4,0{100}'); +$story->linkStories->range('0,6,0{100}'); +$story->linkRequirements->range('3,0{100}'); +$story->childStories->range('0,8,0{100}'); +$story->toBug->range('0{9},1,0{100}'); +$story->parent->range('0{17},`-1`,0,18,0{100}'); +$story->twins->range('``{27},30,``,28'); +$story->version->range('1'); +$story->gen(30); + +$storyReview = zdTable('storyreview'); +$storyReview->story->range('1-30{3}'); +$storyReview->reviewer->range('admin,user1,user2'); +$storyReview->result->range('``{2}, pass'); +$storyReview->version->range('1'); +$storyReview->gen(90); + /** title=测试 storyModel->mergeReviewer(); cid=1 pid=1 -获取需求301的评审人 >> admin -获取需求301的待评审人 >> admin -获取产品76下的需求评审人 >> admin -获取产品76下的需求待评审人 >> admin -获取产品76下的需求评审人 >> admin -获取产品76下的需求待评审人 >> admin - */ global $tester; -$story = $tester->loadModel('story')->getById(301); -$story = $tester->story->mergeReviewer($story, true); +$story = $tester->loadModel('story')->getById(2); +$story = $tester->story->mergeReviewer($story, true); +r(implode('|', $story->reviewer)) && p() && e('admin|user1|user2'); // 获取需求2的评审人 +r(implode('|', $story->notReview)) && p() && e('admin|user1'); // 获取需求2的待评审人 -$stories = $tester->story->getProductStories(76); -$stories = $tester->story->mergeReviewer($stories); +$story = $tester->loadModel('story')->getById(18); +$story = $tester->story->mergeReviewer($story, true); +r(implode('|', $story->reviewer)) && p() && e('admin|user1|user2'); // 获取需求18的评审人 +r(implode('|', $story->notReview)) && p() && e('admin|user1'); // 获取需求18的待评审人 +r(implode('|', $story->children[20]->reviewer)) && p() && e('admin|user1|user2'); // 获取需求18子需求的评审人 +r(implode('|', $story->children[20]->notReview)) && p() && e('admin|user1'); // 获取需求18子需求的待评审人 -r($story) && p('reviewer:0') && e('admin'); // 获取需求301的评审人 -r($story) && p('notReview:0') && e('admin'); // 获取需求301的待评审人 -r($stories[302]->reviewer[0]) && p() && e('admin'); // 获取产品76下的需求评审人 -r($stories[302]->notReview[0]) && p() && e('admin'); // 获取产品76下的需求待评审人 -r($stories[304]->reviewer[0]) && p() && e('admin'); // 获取产品76下的需求评审人 -r($stories[304]->notReview[0]) && p() && e('admin'); // 获取产品76下的需求待评审人 \ No newline at end of file +$stories = $tester->story->mergeReviewer(array(18 => $story)); + +r(implode('|', $stories[18]->reviewer)) && p() && e('admin|user1|user2'); // 批量获取需求18的评审人 +r(implode('|', $stories[18]->notReview)) && p() && e('admin|user1'); // 批量获取需求18的待评审人 +r(implode('|', $stories[18]->children[20]->reviewer)) && p() && e('admin|user1|user2'); // 批量获取需求18子需求的评审人 +r(implode('|', $stories[18]->children[20]->notReview)) && p() && e('admin|user1'); // 批量获取需求18子需求的待评审人 diff --git a/module/story/zen.php b/module/story/zen.php index 3e300f8276..1f8cc25b1a 100644 --- a/module/story/zen.php +++ b/module/story/zen.php @@ -1704,4 +1704,56 @@ class storyZen extends story $story = $this->loadModel('file')->processImgURL($postData, $this->config->story->editor->activate['id'], $this->post->uid); return $story; } + + /** + * Get linked objects. e.g. bugs,cases,linkedMRs,linkedCommits,twins,reviewers,relations. + * + * @param object $story + * @access protected + * @return void + */ + protected function getLinkedObjects(object $story) + { + $linkedStories = isset($story->linkStoryTitles) ? array_keys($story->linkStoryTitles) : array(); + + $this->view->bugs = $this->dao->select('id,title,status,pri,severity')->from(TABLE_BUG)->where('story')->eq($story->id)->andWhere('deleted')->eq(0)->fetchAll(); + $this->view->fromBug = $story->fromBug ? $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->eq($story->fromBug)->fetch() : ''; + $this->view->cases = $this->dao->select('id,title,status,pri')->from(TABLE_CASE)->where('story')->eq($story->id)->andWhere('deleted')->eq(0)->fetchAll(); + $this->view->linkedMRs = $this->loadModel('mr')->getLinkedMRPairs($story->id, 'story'); + $this->view->linkedCommits = $this->loadModel('repo')->getCommitsByObject($story->id, 'story'); + $this->view->modulePath = $this->tree->getParents($story->module); + $this->view->storyModule = empty($story->module) ? '' : $this->tree->getById($story->module); + $this->view->storyProducts = $this->dao->select('id,product')->from(TABLE_STORY)->where('id')->in($linkedStories)->fetchPairs(); + $this->view->twins = !empty($story->twins) ? $this->story->getByList($story->twins) : array(); + $this->view->reviewers = $this->story->getReviewerPairs($story->id, $story->version); + $this->view->relations = $this->story->getStoryRelation($story->id, $story->type); + } + + /** + * Set hidden fields for view. like: hiddenPlan,hiddenURS. + * + * @param object $product + * @access protected + * @return void + */ + protected function setHiddenFieldsForView(object $product) + { + $this->view->hiddenPlan = false; + $this->view->hiddenURS = false; + if(empty($product->shadow)) return; + + $projectInfo = $this->dao->select('t2.model, t2.multiple')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.product')->eq($product->id) + ->andWhere('t2.type')->eq('project') + ->fetch(); + + if($projectInfo->model == 'waterfall') $this->view->hiddenPlan = true; + if($projectInfo->model == 'kanban') + { + $this->view->hiddenPlan = true; + $this->view->hiddenURS = true; + } + if(!$projectInfo->multiple) $this->view->hiddenPlan = true; + } }