model.php 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351
  1. <?php /**
  2. * The model file of custom module of ZenTaoPMS.
  3. *
  4. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  5. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  6. * @author Congzhi Chen <congzhi@cnezsoft.com>
  7. * @package custom
  8. * @version $Id$
  9. * @link https://www.zentao.net
  10. */
  11. class customModel extends model
  12. {
  13. /**
  14. * 获取自定义语言项。
  15. * Get all custom lang.
  16. *
  17. * @access public
  18. * @return array|false
  19. */
  20. public function getAllLang()
  21. {
  22. $currentLang = $this->app->getClientLang();
  23. $allCustomLang = $this->customTao->getCustomLang();
  24. if(!$allCustomLang) return false;
  25. $sectionLang = array();
  26. foreach($allCustomLang as $customLang)
  27. {
  28. $sectionLang[$customLang->module][$customLang->section][$customLang->lang] = $customLang->lang;
  29. }
  30. $processedLang = array();
  31. foreach($allCustomLang as $customLang)
  32. {
  33. if(isset($sectionLang[$customLang->module][$customLang->section]['all']) && isset($sectionLang[$customLang->module][$customLang->section][$currentLang]) && $customLang->lang == 'all') continue;
  34. /* Process list featureBar and more language. */
  35. if(strpos($customLang->section, 'featureBar-') !== false || strpos($customLang->section, 'moreSelects-') !== false)
  36. {
  37. $sections = explode('-', $customLang->section);
  38. $sections = array_reverse($sections);
  39. if(!isset($processedLang[$customLang->module])) $processedLang[$customLang->module] = array();
  40. $sectionArr = array($customLang->key => $customLang->value);
  41. foreach($sections as $section)
  42. {
  43. $sectionKey = key($sectionArr);
  44. $sectionArr[$section] = $sectionArr;
  45. if($sectionKey != $section) unset($sectionArr[$sectionKey]);
  46. }
  47. if(!empty($sectionArr)) $processedLang[$customLang->module] = array_merge_recursive($processedLang[$customLang->module], $sectionArr);
  48. }
  49. else
  50. {
  51. if($customLang->module == 'productMenu' && $customLang->key == 'system') $this->lang->product->system = $customLang->value;
  52. $processedLang[$customLang->module][$customLang->section][$customLang->key] = $customLang->value;
  53. }
  54. }
  55. return $processedLang;
  56. }
  57. /**
  58. * 设置自定义语言项。
  59. * Set value of an item.
  60. *
  61. * @param string $path zh-cn.story.soucreList.customer.1
  62. * @param string $value
  63. * @access public
  64. * @return bool
  65. */
  66. public function setItem($path, $value = '')
  67. {
  68. $level = substr_count($path, '.');
  69. $section = '';
  70. $system = 1;
  71. if($level <= 1) return false;
  72. if($level == 2) list($lang, $module, $key) = explode('.', $path);
  73. if($level == 3) list($lang, $module, $section, $key) = explode('.', $path);
  74. if($level == 4) list($lang, $module, $section, $key, $system) = explode('.', $path);
  75. $item = new stdclass();
  76. $item->lang = $lang;
  77. $item->module = $module;
  78. $item->section = $section;
  79. $item->key = $key;
  80. $item->value = $value;
  81. $item->system = $system;
  82. if(!$this->app->upgrading)
  83. {
  84. $item->vision = $this->config->vision;
  85. if(in_array("{$item->module}-{$item->section}", $this->config->custom->nonInterface->lang)) $item->vision = 'all';
  86. if($item->module == 'feedback') $item->vision = 'all';
  87. }
  88. $this->dao->replace(TABLE_LANG)->data($item)->exec();
  89. return !dao::isError();
  90. }
  91. /**
  92. * 获取自定义语言项。
  93. * Get value of custom items.
  94. *
  95. * @param string $paramString see parseItemParam();
  96. * @access public
  97. * @return array
  98. */
  99. public function getItems($paramString)
  100. {
  101. return $this->prepareSQL($this->parseItemParam($paramString), 'select')->orderBy('lang,id')->fetchAll('key', false);
  102. }
  103. /**
  104. * 删除自定义项。
  105. * Delete items.
  106. *
  107. * @param string $paramString see parseItemParam();
  108. * @access public
  109. * @return bool
  110. */
  111. public function deleteItems($paramString)
  112. {
  113. $this->prepareSQL($this->parseItemParam($paramString), 'delete')->exec();
  114. return !dao::isError();
  115. }
  116. /**
  117. * 解析选择或删除项的参数字符串。
  118. * Parse the param string for select or delete items.
  119. *
  120. * @param string $paramString lang=xxx&module=story&section=sourceList&key=customer and so on.
  121. * @access public
  122. * @return array
  123. */
  124. public function parseItemParam($paramString)
  125. {
  126. /* Parse the param string into array. */
  127. parse_str($paramString, $params);
  128. /* Init fields not set in the param string. */
  129. $fields = 'lang,module,section,key,vision';
  130. $fields = explode(',', $fields);
  131. foreach($fields as $field)
  132. {
  133. if(isset($params[$field])) continue;
  134. $params[$field] = '';
  135. }
  136. return $params;
  137. }
  138. /**
  139. * 创建一个DAO对象来选择或删除一条或多条记录。
  140. * Create a DAO object to select or delete one or more records.
  141. *
  142. * @param array $params the params parsed by parseItemParam() method.
  143. * @param string $method select|delete.
  144. * @access public
  145. * @return object
  146. */
  147. public function prepareSQL($params, $method = 'select')
  148. {
  149. return $this->dao->$method('*')->from(TABLE_LANG)->where('1 = 1')
  150. ->beginIF($params['lang'])->andWhere('lang')->in($params['lang'])->fi()
  151. ->beginIF($params['module'])->andWhere('module')->in($params['module'])->fi()
  152. ->beginIF($params['section'])->andWhere('section')->in($params['section'])->fi()
  153. ->beginIF($params['key'])->andWhere('`key`')->in($params['key'])->fi()
  154. ->beginIF($params['vision'])->andWhere('`vision`')->in('all,' . $params['vision'])->fi();
  155. }
  156. /**
  157. * 通过配置文件设置菜单。
  158. * Build menu data from config
  159. *
  160. * @param object|array $allMenu
  161. * @param string|array $customMenu
  162. * @param string $module
  163. * @access public
  164. * @return array
  165. */
  166. public static function setMenuByConfig($allMenu, $customMenu, $module = '')
  167. {
  168. global $app, $lang;
  169. $tab = $app->tab;
  170. list($customMenuMap, $order) = static::buildCustomMenuMap($allMenu, $customMenu, $module);
  171. /* Merge fileMenu && customMenu. */
  172. foreach($customMenuMap as $name => &$item)
  173. {
  174. if(is_object($allMenu) && !isset($allMenu->{$name})) $allMenu->{$name} = $item;
  175. if(is_array($allMenu) && !isset($allMenu[$name])) $allMenu[$name] = $item;
  176. if(is_object($allMenu) && isset($allMenu->{$name}))
  177. {
  178. $menuItem = (array)$allMenu->{$name};
  179. if(isset($menuItem['icon'])) $item->icon = $menuItem['icon'];
  180. }
  181. }
  182. $menu = static::buildMenuItems($allMenu, $customMenuMap, $module, $order);
  183. ksort($menu, SORT_NUMERIC);
  184. if(!isset($lang->{$tab})) return array();
  185. /* Set divider in main && module menu. */
  186. if(!isset($lang->{$tab}->menuOrder))
  187. {
  188. if(!isset($lang->{$tab})) $tab == 'my';
  189. $lang->{$tab}->menuOrder = array();
  190. }
  191. ksort($lang->{$tab}->menuOrder, SORT_NUMERIC);
  192. $group = 0;
  193. $dividerOrders = array();
  194. foreach($lang->{$tab}->menuOrder as $name)
  195. {
  196. if(isset($lang->{$tab}->dividerMenu) && strpos($lang->{$tab}->dividerMenu, ",{$name},") !== false) $group++;
  197. $dividerOrders[$name] = $group;
  198. }
  199. $isFirst = true; // No divider before First item.
  200. $group = 0;
  201. foreach($menu as $item)
  202. {
  203. $isNormalItem = $module == 'main' && isset($item->name) && $item->name != 'other';
  204. if($isNormalItem && isset($dividerOrders[$item->name]) && $dividerOrders[$item->name] > $group)
  205. {
  206. $menu[$item->order]->divider = $isFirst ? false : true;
  207. $group = $dividerOrders[$item->name];
  208. }
  209. else
  210. {
  211. $isFirst = false;
  212. if(!isset($menu[$item->order]->divider)) $menu[$item->order]->divider = false;
  213. }
  214. }
  215. return array_values($menu);
  216. }
  217. /**
  218. * 构造自定义导航数据。
  219. * Build custom menu data.
  220. *
  221. * @param array|string $customMenu
  222. * @param string $module
  223. * @static
  224. * @access public
  225. * @return array
  226. * @param object|mixed[] $allMenu
  227. */
  228. public static function buildCustomMenuMap($allMenu, $customMenu = '', $module = '')
  229. {
  230. global $lang;
  231. $customMenuMap = array();
  232. $order = 1;
  233. if($customMenu && is_array($customMenu))
  234. {
  235. $prev = '';
  236. foreach($customMenu as $customMenuItem)
  237. {
  238. if(empty($customMenuItem->name)) continue;
  239. $name = $customMenuItem->name;
  240. if(!isset($customMenuItem->order)) $customMenuItem->order = $order;
  241. if($prev == 'divider') $customMenuItem->divider = true;
  242. if($name != 'divider') $customMenuMap[$name] = $customMenuItem;
  243. $prev = $name;
  244. $order ++;
  245. }
  246. }
  247. elseif($module)
  248. {
  249. $menuOrder = array();
  250. if($module == 'main' && isset($lang->menuOrder))
  251. {
  252. $menuOrder = $lang->menuOrder;
  253. }
  254. elseif(isset($lang->menu->{$module}))
  255. {
  256. $moduleMenu = is_object($lang->menu->$module) ? (array)$lang->menu->$module : $lang->menu->$module;
  257. if(is_array($moduleMenu) && isset($moduleMenu['menuOrder'])) $menuOrder = $moduleMenu['menuOrder'];
  258. }
  259. if($menuOrder)
  260. {
  261. ksort($menuOrder);
  262. foreach($menuOrder as $name)
  263. {
  264. /* If menu is removed, delete the menuOrder. */
  265. if(!isset($allMenu->$name)) continue;
  266. $item = new stdclass();
  267. $item->name = $name;
  268. $item->hidden = false;
  269. $item->order = $order ++;
  270. $customMenuMap[$name] = $item;
  271. }
  272. }
  273. }
  274. return array($customMenuMap, $order);
  275. }
  276. /**
  277. * 构造菜单数据。
  278. * Build menu data.
  279. *
  280. * @param object|array $allMenu
  281. * @param array $customMenuMap
  282. * @param string $menuModuleName
  283. * @param int $order
  284. * @static
  285. * @access public
  286. * @return array
  287. */
  288. public static function buildMenuItems($allMenu, $customMenuMap, $menuModuleName, $order = 1)
  289. {
  290. global $config, $app;
  291. $menu = array();
  292. $isTutorialMode = commonModel::isTutorialMode();
  293. $module = $menuModuleName;
  294. foreach($allMenu as $name => $item)
  295. {
  296. $name = (string)$name;
  297. if(is_object($item)) $item = (array)$item;
  298. /* The variable of item has not link && is not link then ignore it. */
  299. $link = (is_array($item) && isset($item['link'])) ? $item['link'] : $item;
  300. if(!is_string($link)) continue;
  301. $subMenu = array();
  302. $label = $link;
  303. $hasPriv = true;
  304. $method = '';
  305. if(strpos($link, '|') !== false)
  306. {
  307. $link = explode('|', $link);
  308. list($label, $module, $method) = $link;
  309. $methodName = $method;
  310. /* 需求列表按照对应的需求模块鉴权。 */
  311. if($module == 'product' && $method == 'browse')
  312. {
  313. $params = zget($link, 3, '');
  314. preg_match('/storyType=([^&]*)/', $params, $matches);
  315. $methodName = !empty($matches[1]) ? $matches[1] : $methodName;
  316. }
  317. $hasPriv = commonModel::hasPriv($module, $methodName, null, zget($link, 3, ''));
  318. /* Fix bug #20464 */
  319. if(isset($vars)) unset($vars);
  320. if(!$hasPriv && is_array($item) && isset($item['subMenu']))
  321. {
  322. foreach($item['subMenu'] as $subMenu)
  323. {
  324. if(!isset($subMenu['link']) || strpos($subMenu['link'], '|') === false) continue;
  325. if(strpos("|program|product|project|execution|qa|", "|{$app->tab}|") === false && strpos($subMenu['link'], '%s') !== false) continue;
  326. list($subLabel, $module, $method) = explode('|', $subMenu['link']);
  327. if(count(explode('|', $subMenu['link'])) > 3) list($subLabel, $module, $method, $vars) = explode('|', $subMenu['link']);
  328. $hasPriv = commonModel::hasPriv($module, $method);
  329. if($hasPriv) break;
  330. }
  331. }
  332. if($module == 'execution' && $method == 'more') $hasPriv = true;
  333. if($module == 'project' && $method == 'other') $hasPriv = true;
  334. if(!$hasPriv && isset($vars)) unset($vars);
  335. }
  336. if($isTutorialMode || $hasPriv)
  337. {
  338. $itemLink = '';
  339. if($module && $method)
  340. {
  341. $itemLink = array('module' => $module, 'method' => $method);
  342. if(isset($link[3])) $itemLink['vars'] = $link[3];
  343. if(isset($vars)) $itemLink['vars'] = $vars;
  344. if(is_array($item) && isset($item['target'])) $itemLink['target'] = $item['target'];
  345. }
  346. /* Process menu item's order and hidden attirbute. */
  347. $menuItem = static::buildMenuItem($item, $customMenuMap, $name, $label, $itemLink, $isTutorialMode, $subMenu);
  348. $menuItem->order = (isset($customMenuMap[$name]) && isset($customMenuMap[$name]->order) ? $customMenuMap[$name]->order : $order ++);
  349. if(!empty($customMenuMap) && !empty($customMenuMap[$name]->hidden)) $menuItem->hidden = true; // 自定义过滤掉的菜单不显示。
  350. if(isset($customMenuMap[$name]) && isset($customMenuMap[$name]->divider)) $menuItem->divider = true;
  351. if($app->viewType == 'mhtml' && isset($config->custom->moblieHidden[$menuModuleName]) && in_array($name, $config->custom->moblieHidden[$menuModuleName])) $menuItem->hidden = 1; // Hidden menu by config in mobile.
  352. while(isset($menu[$menuItem->order])) $menuItem->order ++;
  353. $menu[$menuItem->order] = $menuItem;
  354. }
  355. }
  356. return $menu;
  357. }
  358. /**
  359. * 构造菜单数据项。
  360. * Build menu item.
  361. *
  362. * @param array|string $item
  363. * @param int $customMenuMap
  364. * @param string $name
  365. * @param string $label
  366. * @param string|array $itemLink
  367. * @param bool $isTutorialMode
  368. * @param array $subMenu
  369. * @static
  370. * @access public
  371. * @return object
  372. */
  373. public static function buildMenuItem($item, $customMenuMap, $name = '', $label = '', $itemLink = '', $isTutorialMode = false, $subMenu = array())
  374. {
  375. /* 用例列表featureBar的分割线。 */
  376. if($item === '-')
  377. {
  378. $menuItem = new stdclass();
  379. $menuItem->type = 'divider';
  380. return $menuItem;
  381. }
  382. if(is_array($item) && (isset($item['subMenu']) || isset($item['dropMenu'])))
  383. {
  384. foreach(array('subMenu', 'dropMenu') as $key)
  385. {
  386. if(!isset($item[$key])) continue;
  387. foreach($item[$key] as $subItem)
  388. {
  389. if(isset($subItem->link['module']) && isset($subItem->link['method'])) $subItem->hidden = !common::hasPriv($subItem->link['module'], $subItem->link['method']);
  390. }
  391. }
  392. }
  393. $menuItem = new stdclass();
  394. $menuItem->name = $name;
  395. $menuItem->link = $itemLink;
  396. $menuItem->text = $label;
  397. if(is_array($item) && isset($item['showInMainMenu'])) $menuItem->showInMainMenu = $item['showInMainMenu'];
  398. if($isTutorialMode) $menuItem->tutorial = true;
  399. if(isset($customMenuMap[$name]) && isset($customMenuMap[$name]->icon)) $menuItem->icon = $customMenuMap[$name]->icon;
  400. $attrList = array('class', 'subModule', 'dropMenu', 'alias', 'exclude', 'divider');
  401. $hidden = strpos($name, 'QUERY') === 0 && !isset($customMenuMap[$name]) ? false : isset($customMenuMap[$name]) && isset($customMenuMap[$name]->hidden) && $customMenuMap[$name]->hidden;
  402. foreach($attrList as $attr)
  403. {
  404. if(!empty($item[$attr])) $menuItem->$attr = $item[$attr];
  405. }
  406. if($hidden) $menuItem->hidden = $hidden;
  407. if($subMenu) $menuItem->subMenu = $subMenu;
  408. return $menuItem;
  409. }
  410. /**
  411. * 获取模块菜单数据,如果模块是'main'则返回主菜单。
  412. * Get module menu data, if module is 'main' then return main menu.
  413. *
  414. * @param string $module
  415. * @param bool $isHomeMenu
  416. * @access public
  417. * @return array
  418. */
  419. public static function getModuleMenu($module = 'main', $isHomeMenu = false)
  420. {
  421. global $app, $lang, $config;
  422. if(empty($module)) $module = 'main';
  423. $allMenu = new stdclass();
  424. if($module == 'main' and !empty($lang->menu)) $allMenu = $lang->menu;
  425. if($module != 'main' and isset($lang->menu->$module))
  426. {
  427. $moduleMenu = is_object($lang->menu->$module) ? (array)$lang->menu->$module : $lang->menu->$module;
  428. if(is_array($moduleMenu) && isset($moduleMenu['subMenu'])) $allMenu = $moduleMenu['subMenu'];
  429. }
  430. if($module == 'product' and isset($allMenu->branch)) $allMenu->branch = str_replace('@branch@', $lang->custom->branch, $allMenu->branch);
  431. /* 获取自定义过的导航。 */
  432. $customKey = $isHomeMenu ? $app->tab . '-home' : ($module == 'main' ? $app->tab : $app->tab . '-' . $module);
  433. /* 项目自定义导航的key特殊获取。*/
  434. if($app->tab == 'project' && !$isHomeMenu && $module == 'main')
  435. {
  436. $projectID = isset($_SESSION['project']) ? $_SESSION['project'] : 0;
  437. $projectModel = $app->dbh->query("SELECT `model` FROM " . TABLE_PROJECT . " WHERE `id` = '$projectID'")->fetch();
  438. if($projectModel) $customKey = 'project-' . $projectModel->model;
  439. }
  440. $customMenu = (isset($config->customMenu->{$customKey}) && !commonModel::isTutorialMode()) ? $config->customMenu->{$customKey}: array();
  441. if(!empty($customMenu) && is_string($customMenu) && substr($customMenu, 0, 1) === '[') $customMenu = json_decode($customMenu);
  442. if($module == 'my' && empty($config->global->scoreStatus)) unset($allMenu->score);
  443. return static::setMenuByConfig($allMenu, $customMenu, $module);
  444. }
  445. /**
  446. * 获取主菜单数据。
  447. * Get main menu data.
  448. *
  449. * @param bool $isHomeMenu
  450. * @access public
  451. * @return array
  452. */
  453. public static function getMainMenu($isHomeMenu = false)
  454. {
  455. return static::getModuleMenu('main', $isHomeMenu);
  456. }
  457. /**
  458. * 获取模块的筛选标签。
  459. * Get feature menu.
  460. *
  461. * @param string $module
  462. * @param string $method
  463. * @access public
  464. * @return array|null
  465. */
  466. public static function getFeatureMenu($module, $method)
  467. {
  468. global $app, $lang, $config;
  469. $app->loadLang($module);
  470. customModel::mergeFeatureBar($module, $method);
  471. $configKey = $config->global->flow . '_feature_' . $module . '_' . $method;
  472. $allMenu = isset($lang->$module->featureBar[$method]) ? $lang->$module->featureBar[$method] : null;
  473. $customMenu = '';
  474. if(!commonModel::isTutorialMode() && isset($config->customMenu->$configKey)) $customMenu = $config->customMenu->$configKey;
  475. if(!empty($customMenu) && is_string($customMenu)) $customMenu = json_decode($customMenu);
  476. return $allMenu ? static::setMenuByConfig($allMenu, $customMenu) : null;
  477. }
  478. /**
  479. * 将查询条件合并到筛选标签中。
  480. * Merge shortcut query in featureBar.
  481. *
  482. * @param string $module
  483. * @param string $method
  484. * @access public
  485. * @return void
  486. */
  487. public static function mergeFeatureBar($module, $method)
  488. {
  489. global $lang, $app, $config;
  490. if(!isset($lang->$module->featureBar[$method])) return;
  491. $queryModule = $module == 'execution' && $method == 'task' ? 'task' : $module;
  492. if($module == 'product') $queryModule = !empty($_SESSION['storyType']) ? $_SESSION['storyType'] : 'story';
  493. if(isset($config->$module->queryModule[$method])) $queryModule = $config->$module->queryModule[$method];
  494. if($module == 'execution' && $method == 'story') $queryModule = 'executionStory';
  495. $shortcuts = $app->dbQuery('select id, title from ' . TABLE_USERQUERY . " where (`account` = '{$app->user->account}' or `common` = '1') AND `module` = '{$queryModule}' AND `shortcut` = '1' order by id")->fetchAll();
  496. if($shortcuts)
  497. {
  498. $lang->$module->featureBar[$method]['QUERY'] = $lang->custom->common;
  499. foreach($shortcuts as $shortcut) $lang->custom->queryList[$shortcut->id] = $shortcut->title;
  500. }
  501. }
  502. /**
  503. * 获取必填字段。
  504. * Get required fields by config.
  505. *
  506. * @param object $moduleConfig
  507. * @access public
  508. * @return array
  509. */
  510. public function getRequiredFields($moduleConfig)
  511. {
  512. $requiredFields = array();
  513. foreach($moduleConfig as $method => $subConfig)
  514. {
  515. if(is_object($subConfig) && isset($subConfig->requiredFields)) $requiredFields[$method] = trim(str_replace(' ', '', $subConfig->requiredFields));
  516. }
  517. return $requiredFields;
  518. }
  519. /**
  520. * 获取表单必填字段。
  521. * Get form required fields.
  522. *
  523. * @param string $moduleName
  524. * @param string $method
  525. * @access public
  526. * @return array
  527. */
  528. public function getFormFields($moduleName, $method = '')
  529. {
  530. $fields = array();
  531. $moduleLang = $this->lang->{$moduleName};
  532. $customFields = $this->config->custom->fieldList;
  533. if(isset($customFields[$moduleName]))
  534. {
  535. $fieldList = isset($customFields[$moduleName][$method]) ? $customFields[$moduleName][$method] : $customFields[$moduleName];
  536. if(!is_string($fieldList)) return $fields;
  537. if($moduleName == 'user' && $method == 'edit') $this->app->loadConfig('user');
  538. foreach(explode(',', $fieldList) as $fieldName)
  539. {
  540. if($moduleName == 'user' && $method == 'edit' && strpos($this->config->user->contactField, $fieldName) === false && !in_array($fieldName, array('dept', 'role', 'group', 'email', 'commiter'))) continue;
  541. if($moduleName == 'project' && $fieldName == 'budget' && $this->config->vision == 'lite') continue;
  542. if($fieldName == 'comment') $fields[$fieldName] = $this->lang->comment;
  543. if(isset($moduleLang->{$fieldName}) && is_string($moduleLang->{$fieldName})) $fields[$fieldName] = $moduleLang->$fieldName;
  544. if($moduleName == 'program')
  545. {
  546. $fieldKey = substr($method, 0, 3) . ucfirst($fieldName);
  547. if(isset($moduleLang->{$fieldKey}) && is_string($moduleLang->{$fieldKey})) $fields[$fieldName] = $moduleLang->$fieldKey;
  548. }
  549. if($moduleName == 'execution' && in_array($fieldName, array('desc', 'PM', 'code')))
  550. {
  551. $fieldKey = 'exec' . ucfirst($fieldName);
  552. $fields[$fieldName] = $this->lang->execution->{$fieldKey};
  553. }
  554. }
  555. }
  556. return $fields;
  557. }
  558. /**
  559. * 获取需求概念。
  560. * Get UR and SR concept.
  561. *
  562. * @param int $key
  563. * @param string $lang
  564. * @access public
  565. * @return string|false
  566. */
  567. public function getURSRConcept($key, $lang = '')
  568. {
  569. if(empty($lang)) $lang = $this->app->getClientLang();
  570. return $this->dao->select('`value`')->from(TABLE_LANG)
  571. ->where('lang')->eq($lang)
  572. ->andWhere('module')->eq('custom')
  573. ->andWhere('section')->eq('URSRList')
  574. ->andWhere('`key`')->eq($key)
  575. ->fetch('value');
  576. }
  577. /**
  578. * 获取需求概念集合。
  579. * Get UR and SR pairs.
  580. *
  581. * @access public
  582. * @return array
  583. */
  584. public function getURSRPairs()
  585. {
  586. $lang = $this->app->getClientLang();
  587. $langData = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)
  588. ->where('lang')->eq($lang)
  589. ->andWhere('module')->eq('custom')
  590. ->andWhere('section')->eq('URSRList')
  591. ->fetchAll();
  592. if(empty($langData))
  593. {
  594. $URSR = $this->loadModel('setting')->getURSR();
  595. $langData = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)->where('`key`')->eq($URSR)->andWhere('module')->eq('custom')->andWhere('section')->eq('URSRList')->fetchAll();
  596. }
  597. $URSRPairs = array();
  598. foreach($langData as $content)
  599. {
  600. $value = json_decode($content->value);
  601. if(!$this->config->URAndSR && !$this->config->enableER) $URSRPairs[$content->key] = $value->SRName;
  602. if($this->config->URAndSR && !$this->config->enableER) $URSRPairs[$content->key] = $value->URName . '/' . $value->SRName;
  603. if($this->config->URAndSR && $this->config->enableER) $URSRPairs[$content->key] = $value->ERName . '/' . $value->URName . '/' . $value->SRName;
  604. }
  605. return $URSRPairs;
  606. }
  607. /**
  608. * 获取用需概念集合。
  609. * Get UR pairs.
  610. *
  611. * @access public
  612. * @return array
  613. */
  614. public function getURPairs()
  615. {
  616. $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('lang')->eq($this->app->clientLang)->fetchPairs();
  617. if(empty($URSRList))
  618. {
  619. $URSR = $this->loadModel('setting')->getURSR();
  620. $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('`key`')->eq($URSR)->fetchPairs();
  621. }
  622. $URPairs = array();
  623. foreach($URSRList as $key => $value)
  624. {
  625. $URSR = json_decode($value);
  626. $URPairs[$key] = $URSR->URName;
  627. }
  628. return $URPairs;
  629. }
  630. /**
  631. * 获取软需概念集合。
  632. * Get SR pairs.
  633. *
  634. * @access public
  635. * @return array
  636. */
  637. public function getSRPairs()
  638. {
  639. $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('lang')->eq($this->app->clientLang)->fetchPairs();
  640. if(empty($URSRList))
  641. {
  642. $URSR = $this->loadModel('setting')->getURSR();
  643. $URSRList = $this->dao->select('`key`,`value`')->from(TABLE_LANG)->where('module')->eq('custom')->andWhere('section')->eq('URSRList')->andWhere('`key`')->eq($URSR)->fetchPairs();
  644. }
  645. $SRPairs = array();
  646. foreach($URSRList as $key => $value)
  647. {
  648. $URSR = json_decode($value);
  649. $SRPairs[$key] = $URSR->SRName;
  650. }
  651. return $SRPairs;
  652. }
  653. /**
  654. * 获取需求概念列表。
  655. * Get UR and SR list.
  656. *
  657. * @access public
  658. * @return array
  659. */
  660. public function getURSRList()
  661. {
  662. $this->app->loadLang('custom');
  663. $lang = $this->app->getClientLang();
  664. $URSRDataList = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)
  665. ->where('lang')->eq($lang)
  666. ->andWhere('module')->eq('custom')
  667. ->andWhere('section')->eq('URSRList')
  668. ->fetchAll();
  669. if(empty($URSRDataList))
  670. {
  671. $URSR = $this->loadModel('setting')->getURSR();
  672. $URSRDataList = $this->dao->select('`key`, `value`, `system`')->from(TABLE_LANG)->where('`key`')->eq($URSR)->andWhere('module')->eq('custom')->andWhere('section')->eq('URSRList')->fetchAll();
  673. }
  674. $URSRList = array();
  675. foreach($URSRDataList as $URSRData)
  676. {
  677. $value = json_decode($URSRData->value);
  678. $URSRList[$URSRData->key] = new stdclass();
  679. $URSRList[$URSRData->key]->key = $URSRData->key;
  680. $URSRList[$URSRData->key]->ERName = $value->ERName;
  681. $URSRList[$URSRData->key]->SRName = $value->SRName;
  682. $URSRList[$URSRData->key]->URName = $value->URName;
  683. $URSRList[$URSRData->key]->system = $URSRData->system;
  684. }
  685. return $URSRList;
  686. }
  687. /**
  688. * 保存表单必填字段设置。
  689. * Save required fields.
  690. *
  691. * @param string $moduleName product|story|productplan|release|execution|task|bug|testcase|testsuite|testtask|testreport|caselib|doc|user|project|build
  692. * @param array $data
  693. * @access public
  694. * @return void
  695. */
  696. public function saveRequiredFields($moduleName, $data)
  697. {
  698. if(isset($this->config->systemDB->$moduleName)) unset($this->config->systemDB->$moduleName);
  699. if(isset($this->config->personalDB->$moduleName)) unset($this->config->personalDB->$moduleName);
  700. $this->loadModel($moduleName);
  701. $systemFields = $this->getRequiredFields($this->config->$moduleName);
  702. $requiredFields = array();
  703. if(!empty($systemFields))
  704. {
  705. foreach($systemFields as $method => $fields)
  706. {
  707. $optionFields = isset($this->config->custom->fieldList[$moduleName][$method]) ? explode(',', $this->config->custom->fieldList[$moduleName][$method]) : array();
  708. $systemFieldList = explode(',', $this->config->$moduleName->$method->requiredFields);
  709. foreach($optionFields as $field)
  710. {
  711. if(in_array($field, $systemFieldList))
  712. {
  713. $key = array_search($field, $systemFieldList);
  714. unset($systemFieldList[$key]);
  715. }
  716. }
  717. $systemField = implode(',', $systemFieldList);
  718. /* Keep the original required fields when the fields is empty. */
  719. if(!isset($data['requiredFields'][$method]))
  720. {
  721. $requiredFields[$method]['requiredFields'] = $systemField;
  722. continue;
  723. }
  724. $fields = implode(',', $data['requiredFields'][$method]);
  725. $systemFields = array_reverse(explode(',', $systemField));
  726. foreach($systemFields as $field)
  727. {
  728. $field = trim($field);
  729. if(strpos(",$fields,", ",$field,") === false) $fields = "{$field},{$fields}";
  730. }
  731. $requiredFields[$method]['requiredFields'] = trim($fields, ',');
  732. }
  733. }
  734. $this->loadModel('setting')->setItems("system.{$moduleName}@{$this->config->vision}", $requiredFields);
  735. }
  736. /**
  737. * 设置产品、项目和迭代概念。
  738. * Set product and project and sprint concept.
  739. *
  740. * @param string $sprintConcept
  741. * @access public
  742. * @return bool
  743. */
  744. public function setConcept($sprintConcept)
  745. {
  746. $this->loadModel('setting');
  747. $this->setting->setItem('system.custom.sprintConcept', $sprintConcept);
  748. $this->setting->setItem('system.custom.productProject', '0_' . $sprintConcept);
  749. /* Change block title. */
  750. $oldConfig = isset($this->config->custom->sprintConcept) ? $this->config->custom->sprintConcept : '0';
  751. $newConfig = $sprintConcept;
  752. foreach($this->config->executionCommonList as $executionCommonList)
  753. {
  754. if(!isset($executionCommonList[$oldConfig]) || !isset($executionCommonList[$newConfig]))
  755. {
  756. $this->setting->setItem('system.custom.sprintConcept', '0');
  757. $this->setting->setItem('system.custom.productProject', '0_0');
  758. continue;
  759. }
  760. $this->dao->update(TABLE_BLOCK)->set("`title` = REPLACE(`title`, '{$executionCommonList[$oldConfig]}', '{$executionCommonList[$newConfig]}')")->where('dashboard')->eq('execution')->exec();
  761. }
  762. return !dao::isError();
  763. }
  764. /**
  765. * 设置需求概念。
  766. * Set UR and SR concept.
  767. *
  768. * @param array $data
  769. * @access public
  770. * @return bool
  771. */
  772. public function setURAndSR($data)
  773. {
  774. $lang = $this->app->getClientLang();
  775. $maxKey = $this->dao->select('max(cast(`key` as DECIMAL)) as maxKey')->from(TABLE_LANG)
  776. ->where('section')->eq('URSRList')
  777. ->andWhere('module')->eq('custom')
  778. ->andWhere('lang')->eq($lang)
  779. ->fetch('maxKey');
  780. $maxKey = $maxKey ? (int)$maxKey : 1;
  781. /* If has custom UR and SR name. */
  782. foreach($data['SRName'] as $key => $SRName)
  783. {
  784. $URName = zget($data['URName'], $key, $this->lang->URCommon);
  785. $ERName = zget($data['ERName'], $key, $this->lang->ERCommon);
  786. if(!$URName || !$SRName || !$ERName) continue;
  787. $URSRList = new stdclass();
  788. $URSRList->ERName = $ERName;
  789. $URSRList->SRName = $SRName;
  790. $URSRList->URName = $URName;
  791. $value = json_encode($URSRList);
  792. $maxKey += 1;
  793. $this->setItem("$lang.custom.URSRList.{$maxKey}.0", $value);
  794. }
  795. return true;
  796. }
  797. /**
  798. * 编辑需求概念。
  799. * Edit UR and SR concept.
  800. *
  801. * @param int $key
  802. * @param string $lang zh-cn|zh-tw|en|fr|de
  803. * @param array $data
  804. * @access public
  805. * @return bool
  806. */
  807. public function updateURAndSR($key = 0, $lang = '', $data = array())
  808. {
  809. if(empty($lang)) $lang = $this->app->getClientLang();
  810. if(empty($data['SRName']) || empty($data['URName']) || empty($data['ERName'])) return false;
  811. $oldValue = $this->getURSRConcept($key, $lang);
  812. $oldValue = json_decode($oldValue);
  813. if(!$oldValue) return false;
  814. $URSRList = new stdclass();
  815. $URSRList->defaultERName = zget($oldValue, 'defaultERName', $oldValue->ERName);
  816. $URSRList->defaultSRName = zget($oldValue, 'defaultSRName', $oldValue->SRName);
  817. $URSRList->defaultURName = zget($oldValue, 'defaultURName', $oldValue->URName);
  818. $URSRList->ERName = empty($data['ERName']) ? $URSRList->defaultERName : $data['ERName'];
  819. $URSRList->SRName = empty($data['SRName']) ? $URSRList->defaultSRName : $data['SRName'];
  820. $URSRList->URName = empty($data['URName']) ? $URSRList->defaultURName : $data['URName'];
  821. $value = json_encode($URSRList);
  822. $this->dao->update(TABLE_LANG)->set('value')->eq($value)
  823. ->where('`key`')->eq($key)
  824. ->andWhere('section')->eq('URSRList')
  825. ->andWhere('lang')->eq($lang)
  826. ->andWhere('module')->eq('custom')
  827. ->exec();
  828. return true;
  829. }
  830. /**
  831. * 计算启用和不启用的功能。
  832. * Compute the enabled and disabled features.
  833. *
  834. * @access public
  835. * @return array
  836. */
  837. public function computeFeatures()
  838. {
  839. /* Check that the project features are enabled. */
  840. $disabledFeatures = array('program', 'productLine');
  841. foreach($this->config->custom->dataFeatures as $feature)
  842. {
  843. $function = 'has' . ucfirst($feature) . 'Data';
  844. if(!$this->$function())
  845. {
  846. if(in_array($feature, $this->config->custom->projectFeatures))
  847. {
  848. if(!isset($disabledFeatures['project'])) $disabledFeatures['project'] = array();
  849. $disabledFeatures['project'][] = $feature;
  850. }
  851. elseif(in_array($feature, array('waterfall', 'waterfallplus')))
  852. {
  853. $disabledFeatures[] = 'project' . ucfirst($feature);
  854. }
  855. else
  856. {
  857. $disabledFeatures[] = $feature;
  858. }
  859. }
  860. }
  861. if(!isset($disabledFeatures['project'])) $disabledFeatures['project'] = array();
  862. /* Check that the project features are enabled. */
  863. $enabledProjectFeatures = array();
  864. $disabledProjectFeatures = array();
  865. if(in_array($this->config->edition, array('max', 'ipd')))
  866. {
  867. foreach($this->config->custom->projectFeatures as $projectFeature)
  868. {
  869. $label = $this->lang->custom->projectFeatures[$projectFeature];
  870. if(in_array($projectFeature, $disabledFeatures['project']))
  871. {
  872. $disabledProjectFeatures[] = $label;
  873. }
  874. else
  875. {
  876. $enabledProjectFeatures[] = $label;
  877. }
  878. }
  879. }
  880. return array($disabledFeatures, $enabledProjectFeatures, $disabledProjectFeatures);
  881. }
  882. /**
  883. * 处理项目权限为继承项目集的项目权限。
  884. * process project priv within a program set.
  885. *
  886. * @access public
  887. * @return bool
  888. */
  889. public function processProjectAcl()
  890. {
  891. list($projectGroup, $programPM, $stakeholders) = $this->customTao->getDataForUpdateProjectAcl();
  892. $projectIDList = array();
  893. foreach($projectGroup as $projects) $projectIDList = array_merge($projectIDList, array_keys($projects));
  894. $executionGroup = $this->dao->select('project,id')->from(TABLE_EXECUTION)->where('project')->in($projectIDList)->fetchGroup('project', 'id');
  895. $this->loadModel('user');
  896. $this->loadModel('action');
  897. $this->loadModel('personnel');
  898. foreach($projectGroup as $projects)
  899. {
  900. foreach($projects as $project)
  901. {
  902. $PM = zget($programPM, $project->parent, '');
  903. $stakeholder = zget($stakeholders, $project->parent, '');
  904. if($stakeholder) $stakeholder = implode(',', array_keys($stakeholder));
  905. $whitelist = rtrim($project->whitelist . ',' . $PM . ',' . $stakeholder);
  906. $whitelist = explode(',', $whitelist);
  907. $whitelist = array_filter(array_unique($whitelist));
  908. $whitelist = implode(',', $whitelist);
  909. $data = new stdclass();
  910. $data->acl = 'private';
  911. $data->whitelist = $whitelist;
  912. $this->dao->update(TABLE_PROJECT)->data($data)->where('id')->eq($project->id)->exec();
  913. $whitelist = explode(',', $whitelist);
  914. $this->personnel->updateWhitelist($whitelist, 'project', $project->id);
  915. $this->user->updateUserView(array($project->id), 'project');
  916. if(zget($executionGroup, $project->id, ''))
  917. {
  918. $executions = zget($executionGroup, $project->id);
  919. $executionPairs = array();
  920. foreach($executions as $executionID => $execution) $executionPairs[$executionID] = $executionID;
  921. $this->user->updateUserView($executionPairs, 'sprint');
  922. }
  923. $changes = common::createChanges($project, $data);
  924. $actionID = $this->action->create('project', $project->id, 'SwitchToLight');
  925. $this->action->logHistory($actionID, $changes);
  926. }
  927. }
  928. return !dao::isError();
  929. }
  930. /**
  931. * 根据管理模式禁用相关功能。
  932. * Disable related features based on the management mode.
  933. *
  934. * @param string $mode
  935. * @access public
  936. * @return void
  937. */
  938. public function disableFeaturesByMode($mode)
  939. {
  940. $disabledFeatures = '';
  941. if($mode == 'light')
  942. {
  943. /* Check whether the product or project data in the system is empty. */
  944. foreach($this->config->custom->dataFeatures as $feature)
  945. {
  946. $function = 'has' . ucfirst($feature) . 'Data';
  947. if(!$this->$function())
  948. {
  949. if(in_array($feature, $this->config->custom->projectFeatures)) $feature = 'project' . ucfirst($feature);
  950. /* If the data is empty, this feature is disabled. */
  951. $disabledFeatures .= "$feature,";
  952. }
  953. }
  954. $disabledFeatures .= 'productTrack,productRoadmap';
  955. }
  956. /* Save the features that are disable to the config. */
  957. $disabledFeatures = rtrim($disabledFeatures, ',');
  958. $this->loadModel('setting')->setItem('system.common.disabledFeatures', $disabledFeatures);
  959. $URAndSR = strpos(",$disabledFeatures,", ',productUR,') === false ? '1' : '0';
  960. $this->setting->setItem('system.custom.URAndSR', $URAndSR);
  961. $disableER = strpos(",$disabledFeatures,", ',productER,') !== false;
  962. $enableER = (!$URAndSR || $disableER) ? '0' : '1';
  963. $this->setting->setItem('system.custom.enableER', $enableER);
  964. $this->processMeasrecordCron();
  965. }
  966. /**
  967. * 检查系统中是否有业务需求数据。
  968. * Check whether there is epic data in the system.
  969. *
  970. * @access public
  971. * @return int
  972. */
  973. public function hasProductERData()
  974. {
  975. return (int)$this->dao->select('*')->from(TABLE_STORY)->where('type')->eq('epic')->andWhere('deleted')->eq('0')->count();
  976. }
  977. /**
  978. * 检查系统中是否有用户需求数据。
  979. * Check whether there is requirement data in the system.
  980. *
  981. * @access public
  982. * @return int
  983. */
  984. public function hasProductURData()
  985. {
  986. return (int)$this->dao->select('*')->from(TABLE_STORY)->where('type')->eq('requirement')->andWhere('deleted')->eq('0')->count();
  987. }
  988. /**
  989. * 检查系统中是否有瀑布项目数据。
  990. * Check whether there is waterfall project data in the system.
  991. *
  992. * @access public
  993. * @return int
  994. */
  995. public function hasWaterfallData()
  996. {
  997. return (int)$this->dao->select('*')->from(TABLE_PROJECT)->where('model')->eq('waterfall')->andWhere('deleted')->eq('0')->count();
  998. }
  999. /**
  1000. * 检查系统中是否有融合项目数据。
  1001. * Check whether there is waterfallplus project data in the system.
  1002. *
  1003. * @access public
  1004. * @return int
  1005. */
  1006. public function hasWaterfallplusData()
  1007. {
  1008. return (int)$this->dao->select('*')->from(TABLE_PROJECT)->where('model')->eq('waterfallplus')->andWhere('deleted')->eq('0')->count();
  1009. }
  1010. /**
  1011. * 检查系统中是否有资产库数据。
  1012. * Check whether there is assetlib data in the system.
  1013. *
  1014. * @access public
  1015. * @return int
  1016. */
  1017. public function hasAssetlibData()
  1018. {
  1019. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_ASSETLIB)->where('deleted')->eq(0)->count();
  1020. return 0;
  1021. }
  1022. /**
  1023. * 检查系统中是否有问题数据。
  1024. * Check whether there is issue data in the system.
  1025. *
  1026. * @access public
  1027. * @return int
  1028. */
  1029. public function hasIssueData()
  1030. {
  1031. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_ISSUE)->where('deleted')->eq('0')->count();
  1032. return 0;
  1033. }
  1034. /**
  1035. * 检查系统中是否有风险数据。
  1036. * Check whether there is risk data in the system.
  1037. *
  1038. * @access public
  1039. * @return int
  1040. */
  1041. public function hasRiskData()
  1042. {
  1043. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_RISK)->where('deleted')->eq('0')->count();
  1044. return 0;
  1045. }
  1046. /**
  1047. * 检查系统中是否有培训计划数据。
  1048. * Check whether there is gapanalysis data in the system.
  1049. *
  1050. * @access public
  1051. * @return int
  1052. */
  1053. public function hasGapanalysisData()
  1054. {
  1055. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_GAPANALYSIS)->where('deleted')->eq('0')->count();
  1056. return 0;
  1057. }
  1058. /**
  1059. * 检查系统中是否有调研计划数据。
  1060. * Check whether there is researchplan data in the system.
  1061. *
  1062. * @access public
  1063. * @return int
  1064. */
  1065. public function hasResearchplanData()
  1066. {
  1067. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_RESEARCHPLAN)->where('deleted')->eq('0')->count();
  1068. return 0;
  1069. }
  1070. /**
  1071. * 检查系统中是否有机会数据。
  1072. * Check whether there is opportunity data in the system.
  1073. *
  1074. * @access public
  1075. * @return int
  1076. */
  1077. public function hasOpportunityData()
  1078. {
  1079. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_OPPORTUNITY)->where('deleted')->eq('0')->count();
  1080. return 0;
  1081. }
  1082. /**
  1083. * 检查系统中是否有敏捷项目的会议数据。
  1084. * Check whether there is meeting data in the system.
  1085. *
  1086. * @access public
  1087. * @return int
  1088. */
  1089. public function hasMeetingData()
  1090. {
  1091. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_MEETING)->where('deleted')->eq('0')->count();
  1092. return 0;
  1093. }
  1094. /**
  1095. * 检查系统中是否有度量数据。
  1096. * Check whether there is measrecord data in the system.
  1097. *
  1098. * @access public
  1099. * @return int
  1100. */
  1101. public function hasMeasrecordData()
  1102. {
  1103. return 0;
  1104. }
  1105. /**
  1106. * 检查系统中是否有审计数据。
  1107. * Check whether there is auditplan data in the system.
  1108. *
  1109. * @access public
  1110. * @return int
  1111. */
  1112. public function hasAuditplanData()
  1113. {
  1114. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_AUDITPLAN)->where('deleted')->eq('0')->count();
  1115. return 0;
  1116. }
  1117. /**
  1118. * 检查系统中是否有项目活动数据。
  1119. * Check whether there is process data in the system.
  1120. *
  1121. * @access public
  1122. * @return int
  1123. */
  1124. public function hasProcessData()
  1125. {
  1126. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_PROGRAMACTIVITY)->where('deleted')->eq('0')->count();
  1127. return 0;
  1128. }
  1129. /**
  1130. * 检查系统中是否有交付物数据。
  1131. * Check whether there is deliverable data in the system.
  1132. *
  1133. * @access public
  1134. * @return int
  1135. */
  1136. public function hasDeliverableData()
  1137. {
  1138. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_PROJECTDELIVERABLE)->count();
  1139. return 0;
  1140. }
  1141. /**
  1142. * 检查系统中是否有评审数据,有交付物就算有评审。
  1143. * Check whether there is review data in the system.
  1144. *
  1145. * @access public
  1146. * @return int
  1147. */
  1148. public function hasReviewData()
  1149. {
  1150. if(in_array($this->config->edition, array('max', 'ipd')))
  1151. {
  1152. $reviewCount = (int)$this->dao->select('*')->from(TABLE_REVIEW)->where('deleted')->eq('0')->count();
  1153. $deliverableCount = (int)$this->dao->select('*')->from(TABLE_DELIVERABLE)->where('deleted')->eq('0')->count();
  1154. return $reviewCount + $deliverableCount;
  1155. }
  1156. return 0;
  1157. }
  1158. /**
  1159. * 检查系统中是否有变更管理数据。
  1160. * Check whether there is projectchange data in the system.
  1161. *
  1162. * @access public
  1163. * @return int
  1164. */
  1165. public function hasChangeData()
  1166. {
  1167. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_PROJECTCHANGE)->where('deleted')->eq('0')->count();
  1168. return 0;
  1169. }
  1170. /**
  1171. * 检查系统中是否有基线数据。
  1172. * Check whether there is cm data in the system.
  1173. *
  1174. * @access public
  1175. * @return int
  1176. */
  1177. public function hasCmData()
  1178. {
  1179. if(in_array($this->config->edition, array('max', 'ipd'))) return (int)$this->dao->select('*')->from(TABLE_OBJECT)->where('deleted')->eq('0')->andWhere('type')->eq('taged')->count();
  1180. return 0;
  1181. }
  1182. /**
  1183. * 处理定时任务。
  1184. * Process measrecord cron.
  1185. *
  1186. * @access public
  1187. * @return void
  1188. */
  1189. public function processMeasrecordCron()
  1190. {
  1191. $this->loadModel('setting');
  1192. $closedFeatures = $this->setting->getItem('owner=system&module=common&section=&key=closedFeatures');
  1193. $disabledFeatures = $this->setting->getItem('owner=system&module=common&section=&key=disabledFeatures');
  1194. $disabledFeatures = $disabledFeatures . ',' . $closedFeatures;
  1195. $hasProjectMeasrecord = strpos(",{$disabledFeatures},", ',projectMeasrecord,') === false;
  1196. /* Determine whether the cron is enabled based on whether the feature is disabled. */
  1197. $cronStatus = 'normal';
  1198. if(!$hasProjectMeasrecord) $cronStatus = 'stop';
  1199. /* Update the status of the cron. */
  1200. $this->loadModel('cron');
  1201. $cron = $this->dao->select('id,status')->from(TABLE_CRON)->where('command')->like('%methodName=initCrontabQueue')->fetch();
  1202. if($cron && $cron->status != $cronStatus) $this->cron->changeStatus($cron->id, $cronStatus);
  1203. $cron = $this->dao->select('id,status')->from(TABLE_CRON)->where('command')->like('%methodName=execCrontabQueue')->fetch();
  1204. if($cron && $cron->status != $cronStatus) $this->cron->changeStatus($cron->id, $cronStatus);
  1205. }
  1206. }