| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- <?php
- /**
- * The tao file of metric module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author zhouxin <zhouxin@easysoft.ltd>
- * @package metric
- * @link https://www.zentao.net
- */
- class metricTao extends metricModel
- {
- /**
- * 请求度量项数据列表。
- * Fetch metric list.
- *
- * @param string $scope
- * @param string $stage
- * @param string $object
- * @param string $purpose
- * @param string $query
- * @param stirng $sort
- * @param object $pager
- * @access protected
- * @return void
- */
- protected function fetchMetrics($scope, $stage = 'all', $object = '', $purpose = '', $query = '', $sort = 'id_desc', $pager = null)
- {
- return $this->dao->select('*')->from(TABLE_METRIC)
- ->where('deleted')->eq('0')
- ->andWhere('scope')->eq($scope)
- ->andWhere('object')->in(array_keys($this->lang->metric->objectList))
- ->beginIF($query)->andWhere($query)->fi()
- ->beginIF($stage != 'all')->andWhere('stage')->eq($stage)->fi()
- ->beginIF(!empty($object))->andWhere('object')->eq($object)->fi()
- ->beginIF(!empty($purpose))->andWhere('purpose')->eq($purpose)->fi()
- ->beginIF($this->config->edition == 'open')->andWhere('object')->notIN('feedback,ticket,issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'biz')->andWhere('object')->notIN('issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'ipd' && $this->config->vision == 'rnd')->andWhere('code')->notIN($this->config->metric->orMetricList)->fi()
- ->beginIF($this->config->systemMode == 'light')->andWhere('code')->notIN($this->config->metric->waterfallCode)->fi()
- ->beginIF(!helper::hasFeature('program'))->andWhere('object')->notIN('program')->fi()
- ->beginIF(!helper::hasFeature('devops'))->andWhere('object')->notIN('host,deployment,node,code,codebase,pipeline,artifact')->fi()
- ->beginIF($sort)->orderBy($sort)->fi()
- ->beginIF($pager)->page($pager)->fi()
- ->fetchAll();
- }
- /**
- * 根据范围获取度量项。
- * Fetch metric by scope.
- *
- * @param string|array $scopes
- * @param int $limit
- * @access protected
- * @return array
- */
- protected function fetchMetricsByScope($scopes, $limit = -1)
- {
- if(!is_array($scopes)) $scopes = array($scopes);
- $metrics = $this->dao->select('*')->from(TABLE_METRIC)
- ->where('deleted')->eq('0')
- ->andWhere('scope')->in($scopes)
- ->andWhere('object')->in(array_keys($this->lang->metric->objectList))
- ->beginIF($limit > 0)->limit($limit)->fi()
- ->fetchAll('scope');
- return $metrics;
- }
- /**
- * 根据编号获取度项。
- * Fetch metric by id.
- *
- * @param string $code
- * @param array|string $fields
- * @access protected
- * @return mixed
- */
- protected function fetchMetricByID($code, $fields = '*')
- {
- if(is_array($fields)) $fields = implode(',', $fields);
- $metric = $this->dao->select($fields)->from(TABLE_METRIC)->where('code')->eq($code)->fetch();
- return $metric;
- }
- /**
- * 根据编号列表获取度项。
- * Fetch metric list by id list.
- *
- * @param array $metricIDList
- * @access protected
- * @return array
- */
- protected function fetchMetricsByIDList($metricIDList)
- {
- return $this->dao->select('*')->from(TABLE_METRIC)
- ->where('deleted')->eq(0)
- ->andWhere('id')->in($metricIDList)
- ->fetchAll();
- }
- /**
- * 根据编号列表获取度项。
- * Fetch metric list by id list.
- *
- * @param array $metricIDList
- * @access protected
- * @return array
- */
- protected function fetchMetricsByCodeList($codeList)
- {
- return $this->dao->select('*')->from(TABLE_METRIC)
- ->where('deleted')->eq(0)
- ->andWhere('code')->in($codeList)
- ->fetchAll();
- }
- /**
- * 根据度量项编码获取度量项数据。
- * Fetch metric by code.
- *
- * @param string $code
- * @access protected
- * @return object|false
- */
- protected function fetchMetricByCode($code, $fieldList = '*')
- {
- return $this->dao->select($fieldList)->from(TABLE_METRIC)
- ->where('code')->eq($code)
- ->fetch();
- }
- /**
- * 根据筛选条件获取度量项数据。
- * Fetch metric by filter.
- *
- * @param array $filters
- * @param string $stage
- * @access protected
- * @return array
- */
- protected function fetchMetricsWithFilter($filters, $stage = 'all')
- {
- $scopes = null;
- $objects = null;
- $purposes = null;
- if(isset($filters['scope']) && !empty($filters['scope'])) $scopes = implode(',', $filters['scope']);
- if(isset($filters['object']) && !empty($filters['object'])) $objects = implode(',', $filters['object']);
- if(isset($filters['purpose']) && !empty($filters['purpose'])) $purposes = implode(',', $filters['purpose']);
- $metrics = $this->dao->select('*')->from(TABLE_METRIC)
- ->where('deleted')->eq('0')
- ->beginIF($stage != 'all')->andWhere('stage')->eq($stage)->fi()
- ->beginIF(!empty($scopes))->andWhere('scope')->in($scopes)->fi()
- ->beginIF(!empty($objects))->andWhere('object')->in($objects)->fi()
- ->beginIF(!empty($purposes))->andWhere('purpose')->in($purposes)->fi()
- ->beginIF($this->config->edition == 'open')->andWhere('object')->notIN('feedback,ticket,issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'biz')->andWhere('object')->notIN('issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'ipd' && $this->config->vision == 'rnd')->andWhere('code')->notIN($this->config->metric->orMetricList)->fi()
- ->beginIF($this->config->systemMode == 'light')->andWhere('code')->notIN($this->config->metric->waterfallCode)
- ->beginIF(!helper::hasFeature('program'))->andWhere('object')->notIN('program')->fi()
- ->beginIF(!helper::hasFeature('devops'))->andWhere('object')->notIN('host')->fi()
- ->fetchAll();
- return $metrics;
- }
- /**
- * 请求我的收藏度量项。
- * Fetch my collect metrics.
- *
- * @param string $stage
- * @access protected
- * @return array
- */
- protected function fetchMetricsByCollect($stage)
- {
- return $this->dao->select('*')->from(TABLE_METRIC)
- ->where('deleted')->eq('0')
- ->andWhere('collector')->like("%,{$this->app->user->account},%")
- ->beginIF($stage!= 'all')->andWhere('stage')->eq($stage)->fi()
- ->beginIF($this->config->edition == 'open')->andWhere('object')->notIN('feedback,ticket,issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'biz')->andWhere('object')->notIN('issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'ipd' && $this->config->vision == 'rnd')->andWhere('code')->notIN($this->config->metric->orMetricList)->fi()
- ->beginIF($this->config->systemMode == 'light')->andWhere('code')->notIN($this->config->metric->waterfallCode)
- ->beginIF(!helper::hasFeature('program'))->andWhere('object')->notIN('program')->fi()
- ->beginIF(!helper::hasFeature('devops'))->andWhere('object')->notIN('host')->fi()
- ->fetchAll();
- }
- /**
- * 请求模块数据。
- * Fetch module data.
- *
- * @param string $scope
- * @access protected
- * @return void
- */
- protected function fetchModules($scope)
- {
- return $this->dao->select('object, purpose')->from(TABLE_METRIC)
- ->where('deleted')->eq('0')
- ->andWhere('scope')->eq($scope)
- ->beginIF($this->config->edition == 'open')->andWhere('object')->notIN('feedback,ticket,issue,risk,demand')->fi()
- ->beginIF($this->config->edition == 'biz')->andWhere('object')->notIN('issue,risk,demand')->fi()
- ->beginIF(!helper::hasFeature('program'))->andWhere('object')->notIN('program')->fi()
- ->beginIF(!helper::hasFeature('devops'))->andWhere('object')->notIN('host')->fi()
- ->groupBy('object, purpose')
- ->fetchAll();
- }
- /**
- * 获取范围对象类型以构建分页对象。
- * Get object list with page.
- *
- * @param string $code
- * @param string $scope
- * @param object $pager
- * @access protected
- * @return array|false
- */
- protected function getObjectsWithPager($metric, $query, $pager = null, $extra = array())
- {
- $code = $metric->code;
- $scope = $metric->scope;
- $dateType = $metric->dateType;
- if($scope == 'system') return false;
- $scopeObjects = $this->dao->select($scope)->from(TABLE_METRICLIB)
- ->where('metricCode')->eq($code)
- ->beginIF(!empty($extra))->andWhere($scope)->in($extra)->fi();
- $scopeObjects = $this->processDAOWithDate($scopeObjects, $query, $dateType)->fetchPairs();
- $objects = null;
- if($scope == 'product')
- {
- $objects = $this->dao->select('id')->from(TABLE_PRODUCT)
- ->where('deleted')->eq(0)
- ->andWhere('shadow')->eq(0)
- ->andWhere('id')->in($scopeObjects);
- }
- elseif($scope == 'project')
- {
- $objects = $this->dao->select('id')->from(TABLE_PROJECT)
- ->where('deleted')->eq(0)
- ->andWhere('type')->eq('project')
- ->andWhere('id')->in($scopeObjects);
- }
- elseif($scope == 'execution')
- {
- $objects = $this->dao->select('id')->from(TABLE_EXECUTION)
- ->where('deleted')->eq(0)
- ->andWhere('type')->in('sprint,stage,kanban')
- ->andWhere('id')->in($scopeObjects);
- }
- elseif($scope == 'user')
- {
- $objects = $this->dao->select('account')->from(TABLE_USER)
- ->where('deleted')->eq('0')
- ->andWhere('account')->in($scopeObjects);
- }
- elseif($scope == 'repo')
- {
- $objects = $this->dao->select('id')->from(TABLE_REPO)
- ->where('deleted')->eq('0')
- ->andWhere('id')->in($scopeObjects);
- }
- if(!is_null($objects))
- {
- if(!empty($pager)) $objects = $objects->page($pager);
- return $objects->fetchPairs();
- }
- return array();
- }
- /**
- * Process dao with query date values.
- *
- * @param object $stmt
- * @param object $query
- * @param string $dateType
- * @access protected
- * @return object
- */
- protected function processDAOWithDate($stmt, $query, $dateType)
- {
- $dateBegin = $this->processRecordQuery($query, 'dateBegin', 'date');
- $dateEnd = $this->processRecordQuery($query, 'dateEnd', 'date');
- $calcDate = $this->processRecordQuery($query, 'calcDate', 'date');
- list($dateBegin, $dateEnd) = $this->processRecordQuery($query, 'dateLabel', 'date');
- $yearBegin = empty($dateBegin) ? '' : $dateBegin->year;
- $yearEnd = empty($dateEnd) ? '' : $dateEnd->year;
- $monthBegin = empty($dateBegin) ? '' : $dateBegin->month;
- $monthEnd = empty($dateEnd) ? '' : $dateEnd->month;
- $weekBegin = empty($dateBegin) ? '' : $dateBegin->week;
- $weekEnd = empty($dateEnd) ? '' : $dateEnd->week;
- $dayBegin = empty($dateBegin) ? '' : $dateBegin->day;
- $dayEnd = empty($dateEnd) ? '' : $dateEnd->day;
- $stmt = $stmt->beginIF(!empty($dateBegin) and $dateType == 'year')->andWhere('`year`')->ge($yearBegin)->fi()
- ->beginIF(!empty($dateEnd) and $dateType == 'year')->andWhere('`year`')->le($yearEnd)->fi()
- ->beginIF(!empty($dateBegin) and $dateType == 'month')->andWhere('CONCAT(`year`, `month`)')->ge($monthBegin)->fi()
- ->beginIF(!empty($dateEnd) and $dateType == 'month')->andWhere('CONCAT(`year`, `month`)')->le($monthEnd)->fi()
- ->beginIF(!empty($dateBegin) and $dateType == 'week')->andWhere('CONCAT(`year`, `week`)')->ge($weekBegin)->fi()
- ->beginIF(!empty($dateEnd) and $dateType == 'week')->andWhere('CONCAT(`year`, `week`)')->le($weekEnd)->fi()
- ->beginIF(!empty($dateBegin) and $dateType == 'day')->andWhere('CONCAT(`year`, `month`, `day`)')->ge($dayBegin)->fi()
- ->beginIF(!empty($dateEnd) and $dateType == 'day')->andWhere('CONCAT(`year`, `month`, `day`)')->le($dayEnd)->fi()
- ->beginIF(!empty($calcDate))->andWhere('date')->ge($calcDate)->fi();
- return $stmt;
- }
- /**
- * 请求度量数据。
- * Fetch metric data.
- *
- * @param string $code
- * @param array $fieldList
- * @param array $query
- * @param object|null $pager
- * @access protected
- * @return array
- */
- protected function fetchMetricRecords($code, $fieldList, $query = array(), $pager = null)
- {
- $metric = $this->getByCode($code);
- $scopeKey = $metric->scope;
- $dateType = $metric->dateType;
- $query['dateType'] = $dateType;
- $scopeValue = $this->processRecordQuery($query, 'scope');
- $objectList = $this->getObjectsWithPager($metric, $query, $pager, $scopeValue);
- $fieldList = array_merge($fieldList, array('id', 'value', 'date', 'calcType', 'calculatedBy'));
- $wrapFields = array_map(function ($value) {
- return "`$value`";
- }, $fieldList);
- $dataFieldStr = implode(',', $wrapFields);
- $stmt = $this->dao->select($dataFieldStr)
- ->from(TABLE_METRICLIB)
- ->where('metricCode')->eq($code)
- ->beginIF($scopeKey != 'system' && !empty($objectList))->andWhere($scopeKey)->in($objectList)->fi()
- ->beginIF(!empty($scopeValue))->andWhere($scopeKey)->in($scopeValue)->fi();
- $stmt = $this->processDAOWithDate($stmt, $query, $dateType)
- ->beginIF($scopeKey != 'system')->orderBy("date desc, $scopeKey, year desc, month desc, week desc, day desc")->fi()
- ->beginIF($scopeKey == 'system')->orderBy("date desc, year desc, month desc, week desc, day desc")->fi();
- if($scopeKey == 'system') $stmt = $stmt->page($pager); // beginIF not work with page()
- return $stmt->fetchAll();
- }
- protected function fetchMetricRecordsWithOption($code, $fieldList, $options = array(), $pager = null)
- {
- $metric = $this->getByCode($code);
- $scopeKey = $metric->scope;
- $dateType = $metric->dateType;
- $fieldList = array_merge($fieldList, array('id', 'value', 'date', 'calcType', 'calculatedBy'));
- $wrapFields = array_map(function ($value) {
- return "`$value`";
- }, $fieldList);
- $dataFieldStr = implode(',', $wrapFields);
- $stmt = $this->dao->select($dataFieldStr)->from(TABLE_METRICLIB)
- ->where('metricCode')->eq($code);
- if(!empty($options))
- {
- foreach($options as $key => $option)
- {
- $stmt = $stmt->andWhere($key)->in($option);
- }
- }
- if($dateType == 'nodate')
- {
- $stmt->andWhere('date')->ge(helper::today());
- }
- $stmt = $stmt->orderBy("date desc");
- if($scopeKey == 'system') $stmt = $stmt->page($pager); // beginIF not work with page()
- return $stmt->fetchAll();
- }
- /**
- * 请求最新的度量数据。
- * Fetch latest metric data.
- *
- * @param string $code
- * @param array $fieldList
- * @param array $query
- * @param object|null $pager
- * @access protected
- * @return array
- */
- protected function fetchLatestMetricRecords($code, $fieldList, $query = array(), $pager = null)
- {
- $metric = $this->getByCode($code);
- $dateType = $metric->dateType;
- $lastCalcDate = substr($metric->lastCalcTime, 0, 10);
- $query['dateType'] = $dateType;
- $objectList = $this->getObjectsWithPager($metric, $query);
- $scopeValue = $this->processRecordQuery($query, 'scope');
- $scopeKey = $metric->scope;
- $fieldList = array_merge($fieldList, array('id', 'value', 'date'));
- $wrapFields = array_map(function ($value) {
- return "`$value`";
- }, $fieldList);
- $dataFieldStr = implode(',', $wrapFields);
- $stmt = $this->dao->select($dataFieldStr)
- ->from(TABLE_METRICLIB)
- ->where('metricCode')->eq($code)
- ->beginIF($scopeKey != 'system')->andWhere($scopeKey)->in($objectList)->fi()
- ->beginIF(!empty($scopeValue))->andWhere($scopeKey)->in($scopeValue)->fi();
- $stmt = $this->processDAOWithDate($stmt, $query, $dateType)
- ->beginIF(!empty($scopeList))->orderBy("date desc, $scopeKey, year desc, month desc, week desc, day desc")->fi()
- ->beginIF(empty($scopeList))->orderBy("date desc, year desc, month desc, week desc, day desc")->fi();
- $stmt = $stmt->page($pager);
- return $stmt->fetchAll();
- }
- /**
- * 根据日期获取度量数据。
- * Fetch metric record by date.
- *
- * @param string $code
- * @param string $date
- * @param int $limit
- * @access protected
- * @return array
- */
- protected function fetchMetricRecordByDate($code = 'all', $date = '', $limit = 100)
- {
- $nextDate = empty($date) ? '' : date('Y-m-d', strtotime($date) + 86400);
- $records = $this->dao->select('id')->from(TABLE_METRICLIB)
- ->where('1 = 1')
- ->beginIF($code != 'all')->andWhere('metricCode')->eq($code)->fi()
- ->beginIF(!empty($date))
- ->andWhere('date')->ge($date)
- ->andWhere('date')->lt($nextDate)
- ->fi()
- ->beginIF($limit > 0)->limit($limit)->fi()
- ->fetchAll();
- return $records;
- }
- /**
- * Set deleted.
- *
- * @param string $code
- * @param string $value
- * @access protected
- * @return void
- */
- protected function setDeleted($code, $value)
- {
- $this->dao->update(TABLE_METRICLIB)
- ->set('deleted')->eq($value)
- ->where('metricCode')->eq($code)
- ->exec();
- }
- /**
- * Keep latest records.
- *
- * @param int $code
- * @param int $fields
- * @access protected
- * @return void
- */
- protected function keepLatestRecords($code, $fields)
- {
- if(empty($fields)) return;
- /**
- * 判断fields中的字段是否与array('year', 'month', 'week', 'day')存在交集
- */
- $intersect = array_intersect($fields, array('year', 'month', 'week', 'day'));
- foreach($fields as $key => $field) $fields[$key] = "`$field`";
- if(empty($intersect)) $fields[] = 'DATE(date)';
- $table = TABLE_METRICLIB;
- $sql = " UPDATE $table AS t1";
- $sql .= " SET t1.deleted = '0'";
- $sql .= " WHERE id IN (";
- $sql .= " SELECT maxid FROM (";
- $sql .= " SELECT MAX(id) AS maxid";
- $sql .= " FROM $table";
- $sql .= " WHERE metricCode = '$code'";
- $sql .= " GROUP BY ". implode(',', $fields);
- $sql .= " ) AS tmp";
- $sql .= " )";
- $this->dao->exec($sql);
- }
- /**
- * Execute delete.
- *
- * @param string $code
- * @access protected
- * @return void
- */
- protected function executeDelete($code)
- {
- $this->dao->delete()->from(TABLE_METRICLIB)
- ->where('metricCode')->eq($code)
- ->andWhere('deleted', true)->eq('1')
- ->orWhere('value')->eq(0)->markRight(1)
- ->exec();
- }
- /**
- * 重建id列顺序。
- * Rebuild id column order.
- *
- * @access protected
- * @return void
- */
- protected function rebuildIdColumn()
- {
- if($this->config->db->driver != 'mysql') return;
- $table = TABLE_METRICLIB;
- $tableRowCount = $this->dao->select('COUNT(id) as rowcount')->from(TABLE_METRICLIB)->fetch('rowcount');
- $autoIncrement = $tableRowCount + 1;
- $this->dao->exec("SET @count = 0;UPDATE $table SET `id` = @count:= @count + 1;");
- $this->dao->exec("ALTER TABLE $table AUTO_INCREMENT = $autoIncrement");
- }
- }
|