* product: refactor browse function.

This commit is contained in:
chentao
2023-05-06 22:05:24 +08:00
parent ab2484c493
commit e4fac58baf
2 changed files with 445 additions and 204 deletions
+42 -204
View File
@@ -102,10 +102,10 @@ class product extends control
* Browse requirements list of product.
*
* @param int $productID
* @param int|stirng $branch
* @param int|stirng $branch all|''|0
* @param string $browseType
* @param int $param
* @param string $storyType requirement|story
* @param int $param Story Module ID
* @param string $storyType requirement|story
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
@@ -122,214 +122,50 @@ class product extends control
$recPerPage = (int)$recPerPage;
$pageID = (int)$pageID;
$projectID = (int)$projectID;
$productID = $this->app->tab != 'project' ? $this->product->saveVisitState($productID, $this->products) : $productID;
$product = $this->product->getById($productID);
if($product && !isset($this->products[$product->id])) $this->products[$product->id] = $product->name;
if($product and $product->type != 'normal')
{
$branchPairs = $this->loadModel('branch')->getPairs($productID, 'all');
$branch = ($this->cookie->preBranch !== '' and $branch === '' and isset($branchPairs[$this->cookie->preBranch])) ? $this->cookie->preBranch : $branch;
$branchID = $branch;
}
else
{
$branchID = $branch = 'all';
}
/* Set menu. */
if($this->app->tab == 'project')
{
$this->session->set('storyList', $this->app->getURI(true), 'project');
$this->loadModel('project')->setMenu($projectID);
}
else
{
$this->session->set('storyList', $this->app->getURI(true), 'product');
$this->session->set('productList', $this->app->getURI(true), 'product');
$this->product->setMenu($productID, $branch, 0, '', "storyType=$storyType");
}
/* Lower browse type. */
$browseType = strtolower($browseType);
/* Load datatable and execution. */
/* Pre process. */
$isProjectStory = $this->app->rawModule == 'projectstory';
$this->loadModel('datatable');
$this->loadModel('execution');
/* Set product, module and query. */
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
/* Generate data. */
$showModule = !empty($this->config->datatable->productBrowse->showModule) ? $this->config->datatable->productBrowse->showModule : '';
$productName = ($isProjectStory and empty($productID)) ? $this->lang->product->all : $this->products[$productID];
$productID = $this->app->tab != 'project' ? $this->product->saveVisitState($productID, $this->products) : $productID;
$product = $this->productZen->getBrowseProduct($productID);
$project = $this->loadModel('project')->getByID($projectID);
list($branch, $branchID) = $this->productZen->getBranchAndBranchID($product, $branch);
$orderBy = $orderBy ?? ($this->cookie->productStoryOrder ? $this->cookie->productStoryOrder : 'id_desc');
if($this->cookie->preProductID != $productID or $this->cookie->preBranch != $branch or $browseType == 'bybranch')
{
$_COOKIE['storyModule'] = 0;
setcookie('storyModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
/* ATTENTION: be careful to change the order of follow sentencies. */
$this->productZen->setMenu4Browse($projectID, $productID, $branch, $storyType);
$this->productZen->saveAndModifyCookie4Browse($productID, $branch, $param, $browseType, $orderBy);
if($browseType == 'bymodule' or $browseType == '')
{
setcookie('storyModule', (int)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
if($this->app->tab == 'project') setcookie('storyModuleParam', (int)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$_COOKIE['storyBranch'] = 'all';
setcookie('storyBranch', 'all', 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
if($browseType == '') setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
if($browseType == 'bybranch') setcookie('storyBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$cookieModule = $this->app->tab == 'project' ? $this->cookie->storyModuleParam : $this->cookie->storyModule;
$moduleID = 0;
if($browseType == 'bymodule') $moduleID = (int)$param;
elseif($browseType != 'bysearch' and $browseType != 'bybranch' and $cookieModule) $moduleID = $cookieModule;
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
/* Set moduleTree. */
$createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink';
if($browseType == '')
{
setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$browseType = 'unclosed';
}
else
{
$branch = $this->cookie->treeBranch;
}
$isProjectStory = $this->app->rawModule == 'projectstory';
/* If in project story and not chose product, get project story mdoules. */
if($isProjectStory and empty($productID))
{
$moduleTree = $this->tree->getProjectStoryTreeMenu($projectID, 0, array('treeModel', $createModuleLink));
}
else
{
$moduleTree = $this->tree->getTreeMenu($productID, 'story', $startModuleID = 0, array('treeModel', $createModuleLink), array('projectID' => $projectID, 'productID' => $productID), $branch, "&param=$param&storyType=$storyType");
}
if($browseType != 'bymodule' and $browseType != 'bybranch') $this->session->set('storyBrowseType', $browseType);
if(($browseType == 'bymodule' or $browseType == 'bybranch') and $this->session->storyBrowseType == 'bysearch') $this->session->set('storyBrowseType', 'unclosed');
/* Process the order by field. */
if(!$orderBy) $orderBy = $this->cookie->productStoryOrder ? $this->cookie->productStoryOrder : 'id_desc';
setcookie('productStoryOrder', $orderBy, 0, $this->config->webRoot, '', $this->config->cookieSecure, true);
/* Append id for secend sort. */
$sort = common::appendOrder($orderBy);
if(strpos($sort, 'pri_') !== false) $sort = str_replace('pri_', 'priOrder_', $sort);
/* Load pager. */
$this->app->loadClass('pager', $static = true);
if($this->app->getViewType() == 'xhtml') $recPerPage = 10;
$pager = new pager($recTotal, $recPerPage, $pageID);
/* Display of branch label. */
$showBranch = $this->loadModel('branch')->showBranch($productID);
/* Get stories. */
$projectProducts = array();
if($isProjectStory and $storyType == 'story')
{
$showBranch = $this->loadModel('branch')->showBranch($productID, 0, $projectID);
if(!empty($product)) $this->session->set('currentProductType', $product->type);
$this->products = $this->product->getProducts($projectID, 'all', '', false);
$projectProducts = $this->product->getProducts($projectID);
$productPlans = $this->execution->getPlans($projectProducts, 'skipParent,unexpired,noclosed', $projectID);
if($browseType == 'bybranch') $param = $branchID;
$stories = $this->story->getExecutionStories($projectID, $productID, $branchID, $sort, $browseType, $param, $storyType, '', $pager);
}
else
{
$stories = $this->product->getStories($productID, $branchID, $browseType, $queryID, $moduleID, $storyType, $sort, $pager);
}
$queryCondition = $this->story->dao->get();
/* Display status of branch. */
$branchOption = array();
$branchTagOption = array();
if(!$product and $isProjectStory)
{
/* Get branch display under multiple products. */
$branchOptions = array();
foreach($projectProducts as $projectProduct)
{
if($projectProduct and $projectProduct->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($projectProduct->id, $projectID, 'all');
foreach($branches as $branchInfo) $branchOptions[$projectProduct->id][$branchInfo->id] = $branchInfo->name;
}
}
$this->view->branchOptions = $branchOptions;
}
else
{
if($product and $product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
}
/* Generate data. */
$moduleID = $this->productZen->getModuleId4Browse($param, $browseType);
$moduleTree = $this->productZen->getModuleTree4BrowseTODO($projectID, $productID, $branch, $param, $storyType, $browseType);
$showBranch = $this->productZen->getShowBranch4Browse($projectID, $productID, $storyType, $isProjectStory);
$projectProducts = $this->productZen->getProjectProducts4Browse($projectID, $storyType, $isProjectStory);
$productPlans = $this->productZen->getProductPlans4Browse($projectProducts, $projectID, $storyType, $isProjectStory);
list($stories, $pager) = $this->productZen->getStoriesAndPager4Browse($projectID, $productID, $branchID, $moduleID, $param, $storyType, $browseType, $orderBy, $recTotal, $recPerPage, $pageID);
/* Process the sql, get the conditon partion, save it to session. */
$queryCondition = $this->story->dao->get();
$this->loadModel('common')->saveQueryCondition($queryCondition, 'story', (strpos('bysearch,reviewbyme,bymodule', $browseType) === false and !$isProjectStory));
if(!empty($stories)) $stories = $this->story->mergeReviewer($stories);
/* Collect story ID list. */
$storyIdList = $this->productZen->getStoryIdList($stories);
/* Get related tasks, bugs, cases count of each story. */
$storyIdList = array();
foreach($stories as $story)
{
$storyIdList[$story->id] = $story->id;
if(!empty($story->children))
{
foreach($story->children as $child) $storyIdList[$child->id] = $child->id;
}
}
$storyTasks = $this->loadModel('task')->getStoryTaskCounts($storyIdList);
$storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList);
$storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList);
/* Change for requirement story title. */
if($storyType == 'requirement')
{
$this->lang->story->title = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->title);
$this->lang->story->create = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->create);
$this->config->product->search['fields']['title'] = $this->lang->story->title;
unset($this->config->product->search['fields']['plan']);
unset($this->config->product->search['fields']['stage']);
}
$project = $this->loadModel('project')->getByID($projectID);
if(isset($project->hasProduct) && empty($project->hasProduct))
{
if($isProjectStory && !$productID && !empty($this->products)) $productID = key($this->products); // If toggle a project by the #swapper component on the story page of the projectstory module, the $productID may be empty. Make sure it has value.
unset($this->config->product->search['fields']['product']); // The none-product project don't need display the product in the search form.
if($project->model != 'scrum') unset($this->config->product->search['fields']['plan']); // The none-product and none-scrum project don't need display the plan in the search form.
}
/* Generate data. */
list($branchOpt, $branchTagOpt) = $this->productZen->getBranchAndTagOption4Browse($projectID, $product, $isProjectStory);
$branchOptions = (empty($product) && $isProjectStory) ? $this->productZen->getBranchOptions4Browse($projectProducts, $projectID) : array();
$storyTasks = $this->loadModel('task')->getStoryTaskCounts($storyIdList);
$storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList);
$storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList);
/* Build search form. */
$params = $isProjectStory ? "projectID=$projectID&" : '';
$actionURL = $this->createLink($this->app->rawModule, $this->app->rawMethod, $params . "productID=$productID&branch=$branch&browseType=bySearch&queryID=myQueryID&storyType=$storyType");
$this->config->product->search['onMenuBar'] = 'yes';
$this->product->buildSearchForm($productID, $this->products, $queryID, $actionURL, $branch, $projectID);
$showModule = !empty($this->config->datatable->productBrowse->showModule) ? $this->config->datatable->productBrowse->showModule : '';
$productName = ($isProjectStory and empty($productID)) ? $this->lang->product->all : $this->products[$productID];
$this->productZen->buildSearchForm4Browse($project, $projectID, $productID, $branch, $param, $storyType, $browseType, $isProjectStory);
/* Assign. */
$this->view->title = $productName . $this->lang->colon . ($storyType === 'story' ? $this->lang->product->browse : $this->lang->product->requirement);
@@ -341,7 +177,7 @@ class product extends control
$this->view->moduleID = $moduleID;
$this->view->stories = $stories;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, ($branch === 'all' or empty($branch)) ? '' : $branch, 'unexpired,noclosed', true);
$this->view->productPlans = isset($productPlans) ? array(0 => '') + $productPlans : array();
$this->view->productPlans = !empty($productPlans) ? array(0 => '') + $productPlans : array();
$this->view->summary = $this->product->summary($stories, $storyType);
$this->view->moduleTree = $moduleTree;
$this->view->parentModules = $this->tree->getParents($moduleID);
@@ -354,8 +190,9 @@ class product extends control
$this->view->moduleName = ($moduleID and $moduleID !== 'all') ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
$this->view->branch = $branch;
$this->view->branchID = $branchID;
$this->view->branchOption = $branchOption;
$this->view->branchTagOption = $branchTagOption;
$this->view->branchOptions = $branchOptions;
$this->view->branchOption = $branchOpt;
$this->view->branchTagOption = $branchTagOpt;
$this->view->showBranch = $showBranch;
$this->view->storyStages = $this->product->batchGetStoryStage($stories);
$this->view->setModule = true;
@@ -365,14 +202,14 @@ class product extends control
$this->view->param = $param;
$this->view->projectID = $projectID;
$this->view->products = $this->products;
$this->view->projectProducts = isset($projectProducts) ? $projectProducts : array();
$this->view->projectProducts = !empty($projectProducts) ? $projectProducts : array();
$this->view->storyType = $storyType;
$this->view->from = $this->app->tab;
$this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'story', $showModule) : array();
$this->view->project = $project;
$this->view->recTotal = $pager->recTotal;
$this->render();
$this->display();
}
/**
@@ -691,8 +528,9 @@ class product extends control
* @access public
* @return void
*/
public function dashboard($productID = 0)
public function dashboard(string $productID = '0')
{
$productID = (int)$productID;
$uri = $this->app->getURI(true);
$this->session->set('productPlanList', $uri, 'product');
$this->session->set('releaseList', $uri, 'product');
@@ -705,7 +543,7 @@ class product extends control
$this->product->setMenu($productID);
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$this->app->loadClass('pager', true);
$pager = new pager(0, 30, 1);
$this->view->title = $product->name . $this->lang->colon . $this->lang->product->view;
+403
View File
@@ -786,4 +786,407 @@ class productZen extends product
return $fields;
}
/**
* 获取研发需求列表页面关联的产品信息。
* Get the product of the browse page.
*
* @param int $productID
* @access protected
* @return object|false
*/
protected function getBrowseProduct(int $productID): object|false
{
$product = $this->product->getById($productID);
/* If product does not exist in $this->products list, then attach it to the list. */
if($product && !isset($this->products[$product->id])) $this->products[$product->id] = $product->name;
return $product ?? false;
}
/**
* 获取产品的分支和分支ID。
* Get branch and branchID.
*
* @param object $product
* @param string $branch
* @access protected
* @return object
*/
protected function getBranchAndBranchID(object|bool $product, string $branch): array
{
if(empty($product) || $product->type == 'normal') return ['all', 'all'];
/* 获取分支和分支ID。*/
$branchPairs = $this->loadModel('branch')->getPairs($product->id, 'all');
$branch = ($this->cookie->preBranch !== '' and $branch === '' and isset($branchPairs[$this->cookie->preBranch])) ? $this->cookie->preBranch : $branch;
$branchID = $branch;
return [$branch, $branchID];
}
/**
* 设置导航菜单。
* Set navigation menu.
*
* @param int $projectID
* @param int $productID
* @param string $branch
* @param string $storyType
* @access protected
* @return void
*/
protected function setMenu4Browse(int $projectID, int $productID, string $branch, string $storyType): void
{
if($this->app->tab == 'project')
{
$this->session->set('storyList', $this->app->getURI(true), 'project');
$this->loadModel('project')->setMenu($projectID);
return;
}
$this->session->set('storyList', $this->app->getURI(true), 'product');
$this->session->set('productList', $this->app->getURI(true), 'product');
$this->product->setMenu($productID, $branch, 0, '', "storyType=$storyType");
}
/**
* browse方法保存并修改cookie数据。
* Save and modify cookies for browse function.
*
* @param int $productID
* @param string $branch
* @param int $param
* @param string $storyType
* @param string $orderBy
* @access protected
* @return void
*/
protected function saveAndModifyCookie4Browse(int $productID, string $branch, int $param, string $browseType, string $orderBy): void
{
/* Set product ID and branch of the pre visited product. */
setcookie('preProductID', (string)$productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
/* Set module ID of story. */
if($this->cookie->preProductID != $productID or $this->cookie->preBranch != $branch or $browseType == 'bybranch')
{
$_COOKIE['storyModule'] = 0;
setcookie('storyModule', '0', 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
if($browseType == 'bymodule' or $browseType == '')
{
setcookie('storyModule', (string)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
/* The module ID from project app. */
if($this->app->tab == 'project') setcookie('storyModuleParam', (string)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
/* Re-init the story branch. */
$_COOKIE['storyBranch'] = 'all';
setcookie('storyBranch', 'all', 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
/* For rendering module tree. */
if($browseType == '') setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
if($browseType == 'bybranch') setcookie('storyBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
/* Save sort order of product stories list. */
setcookie('productStoryOrder', $orderBy, 0, $this->config->webRoot, '', $this->config->cookieSecure, true);
}
/**
* 获取模块ID。
* Get module ID.
*
* @param int $param
* @param string $browseType
* @access protected
* @return int
*/
protected function getModuleId4Browse(int $param, string $browseType): int
{
$cookieModule = $this->app->tab == 'project' ? $this->cookie->storyModuleParam : $this->cookie->storyModule;
$moduleID = 0;
if($browseType == 'bymodule') $moduleID = $param;
elseif($browseType != 'bysearch' and $browseType != 'bybranch' and $cookieModule) $moduleID = $cookieModule;
return $moduleID;
}
/**
* 获取模块的树形数据结构。
* Get the tree structure of modules.
* TODO return pure HTML string, we need array.
*
* @param int $projectID
* @param int $productID
* @param string $branch
* @param int $param
* @param string $storyType
* @param string $browseType
* @access protected
* @return string
*/
protected function getModuleTree4BrowseTODO(int $projectID, int $productID, string &$branch, int $param, string $storyType, string $browseType): string
{
/* Set moduleTree. */
$createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink';
if($browseType == '') $browseType = 'unclosed';
else $branch = $this->cookie->treeBranch;
/* If in project story and not chose product, get project story mdoules. */
if(empty($productID) && $this->app->rawModule == 'projectstory')
{
return $this->tree->getProjectStoryTreeMenu($projectID, 0, array('treeModel', $createModuleLink));
}
return $this->tree->getTreeMenu(
$productID,
'story',
0,
array('treeModel', $createModuleLink),
array('projectID' => $projectID, 'productID' => $productID),
$branch,
"&param=$param&storyType=$storyType"
);
}
/**
* 获取是否展示分支。
* Get the tree structure of modules.
*
* @param int $projectID
* @param int $productID
* @param string $storyType
* @param bool $isProjectStory
* @access protected
* @return bool
*/
protected function getShowBranch4Browse(int $projectID, int $productID, string $storyType, bool $isProjectStory): bool
{
if($isProjectStory and $storyType == 'story') return $this->loadModel('branch')->showBranch($productID, 0, $projectID);
return $this->loadModel('branch')->showBranch($productID);
}
/**
* 获取项目下的产品列表。
* Get products of the project.
*
* @param int $projectID
* @param string $storyType
* @param bool $isProjectStory
* @access protected
* @return array
*/
protected function getProjectProducts4Browse(int $projectID, string $storyType, bool $isProjectStory): array
{
$projectProducts = array();
if($isProjectStory && $storyType == 'story') $projectProducts = $this->product->getProducts($projectID);
return $projectProducts;
}
/**
* 获取产品计划。
* Get product plans of the project.
*
* @param array $projectProducts
* @param int $projectID
* @param string $storyType
* @param bool $isProjectStory
* @access protected
* @return array
*/
protected function getProductPlans4Browse(array $projectProducts, int $projectID, string $storyType, bool $isProjectStory): array
{
$this->loadModel('execution');
$plans = array();
if($isProjectStory && $storyType == 'story') $plans = $this->execution->getPlans($projectProducts, 'skipParent,unexpired,noclosed', $projectID);
return $plans;
}
/**
* 获取需求列表及分页对象。
* Get stories and the pager object.
*
* @param int $projectID
* @param int $productID
* @param string $branchID
* @param string $moduleID
* @param int $param
* @param string $storyType
* @param string $browseType
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access protected
* @return array
*/
protected function getStoriesAndPager4Browse(int $projectID, int $productID, string $branchID, int $moduleID, int $param, string $storyType, string $browseType, string $orderBy, int $recTotal, int $recPerPage, int $pageID): array
{
/* Append id for secend sort. */
$sort = common::appendOrder($orderBy);
if(strpos($sort, 'pri_') !== false) $sort = str_replace('pri_', 'priOrder_', $sort);
/* Load pager. */
$this->app->loadClass('pager', true);
if($this->app->getViewType() == 'xhtml') $recPerPage = 10;
$pager = new pager($recTotal, $recPerPage, $pageID);
$isProjectStory = $this->app->rawModule == 'projectstory';
/* Get stories. */
if($isProjectStory and $storyType == 'story')
{
if(!empty($product)) $this->session->set('currentProductType', $product->type);
$this->products = $this->product->getProducts($projectID, 'all', '', false);
if($browseType == 'bybranch') $param = $branchID;
$stories = $this->story->getExecutionStories($projectID, $productID, $branchID, $sort, $browseType, $param, $storyType, '', $pager);
}
else
{
$queryID = ($browseType == 'bysearch') ? $param : 0;
$stories = $this->product->getStories($productID, $branchID, $browseType, $queryID, $moduleID, $storyType, $sort, $pager);
}
if(!empty($stories)) $stories = $this->story->mergeReviewer($stories);
return [$stories, $pager];
}
/**
* 获取分支的配置数据。
* Get branch options.
*
* @param array $projectProducts
* @param int $projectID
* @access protected
* @return array
*/
protected function getBranchOptions4Browse(array $projectProducts, int $projectID): array
{
$branchOptions = array();
foreach($projectProducts as $product)
{
if($product and $product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($product->id, $projectID, 'all');
foreach($branches as $branchInfo) $branchOptions[$product->id][$branchInfo->id] = $branchInfo->name;
}
}
return $branchOptions;
}
/**
* 获取分支和分支标签的显示项。
* Get options of branch and branch tag.
*
* @param int $productID
* @param object|bool $product
* @param bool $isProjectStory
* @access protected
* @return [array, array]
*/
protected function getBranchAndTagOption4Browse(int $projectID, object|bool $product, bool $isProjectStory): array
{
$branchOption = array();
$branchTagOption = array();
if(empty($product) and $isProjectStory) return [$branchOption, $branchTagOption];
if($product and $product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($product->id, $projectID, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
return [$branchOption, $branchTagOption];
}
/**
* 构建搜索表单。
* Build search form.
*
* @param object|bool $project
* @param int $projectID
* @param int $productID
* @param string $branch
* @param int $param
* @param string $storyType
* @param string $browseType
* @param bool $isProjectStory
* @access protected
* @return void
*/
protected function buildSearchForm4Browse(object|bool $project,int $projectID, int &$productID, string $branch, int $param, string $storyType, string $browseType, bool $isProjectStory): void
{
/* Save browse type into session. */
if($browseType != 'bymodule' and $browseType != 'bybranch') $this->session->set('storyBrowseType', $browseType);
if(($browseType == 'bymodule' or $browseType == 'bybranch') and $this->session->storyBrowseType == 'bysearch') $this->session->set('storyBrowseType', 'unclosed');
/* Change for requirement story title. */
if($storyType == 'requirement')
{
$this->lang->story->title = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->title);
$this->lang->story->create = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->create);
$this->config->product->search['fields']['title'] = $this->lang->story->title;
unset($this->config->product->search['fields']['plan']);
unset($this->config->product->search['fields']['stage']);
}
if(isset($project->hasProduct) && empty($project->hasProduct))
{
if($isProjectStory && !$productID && !empty($this->products)) $productID = (int)key($this->products); // If toggle a project by the #swapper component on the story page of the projectstory module, the $productID may be empty. Make sure it has value.
unset($this->config->product->search['fields']['product']); // The none-product project don't need display the product in the search form.
if($project->model != 'scrum') unset($this->config->product->search['fields']['plan']); // The none-product and none-scrum project don't need display the plan in the search form.
}
/* Build search form. */
$params = $isProjectStory ? "projectID=$projectID&" : '';
$actionURL = $this->createLink($this->app->rawModule, $this->app->rawMethod, $params . "productID=$productID&branch=$branch&browseType=bySearch&queryID=myQueryID&storyType=$storyType");
$this->config->product->search['onMenuBar'] = 'yes';
$queryID = ($browseType == 'bysearch') ? $param : 0;
$this->product->buildSearchForm($productID, $this->products, $queryID, $actionURL, $branch, $projectID);
}
/**
* 获取需求的ID列表。
* Get ID list of stories.
*
* @param array $stories
* @access protected
* @return array
*/
protected function getStoryIdList(array $stories): array
{
$storyIdList = array();
foreach($stories as $story)
{
$storyIdList[$story->id] = $story->id;
if(!empty($story->children))
{
foreach($story->children as $child) $storyIdList[$child->id] = $child->id;
}
}
return $storyIdList;
}
}