* adjust code for storyModel getProductStories method.

This commit is contained in:
wangyidong
2023-05-10 19:10:13 +08:00
parent 5db73bc70d
commit 97287ca50b
3 changed files with 164 additions and 153 deletions
+44 -120
View File
@@ -98,22 +98,23 @@ class storyModel extends model
/**
* Get stories by idList.
*
* @param int|array|string $storyIdList
* @param string $type requirement|story
* @param string $mode all
* @param array|string $storyIdList
* @param string $type requirement|story
* @param string $mode all
* @access public
* @return array
*/
public function getByList($storyIdList = 0, $type = 'story', $mode = '')
public function getByList(array|string $storyIdList, string $type = 'story', string $mode = ''): array
{
if(empty($storyIdList)) return array();
return $this->dao->select('t1.*, t2.spec, t2.verify, t3.name as productTitle, t3.deleted as productDeleted')
->from(TABLE_STORY)->alias('t1')
->leftJoin(TABLE_STORYSPEC)->alias('t2')->on('t1.id=t2.story')
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product=t3.id')
->where('t1.version=t2.version')
->andWhere('t1.id')->in($storyIdList)
->andWhere('t1.type')->eq($type)
->beginIF($mode != 'all')->andWhere('t1.deleted')->eq(0)->fi()
->beginIF($storyIdList)->andWhere('t1.id')->in($storyIdList)->fi()
->beginIF(!$storyIdList)->andWhere('t1.type')->eq($type)->fi()
->fetchAll('id');
}
@@ -2961,57 +2962,26 @@ class storyModel extends model
/**
* Get stories list of a product.
*
* @param int $productID
* @param int $branch
* @param array|string $moduleIdList
* @param string $status
* @param string $type requirement|story
* @param string $orderBy
* @param array|string $excludeStories
* @param object $pager
* @param bool $hasParent
* @param string|int $productID
* @param array|string|int $branch
* @param array|string $moduleIdList
* @param string $status
* @param string $type requirement|story
* @param string $orderBy
* @param array|string $excludeStories
* @param object|null $pager
* @param bool $hasParent
*
* @access public
* @return array
*/
public function getProductStories($productID = 0, $branch = 0, $moduleIdList = 0, $status = 'all', $type = 'story', $orderBy = 'id_desc', $hasParent = true, $excludeStories = '', $pager = null)
public function getProductStories(string|int $productID = 0, array|string|int $branch = 0, array|string $moduleIdList = '', string $status = 'all', string $type = 'story', string $orderBy = 'id_desc', bool $hasParent = true, array|string $excludeStories = '', object|null $pager = null): array
{
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getStories();
$stories = array();
$branchProducts = array();
$normalProducts = array();
$productList = $this->dao->select('*')->from(TABLE_PRODUCT)->where('id')->in($productID)->fetchAll('id');
foreach($productList as $product)
{
if($product->type != 'normal')
{
$branchProducts[$product->id] = $product->id;
continue;
}
$normalProducts[$product->id] = $product->id;
}
$productQuery = '(';
if(!empty($normalProducts)) $productQuery .= '`product` ' . helper::dbIN(array_keys($normalProducts));
if(!empty($branchProducts))
{
if(!empty($normalProducts)) $productQuery .= " OR ";
$productQuery .= "(`product` " . helper::dbIN(array_keys($branchProducts));
if($branch !== 'all')
{
if(is_array($branch)) $branch = join(',', $branch);
$productQuery .= " AND `branch` " . helper::dbIN($branch);
}
$productQuery .= ')';
}
if(empty($normalProducts) and empty($branchProducts)) $productQuery .= '1 = 1';
$productQuery .= ') ';
$stories = $this->dao->select("*, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder")->from(TABLE_STORY)
->where('product')->in($productID)
$productQuery = $this->storyTao->buildProductsCondition($productID, $branch);
$stories = $this->dao->select("*, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder")->from(TABLE_STORY)
->where('deleted')->eq(0)
->andWhere($productQuery)
->beginIF(!$hasParent)->andWhere("parent")->ge(0)->fi()
->beginIF(!empty($moduleIdList))->andWhere('module')->in($moduleIdList)->fi()
@@ -3019,12 +2989,11 @@ class storyModel extends model
->beginIF($status and $status != 'all')->andWhere('status')->in($status)->fi()
->andWhere('vision')->eq($this->config->vision)
->andWhere('type')->eq($type)
->andWhere('deleted')->eq(0)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
return $this->mergePlanTitle($productID, $stories, $branch, $type);
return $this->mergePlanTitle($productID, $stories, $type);
}
/**
@@ -3245,7 +3214,7 @@ class storyModel extends model
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
return $this->mergePlanTitle($productID, $stories, $branch, $type);
return $this->mergePlanTitle($productID, $stories, $type);
}
/**
@@ -3274,7 +3243,7 @@ class storyModel extends model
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
return $this->mergePlanTitle($productID, $stories, $branch, $type);
return $this->mergePlanTitle($productID, $stories, $type);
}
/**
@@ -3643,7 +3612,7 @@ class storyModel extends model
}
$this->dao->sqlobj->sql = $query;
return $this->mergePlanTitle($productID, $stories, $branch, $storyType);
return $this->mergePlanTitle($productID, $stories, $storyType);
}
/**
@@ -3841,7 +3810,7 @@ class storyModel extends model
$productIdList = array();
foreach($stories as $story) $productIdList[$story->product] = $story->product;
return $this->mergePlanTitle($productIdList, $stories, 0, $storyType);
return $this->mergePlanTitle($productIdList, $stories, $storyType);
}
/**
@@ -4838,83 +4807,38 @@ class storyModel extends model
* @access public
* @return array
*/
public function mergePlanTitle($productID, $stories, $branch = 0, $type = 'story')
public function mergePlanTitle(string|int $productID, array $stories, string $type = 'story'): array
{
$query = $this->dao->get();
if(is_array($branch))
$rawQuery = $this->dao->get();
/* Get plans. */
$plans = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)->Where('deleted')->eq(0)->andWhere('product')->in($productID)->fetchPairs('id', 'title');
/* Get parent stories and children. */
$stories = $this->storyTao->mergeChildren($stories, $type);
$parents = $this->storyTao->extractParents($stories);
if($parents)
{
unset($branch[0]);
$branch = join(',', $branch);
if($branch) $branch = "0,$branch";
$parents = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($parents)->andWhere('deleted')->eq(0)->fetchAll('id');
$children = $this->dao->select('id,title')->from(TABLE_STORY)->where('parent')->in($parents)->andWhere('deleted')->eq(0)->fetchGroup('parent', 'id');
}
$plans = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)
->Where('deleted')->eq(0)
->beginIF($productID)->andWhere('product')->in($productID)->fi()
->fetchPairs('id', 'title');
/* For requirement children. */
if($type == 'requirement')
{
$relations = $this->dao->select('DISTINCT AID, BID')->from(TABLE_RELATION)
->where('AType')->eq('requirement')
->andWhere('BType')->eq('story')
->andWhere('relation')->eq('subdivideinto')
->andWhere('AID')->in(array_keys($stories))
->fetchAll();
$group = array();
foreach($relations as $relation) $group[$relation->AID][] = $relation->BID;
foreach($stories as $story)
{
if(!isset($group[$story->id])) continue;
$story->children = $this->getByList($group[$story->id]);
/* export requirement linkstories. */
foreach($story->children as $child) $story->linkStories .= $child->title . ',';
}
}
$parents = array();
$tmpStories = array();
$childStories = array();
foreach($stories as $story)
{
$tmpStories[$story->id] = $story;
if($story->parent > 0) $parents[$story->parent] = $story->parent;
}
$parents = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($parents)->fetchAll('id');
foreach($stories as $storyID => $story)
{
/* export story linkstories. */
if($story->parent == -1)
{
$childrenTitle = $this->dao->select('title')->from(TABLE_STORY)->where('parent')->eq($story->id)->fetchAll();
$childrenTitle = array_column($childrenTitle, 'title');
$story->linkStories = implode(',', $childrenTitle);
}
/* Export story linkstories. */
if(isset($children[$story->id])) $story->linkStories = implode(',', array_column($children[$story->id], 'title'));
if($story->parent > 0)
{
if(isset($stories[$story->parent]))
{
$stories[$story->parent]->children[$story->id] = $story;
unset($stories[$storyID]);
}
else
{
$parent = $parents[$story->parent];
$story->parentName = $parent->title;
}
}
/* Merge parent story title. */
if($story->parent > 0 and isset($parents[$story->parent]) $story->parentName = $parents[$story->parent]->title;
/* Merge plan title. */
$story->planTitle = '';
$storyPlans = explode(',', trim($story->plan, ','));
$storyPlans = explode(',', trim($story->plan, ','));
foreach($storyPlans as $planID) $story->planTitle .= zget($plans, $planID, '') . ' ';
}
/* For save session query. */
$this->dao->sqlobj->sql = $query;
$this->dao->sqlobj->sql = $rawQuery;
return $stories;
}
+119 -32
View File
@@ -105,38 +105,6 @@ class storyTao extends storyModel
->fetchPairs('BID', 'BID');
}
/**
* 构建研发需求的跟踪矩阵信息。
* Build story track.
*
* @param object $story
* @param int $projectID
* @access protected
* @return object
*/
protected function buildStoryTrack(object $story, int $projectID = 0): object
{
/* 获取关联需求的用例、Bug、任务。 */
$track = new stdclass();
$track->parent = $story->parent;
$track->title = $story->title;
$track->cases = $this->loadModel('testcase')->getStoryCases($story->id);
$track->bugs = $this->loadModel('bug')->getStoryBugs($story->id);
$track->tasks = $this->loadModel('task')->getListByStory($story->id, 0, $projectID);
if($this->config->edition != 'max') return $track;
/* 获取关联需求的设计、关联版本库提交。 */
$track->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($story->id)->andWhere('deleted')->eq('0')->fetchAll('id');
$track->revisions = $this->dao->select('BID, t2.comment')->from(TABLE_RELATION)->alias('t1')
->leftjoin(TABLE_REPOHISTORY)->alias('t2')->on('t1.BID = t2.id')
->where('t1.AType')->eq('design')
->andWhere('t1.BType')->eq('commit')
->andWhere('t1.AID')->in(array_keys($track->designs))
->fetchPairs();
return $track;
}
/**
* 获取用户需求细分的研发需求,或者研发需求关联的用户需求。
* Get associated requirements.
@@ -291,4 +259,123 @@ class storyTao extends storyModel
->groupBy('product')
->fetchPairs();
}
/**
* 构建研发需求的跟踪矩阵信息。
* Build story track.
*
* @param object $story
* @param int $projectID
* @access protected
* @return object
*/
protected function buildStoryTrack(object $story, int $projectID = 0): object
{
/* 获取关联需求的用例、Bug、任务。 */
$track = new stdclass();
$track->parent = $story->parent;
$track->title = $story->title;
$track->cases = $this->loadModel('testcase')->getStoryCases($story->id);
$track->bugs = $this->loadModel('bug')->getStoryBugs($story->id);
$track->tasks = $this->loadModel('task')->getListByStory($story->id, 0, $projectID);
if($this->config->edition != 'max') return $track;
/* 获取关联需求的设计、关联版本库提交。 */
$track->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($story->id)->andWhere('deleted')->eq('0')->fetchAll('id');
$track->revisions = $this->dao->select('BID, t2.comment')->from(TABLE_RELATION)->alias('t1')
->leftjoin(TABLE_REPOHISTORY)->alias('t2')->on('t1.BID = t2.id')
->where('t1.AType')->eq('design')
->andWhere('t1.BType')->eq('commit')
->andWhere('t1.AID')->in(array_keys($track->designs))
->fetchPairs();
return $track;
}
/**
* 根据产品 ID 列表和分支参数,构建查询条件。
* Build products condition.
*
* @param string|int $productIdList
* @param array|string|int $branch
* @access protected
* @return string
*/
protected function buildProductsCondition(string|int $productIdList, array|string|int $branch): string
{
/* 如果查询所有分支,直接用 idList 条件。 */
if(empty($productIdList)) return '1=1';
if($branch === 'all') return '`product` ' . helper::dbIN($productIdList);
/* 将产品分类为正常产品和多分支产品。 */
$branchProducts = array();
$normalProducts = array();
$productList = $this->dao->select('*')->from(TABLE_PRODUCT)->where('id')->in($productIdList)->fetchAll('id');
foreach($productList as $product)
{
if($product->type != 'normal') $branchProducts[$product->id] = $product->id;
if($product->type == 'normal') $normalProducts[$product->id] = $product->id;
}
/* 如果没有多分支产品,直接返回正常产品 ID 列表。*/
if(empty($branchProducts)) return '`product` ' . helper::dbIN($normalProducts);
/* 构造多分支产品和正常产品的复合条件。 */
$productQuery = "(`product` " . helper::dbIN($branchProducts) . " AND `branch` " . helper::dbIN($branch) . ')';
if(!empty($normalProducts)) $productQuery .= ' OR `product` ' . helper::dbIN($normalProducts);
return "({$productQuery}) ";
}
/**
* 将需求列表中的子需求合并到列表中的父需求下。
* Merge children to parent.
*
* @param array $stories
* @param string $type
* @access protected
* @return int[]
*/
protected function mergeChildren(array $stories, string $type = 'story'): array
{
/* For requirement children. */
$relationGroups = array();
if($type == 'requirement') $relationGroups = $this->storyTao->batchGetRelations(array_keys($stories), $type, array('*'));
foreach($stories as $storyID => $story)
{
/* Merge to parent and unset in list. */
if($story->parent > 0 and isset($stories[$story->parent]))
{
$stories[$story->parent]->children[$story->id] = $story;
unset($stories[$storyID]);
}
/* Merge subdivided stories for requirement. */
if(!empty($relationGroups[$story->id]))
{
$story->children = $relationGroups[$story->id];
$story->linkStories = implode(',', array_column($story->children, 'title'));
}
}
return $stories;
}
/**
* 提取需求列表中的父需求 ID 列表。
* Extract parents from stories.
*
* @param array $stories
* @access protected
* @return int[]
*/
protected function extractParents(array $stories): array
{
$parent = array_map(function($story)
{
if($story->parent == '-1') return $story->id;
if($story->parent > '0') return $story->parent;
return false;
}, $stories);
return array_values(array_unique(array_filter($parent)));
}
}
+1 -1
View File
@@ -33,4 +33,4 @@ r(count($tracks['noRequirement'][2]->cases)) && p() && e('4');
r($tracks['noRequirement'][2]->bugs) && p('1:title') && e('BUG1'); // 获取产品1的需求2的关联Bug名称
r($tracks['noRequirement'][2]->bugs) && p('101:title') && e('BUG101'); // 获取产品1的需求2的关联Bug名称
r($tracks['noRequirement'][2]->cases) && p('1:title') && e('这个是测试用例1'); // 获取产品1的需求2的关联Case名称
r($tracks['noRequirement'][2]->cases) && p('2:title') && e('这个是测试用例2'); // 获取产品1的需求2的关联Case名称
r($tracks['noRequirement'][2]->cases) && p('2:title') && e('这个是测试用例2'); // 获取产品1的需求2的关联Case名称