. * * @copyright Copyright 2009-2010 青岛易软天创网络科技有限公司(www.cnezsoft.com) * @author Chunsheng Wang * @package bug * @version $Id$ * @link http://www.zentaoms.com */ ?> lang->bug->menu, 'product', $selectHtml . $this->lang->arrow); common::setMenuVars($this->lang->bug->menu, 'bug', $productID); common::setMenuVars($this->lang->bug->menu, 'testcase', $productID); common::setMenuVars($this->lang->bug->menu, 'testtask', $productID); } /* 创建一个Bug。*/ public function create() { $now = helper::now(); $bug = fixer::input('post') ->add('openedBy', $this->app->user->account) ->add('openedDate', $now) ->setDefault('project,story,task', 0) ->setDefault('openedBuild', '') ->setIF($this->post->assignedTo != '', 'assignedDate', $now) ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) ->specialChars('title,steps,keyword') ->cleanInt('product, module, severity') ->join('openedBuild', ',') ->remove('files, labels') ->get(); $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec(); if(!dao::isError()) { $bugID = $this->dao->lastInsertID(); $this->loadModel('file')->saveUpload('bug', $bugID); return $bugID; } return false; } /* 获得某一个产品,某一个模块下面的所有bug。*/ public function getModuleBugs($productID, $moduleIds = 0, $orderBy = 'id_desc', $pager = null) { return $this->dao->select('*')->from(TABLE_BUG) ->where('product')->eq((int)$productID) ->onCaseOf(!empty($moduleIds))->andWhere('module')->in($moduleIds)->endCase() ->andWhere('deleted')->eq(0) ->orderBy($orderBy)->page($pager)->fetchAll(); } /* 获取一个bug的详细信息。*/ public function getById($bugID) { $bug = $this->dao->select('t1.*, t2.name AS projectName, t3.title AS storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, t4.name AS taskName') ->from(TABLE_BUG)->alias('t1') ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id') ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id') ->where('t1.id')->eq((int)$bugID)->fetch(); if(!$bug) return false; foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = ''; if($bug->mailto) { $bug->mailto = ltrim(trim($bug->mailto), ','); // 去掉开始的,。 $bug->mailto = str_replace(' ', '', $bug->mailto); $bug->mailto = rtrim($bug->mailto, ',') . ','; $bug->mailto = str_replace(',', ', ', $bug->mailto); } if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title'); if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title'); if($bug->linkBug) $bug->linkBugTitles = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs(); $bug->files = $this->loadModel('file')->getByObject('bug', $bugID); return $bug; } /* 更新bug信息。*/ public function update($bugID) { $oldBug = $this->getById($bugID); $now = helper::now(); $bug = fixer::input('post') ->cleanInt('product,module,severity,project,story,task') ->specialChars('title,steps,keyword') ->remove('comment,fiels,labels') ->setDefault('project,module,project,story,task,duplicateBug', 0) ->setDefault('openedBuild', '') ->add('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) ->join('openedBuild', ',') ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account) ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now) ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account) ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed') ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now) ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved') ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed') ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy) ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now) ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active') ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) ->get(); $this->dao->update(TABLE_BUG)->data($bug) ->autoCheck() ->batchCheck($this->config->bug->edit->requiredFields, 'notempty') ->checkIF($bug->resolvedBy, 'resolution', 'notempty') ->checkIF($bug->closedBy, 'resolution', 'notempty') ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') ->where('id')->eq((int)$bugID) ->exec(); if(!dao::isError()) return common::createChanges($oldBug, $bug); } /* 解决Bug。*/ public function resolve($bugID) { $oldBug = $this->getById($bugID); $now = helper::now(); $bug = fixer::input('post') ->add('resolvedBy', $this->app->user->account) ->add('resolvedDate', $now) ->add('status', 'resolved') ->add('assignedDate', $now) ->add('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) ->setDefault('duplicateBug', 0) ->setDefault('assignedTo', $oldBug->openedBy) ->remove('comment') ->get(); $this->dao->update(TABLE_BUG)->data($bug) ->autoCheck() ->batchCheck($this->config->bug->resolve->requiredFields, 'notempty') ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') ->where('id')->eq((int)$bugID) ->exec(); } /* 激活Bug。*/ public function activate($bugID) { $oldBug = $this->getById($bugID); $now = helper::now(); $bug = fixer::input('post') ->setDefault('assignedTo', $oldBug->resolvedBy) ->add('assignedDate', $now) ->add('resolution', '') ->add('status', 'active') ->add('resolvedDate', '0000-00-00') ->add('resolvedBy', '') ->add('resolvedBuild', '') ->add('closedBy', '') ->add('closedDate', '0000-00-00') ->add('duplicateBug', 0) ->add('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) ->remove('comment,files,labels') ->get(); $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); } /* 关闭Bug。*/ public function close($bugID) { $oldBug = $this->getById($bugID); $now = helper::now(); $bug = fixer::input('post') ->add('assignedTo', 'closed') ->add('assignedDate', $now) ->add('status', 'closed') ->add('closedBy', $this->app->user->account) ->add('closedDate', $now) ->add('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) ->remove('comment') ->get(); $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); } /* 从bug列表中提取所有出现过的账户。*/ public function extractAccountsFromList($bugs) { $accounts = array(); foreach($bugs as $bug) { if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; } return array_unique($accounts); } /* 从一条bug中提取所有出现过的账户。*/ public function extractAccountsFromSingle($bug) { $accounts = array(); if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; return array_unique($accounts); } /* 获得用户的Bug id=>title列表。*/ public function getUserBugPairs($account) { $bugs = array(); $stmt = $this->dao->select('t1.id, t1.title, t2.name as product') ->from(TABLE_BUG)->alias('t1') ->leftJoin(TABLE_PRODUCT)->alias('t2') ->on('t1.product=t2.id') ->where('t1.assignedTo')->eq($account) ->andWhere('t1.deleted')->eq(0) ->query(); while($bug = $stmt->fetch()) { $bug->title = $bug->product . ' / ' . $bug->title; $bugs[$bug->id] = $bug->title; } return $bugs; } /* 获得某个项目的bug列表。*/ public function getProjectBugs($projectID, $orderBy = 'id_desc', $pager = null) { return $this->dao->select('*')->from(TABLE_BUG) ->where('project')->eq((int)$projectID) ->andWhere('deleted')->eq(0) ->orderBy($orderBy)->page($pager)->fetchAll(); } /* 通过某一次测试结果获得bug的标题和步骤。*/ public function getBugInfoFromResult($resultID) { $title = ''; $bugSteps = ''; $result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch(); $run = $this->loadModel('testtask')->getRunById($result->run); if($result and $result->caseResult == 'fail') { $title = $run->case->title; $caseSteps = $run->case->steps; $stepResults = unserialize($result->stepResults); $bugSteps = $this->lang->bug->tblStep; foreach($caseSteps as $key => $step) { $bugSteps .= ($key + 1) . '. ' .$step->desc . "\n"; if($stepResults[$step->id]['result'] == 'fail') { $bugSteps .= $this->lang->bug->tblResult; $bugSteps .= $stepResults[$step->id]['real'] . "\n"; $bugSteps .= $this->lang->bug->tblExpect; $bugSteps .= $step->expect; break; } } } return array('title' => $title, 'steps' => $bugSteps, 'storyID' => $run->case->story); } /* 按项目统计bug数。*/ public function getDataOfBugsPerProject() { $datas = $this->dao->select('project as name, count(project) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('project')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); $projects = $this->loadModel('project')->getPairs(); foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined; return $datas; } /* 按产品模块统计bug数。*/ public function getDataOfBugsPerModule() { $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('module')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs(); foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/'; return $datas; } /* 按bug创建日期统计。*/ public function getDataOfOpenedBugsPerDay() { return $this->dao->select('DATE_FORMAT(openedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('openedDate')->fetchAll(); } /* 按bug解决日期统计。*/ public function getDataOfResolvedBugsPerDay() { return $this->dao->select('DATE_FORMAT(resolvedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) ->where($this->session->bugReportCondition)->groupBy('name') ->having('name != 0000-00-00') ->orderBy('resolvedDate') ->fetchAll(); } /* 按bug关闭日期统计。*/ public function getDataOfClosedBugsPerDay() { return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) ->where($this->session->bugReportCondition)->groupBy('name') ->having('name != 0000-00-00') ->orderBy('closedDate')->fetchAll(); } /* 按bug创建者统计。*/ public function getDataOfOpenedBugsPerUser() { $datas = $this->dao->select('openedBy AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; return $datas; } /* 按bug解决者统计。*/ public function getDataOfResolvedBugsPerUser() { $datas = $this->dao->select('resolvedBy AS name, COUNT(*) AS value') ->from(TABLE_BUG)->where($this->session->bugReportCondition) ->andWhere('resolvedBy')->ne('') ->groupBy('name') ->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; return $datas; } /* 按bug关闭者统计。*/ public function getDataOfClosedBugsPerUser() { $datas = $this->dao->select('closedBy AS name, COUNT(*) AS value') ->from(TABLE_BUG) ->where($this->session->bugReportCondition) ->andWhere('closedBy')->ne('') ->groupBy('name') ->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; return $datas; } /* 按bug严重程度统计。*/ public function getDataOfBugsPerSeverity() { $datas = $this->dao->select('severity AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); foreach($datas as $severity => $data) if(isset($this->lang->bug->severityList[$severity])) $data->name = $this->lang->bug->severityList[$severity]; return $datas; } /* 按bug解决方案统计。*/ public function getDataOfBugsPerResolution() { $datas = $this->dao->select('resolution AS name, COUNT(*) AS value') ->from(TABLE_BUG) ->where($this->session->bugReportCondition) ->andWhere('resolution')->ne('') ->groupBy('name')->orderBy('value DESC') ->fetchAll('name'); if(!$datas) return array(); foreach($datas as $resolution => $data) if(isset($this->lang->bug->resolutionList[$resolution])) $data->name = $this->lang->bug->resolutionList[$resolution]; return $datas; } /* 按bug状态统计。*/ public function getDataOfBugsPerStatus() { $datas = $this->dao->select('status AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); foreach($datas as $status => $data) if(isset($this->lang->bug->statusList[$status])) $data->name = $this->lang->bug->statusList[$status]; return $datas; } /* 按bug类型统计。*/ public function getDataOfBugsPerType() { $datas = $this->dao->select('type AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); foreach($datas as $type => $data) if(isset($this->lang->bug->typeList[$type])) $data->name = $this->lang->bug->typeList[$type]; return $datas; } /* 合并公共的chart设置和当前chart的设置。*/ public function mergeChartOption($chartType) { $chartOption = $this->lang->bug->report->$chartType; $commonOption = $this->lang->bug->report->options; /* 设置图表的标题和展示方式。*/ $chartOption->graph->caption = $this->lang->bug->report->charts[$chartType]; if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; /* 合并配置。*/ foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; } }