model.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. <?php
  2. /**
  3. * The model file of workflowdatasource module of ZDOO.
  4. *
  5. * @copyright Copyright 2009-2016 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
  6. * @license 商业软件,非开源软件
  7. * @author Gang Liu <liugang@cnezsoft.com>
  8. * @package workflow
  9. * @version $Id$
  10. * @link http://www.zdoo.com
  11. */
  12. class workflowdatasourceModel extends model
  13. {
  14. /**
  15. * Get apps of datasource.
  16. *
  17. * @access public
  18. * @return array
  19. */
  20. public function getApps()
  21. {
  22. $apps = $this->loadModel('workflow', 'flow')->getApps(false);
  23. return arrayUnion($apps, $this->lang->workflowdatasource->apps);
  24. }
  25. /**
  26. * Get modules of an app.
  27. *
  28. * @access public
  29. * @return array
  30. */
  31. public function getModules()
  32. {
  33. $modules = array();
  34. if(isset($this->config->workflowdatasource->methods) && is_array($this->config->workflowdatasource->methods))
  35. {
  36. foreach($this->config->workflowdatasource->methods as $module => $methods)
  37. {
  38. $this->app->loadLang($module);
  39. $modules[$module] = isset($this->lang->$module->common) ? $this->lang->$module->common : $module;
  40. }
  41. }
  42. if($this->config->vision == 'lite') unset($modules['branch'], $modules['bug'], $modules['build'], $modules['productplan'], $modules['testcase'], $modules['caselib'], $modules['testtask']);
  43. return $modules;
  44. }
  45. /**
  46. * Get methods of a module.
  47. *
  48. * @param string $module
  49. * @access public
  50. * @return array
  51. */
  52. public function getModuleMethods($module)
  53. {
  54. if(empty($this->config->workflowdatasource->methods[$module]) || !is_array($this->config->workflowdatasource->methods[$module])) return array();
  55. $methods = array();
  56. foreach($this->config->workflowdatasource->methods[$module] as $method) $methods[] = array('text' => $method, 'value' => $method);
  57. return $methods;
  58. }
  59. /**
  60. * Get comments of a method.
  61. *
  62. * @param string $module
  63. * @param string $method
  64. * @param int $methodDescOnly
  65. * @access public
  66. * @return array
  67. */
  68. public function getMethodComments($module, $method, $methodDescOnly = false)
  69. {
  70. $model = $this->loadModel($module);
  71. $methodReflect = new ReflectionMethod($model, $method);
  72. $comment = $methodReflect->getDocComment();
  73. /* Strip the opening and closing tags of the docblock. */
  74. $comment = substr($comment, 3, -2);
  75. /* Split into arrays of lines. */
  76. $comment = preg_split('/\r?\n\r?/', $comment);
  77. /* Group the lines together by @tags */
  78. $blocks = array();
  79. $b = -1;
  80. foreach ($comment as $line)
  81. {
  82. /* Trim asterisks and whitespace from the beginning and whitespace from the end of lines. */
  83. $line = ltrim(rtrim($line), "* \t\n\r\0\x0B");
  84. if (isset($line[1]) && $line[0] == '@' && ctype_alpha($line[1]))
  85. {
  86. $b++;
  87. $blocks[] = array();
  88. } else if($b == -1) {
  89. $b = 0;
  90. $blocks[] = array();
  91. }
  92. $blocks[$b][] = $line;
  93. }
  94. $result = array();
  95. /* Parse the blocks */
  96. foreach ($blocks as $block => $body)
  97. {
  98. $body = trim(implode("\n", $body));
  99. if($block == 0 && !(isset($body[1]) && $body[0] == '@' && ctype_alpha($body[1])))
  100. {
  101. /* This is the description block */
  102. if($methodDescOnly) return $body;
  103. $result['desc'] = $body;
  104. continue;
  105. }
  106. else
  107. {
  108. /* This block is tagged */
  109. if(preg_match('/^@[a-z0-9_]+/', $body, $matches))
  110. {
  111. $tag = substr($matches[0], 1);
  112. $body = substr($body, strlen($tag)+2);
  113. if($tag == 'param')
  114. {
  115. $parts = preg_split('/\s+/', trim($body), 3);
  116. $parts = array_pad($parts, 3, null);
  117. $property = array('type', 'var', 'desc');
  118. $param = array_combine($property, $parts);
  119. $param['var'] = substr($param['var'], 1);
  120. $result['param'][$param['var']] = $param;
  121. }
  122. else
  123. {
  124. $result[$tag][] = $body;
  125. }
  126. }
  127. }
  128. }
  129. return $result;
  130. }
  131. /**
  132. * Get default params of a method.
  133. *
  134. * @param string $module
  135. * @param string $method
  136. * @access public
  137. * @return array
  138. */
  139. public function getDefaultParams($module, $method)
  140. {
  141. $params = array();
  142. $defaultValueFiles = glob($this->app->getTmpRoot() . "defaultvalue/*.php");
  143. if($defaultValueFiles) foreach($defaultValueFiles as $file) include $file;
  144. $model = $this->loadModel($module);
  145. $methodReflect = new reflectionMethod($model, $method);
  146. foreach($methodReflect->getParameters() as $param)
  147. {
  148. $name = $param->getName();
  149. $default = '';
  150. if(isset($paramDefaultValue[$module][$method][$name]))
  151. {
  152. $default = $paramDefaultValue[$module][$method][$name];
  153. }
  154. elseif($param->isDefaultValueAvailable())
  155. {
  156. $default = $param->getDefaultValue();
  157. }
  158. $params[$name] = $default;
  159. }
  160. return $params;
  161. }
  162. /**
  163. * Get field pairs of a view.
  164. *
  165. * @param string $sql
  166. * @access public
  167. * @return array
  168. */
  169. public function getViewFields($sql)
  170. {
  171. if(empty($sql)) return array('');
  172. $view = 'view_datasource_tmp';
  173. $sql = "CREATE OR REPLACE VIEW $view AS $sql";
  174. $this->dbh->query($sql);
  175. $sqlFields = $this->dbh->query("DESC $view")->fetchAll();
  176. $i = 1;
  177. $fields = array();
  178. foreach($sqlFields as $field)
  179. {
  180. $fields["field{$i}"] = $field->Field;
  181. $i++;
  182. }
  183. $sql = "DROP VIEW $view";
  184. $this->dbh->query($sql);
  185. return $fields;
  186. }
  187. /**
  188. * Get a datasource by id.
  189. *
  190. * @param int $id
  191. * @access public
  192. * @return objcet
  193. */
  194. public function getByID($id)
  195. {
  196. $datasource = $this->dao->select('*')->from(TABLE_WORKFLOWDATASOURCE)->where('id')->eq($id)->fetch();
  197. if($datasource)
  198. {
  199. $datasource->options = array();
  200. $datasource->app = '';
  201. $datasource->module = '';
  202. $datasource->method = '';
  203. $datasource->methodDesc = '';
  204. $datasource->params = array();
  205. $datasource->sql = '';
  206. $datasource->lang = '';
  207. if($datasource->type == 'option')
  208. {
  209. $datasource->options = json_decode($datasource->datasource, true);
  210. }
  211. elseif($datasource->type == 'system')
  212. {
  213. $data = json_decode($datasource->datasource);
  214. $datasource->app = $data->app;
  215. $datasource->module = $data->module;
  216. $datasource->method = $data->method;
  217. $datasource->methodDesc = $data->methodDesc;
  218. $datasource->params = $data->params;
  219. }
  220. elseif($datasource->type == 'sql')
  221. {
  222. $datasource->sql = $datasource->datasource;
  223. }
  224. elseif($datasource->type == 'lang')
  225. {
  226. $datasource->lang = $datasource->datasource;
  227. }
  228. elseif($datasource->type == 'func')
  229. {
  230. }
  231. elseif($datasource->type == 'category')
  232. {
  233. }
  234. }
  235. return $datasource;
  236. }
  237. /**
  238. * Get datasource list.
  239. *
  240. * @param string $orderBy
  241. * @param objcet $pager
  242. * @access public
  243. * @return array
  244. */
  245. public function getList($orderBy = 'id_desc', $pager = null)
  246. {
  247. return $this->dao->select('*')->from(TABLE_WORKFLOWDATASOURCE)
  248. ->where(1)
  249. ->beginIF(!empty($this->config->vision))->andWhere('vision')->eq($this->config->vision)->fi()
  250. ->beginIF($this->config->systemMode == 'light')->andWhere('code')->notin($this->config->workflowdatasource->notShowInLightMode)->fi()
  251. ->beginIF(!helper::hasFeature('project_cm'))->andWhere('code')->notlike('baseline%')->fi()
  252. ->beginIF(!helper::hasFeature('project_change'))->andWhere('code')->notlike('projectchange%')->fi()
  253. ->beginIF(!helper::hasFeature('project_risk'))->andWhere('code')->notlike('risk%')->fi()
  254. ->beginIF(!helper::hasFeature('project_issue'))->andWhere('code')->notlike('issue%')->fi()
  255. ->beginIF(!helper::hasFeature('project_opportunity'))->andWhere('code')->notlike('opportunity%')->fi()
  256. ->beginIF(!helper::hasFeature('program') && $this->config->edition != 'ipd')->andWhere('code')->notlike('charter%')->fi()
  257. ->orderBy($orderBy)
  258. ->page($pager)
  259. ->fetchAll('id', false);
  260. }
  261. /**
  262. * Get datasource pairs.
  263. *
  264. * @param string $params
  265. * @access public
  266. * @return array
  267. */
  268. public function getPairs($params = '')
  269. {
  270. $datasources = $this->dao->select('id, name')->from(TABLE_WORKFLOWDATASOURCE)
  271. ->where(1)
  272. ->beginIF(!empty($this->config->vision))->andWhere('vision')->eq($this->config->vision)->fi()
  273. ->fetchPairs();
  274. foreach($this->lang->workflowdatasource->options as $key => $name) $datasources[$key] = $name;
  275. if(strpos($params, 'noempty') === false) $datasources = arrayUnion(array('' => ''), $datasources);
  276. return $datasources;
  277. }
  278. /**
  279. * Get datasource id pairs which type is category.
  280. *
  281. * @access public
  282. * @return array
  283. */
  284. public function getCategoryDatasources()
  285. {
  286. return $this->dao->select('id')->from(TABLE_WORKFLOWDATASOURCE)->where('type')->eq('category')->fetchPairs();
  287. }
  288. /**
  289. * Create a datasource.
  290. *
  291. * @access public
  292. * @return bool | int
  293. */
  294. public function create()
  295. {
  296. $datasource = fixer::input('post')
  297. ->setDefault('datasource', '')
  298. ->add('vision', $this->config->vision)
  299. ->add('createdBy', $this->app->user->account)
  300. ->add('createdDate', helper::now())
  301. ->skipSpecial('sql')
  302. ->get();
  303. $datasource->keyField = html_entity_decode($datasource->keyField, ENT_QUOTES);
  304. $datasource->valueField = html_entity_decode($datasource->valueField, ENT_QUOTES);
  305. $result = $this->fix($datasource);
  306. if(!empty($result))
  307. {
  308. dao::$errors = $result;
  309. return false;
  310. }
  311. $this->dao->insert(TABLE_WORKFLOWDATASOURCE)->data($datasource, $skip = 'options, app, module, method, methodDesc, paramName, paramType, paramDesc, paramValue, sql, lang')
  312. ->autoCheck()
  313. ->checkIF($datasource->type != 'category' && $datasource->type != 'func', 'datasource', 'notempty')
  314. ->checkIF($datasource->code, 'code', 'unique')
  315. ->exec();
  316. if(dao::isError()) return false;
  317. $datasourceID = $this->dao->lastInsertId();
  318. if($datasource->type == 'sql')
  319. {
  320. try
  321. {
  322. $view = "view_datasource_$datasourceID";
  323. $fields = $this->getViewFields($datasource->sql);
  324. $fields = implode(',', array_keys($fields));
  325. $sql = "CREATE VIEW $view ($fields) AS $datasource->sql";
  326. $this->dbh->query($sql);
  327. $this->dao->update(TABLE_WORKFLOWDATASOURCE)->set('view')->eq($view)->where('id')->eq($datasourceID)->exec();
  328. }
  329. catch(PDOException $exception)
  330. {
  331. $this->delete($datasourceID);
  332. dao::$errors = $exception->getMessage();
  333. }
  334. }
  335. return $datasourceID;
  336. }
  337. /**
  338. * Update a datasource.
  339. *
  340. * @param int $id
  341. * @access public
  342. * @return bool | array
  343. */
  344. public function update($id)
  345. {
  346. $oldDatasource = $this->getByID($id);
  347. if($oldDatasource->buildin) return false;
  348. $datasource = fixer::input('post')
  349. ->setDefault('datasource', '')
  350. ->add('editedBy', $this->app->user->account)
  351. ->add('editedDate', helper::now())
  352. ->skipSpecial('sql')
  353. ->get();
  354. $datasource->keyField = html_entity_decode($datasource->keyField, ENT_QUOTES);
  355. $datasource->valueField = html_entity_decode($datasource->valueField, ENT_QUOTES);
  356. $result = $this->fix($datasource);
  357. if(!empty($result))
  358. {
  359. dao::$errors = $result;
  360. return false;
  361. }
  362. if($datasource->type == 'sql' && $datasource->datasource != $oldDatasource->datasource)
  363. {
  364. try
  365. {
  366. $sqls = array();
  367. $fields = $this->getViewFields($datasource->datasource);
  368. $fields = implode(',', array_keys($fields));
  369. $view = "view_datasource_$id";
  370. $sqls[] = "DROP VIEW IF EXISTS $view";
  371. $sqls[] = "CREATE VIEW $view ($fields) AS $datasource->datasource";
  372. foreach($sqls as $sql) $this->dbh->query($sql);
  373. $datasource->view = $view;
  374. }
  375. catch(PDOException $exception)
  376. {
  377. dao::$errors = $exception->getMessage();
  378. return false;
  379. }
  380. }
  381. $this->dao->update(TABLE_WORKFLOWDATASOURCE)->data($datasource, $skip = 'options, app, module, method, methodDesc, paramName, paramType, paramDesc, paramValue, sql, lang')
  382. ->where('id')->eq($id)
  383. ->autoCheck()
  384. ->checkIF($datasource->type != 'category' && $datasource->type != 'func', 'datasource', 'notempty')
  385. ->checkIF($datasource->code, 'code', 'unique', "id!={$id}")
  386. ->exec();
  387. unset($oldDatasource->options);
  388. unset($datasource->options);
  389. return commonModel::createChanges($oldDatasource, $datasource);
  390. }
  391. /**
  392. * Fix a datasource.
  393. *
  394. * @param object $datasource
  395. * @access public
  396. * @return array
  397. */
  398. public function fix($datasource)
  399. {
  400. $errors = array();
  401. if(!$datasource->name) $errors['name'] = sprintf($this->lang->error->notempty, $this->lang->workflowdatasource->name);
  402. if($datasource->type == 'option')
  403. {
  404. $options = array();
  405. foreach($datasource->options['value'] as $key => $value)
  406. {
  407. if(empty($value)) continue;
  408. if(empty($datasource->options['text'][$key])) continue;
  409. $options[$value] = $datasource->options['text'][$key];
  410. }
  411. if(empty($options)) $errors['options'] = $this->lang->workflowdatasource->error->emptyOptions;
  412. $datasource->datasource = helper::jsonEncode($options);
  413. }
  414. elseif($datasource->type == 'system')
  415. {
  416. if(!$datasource->method) $errors['method'] = sprintf($this->lang->error->notempty, $this->lang->workflowdatasource->method);
  417. if(!$datasource->module) $errors['module'] = sprintf($this->lang->error->notempty, $this->lang->workflowdatasource->module);
  418. $params = array();
  419. if($this->post->paramName)
  420. {
  421. foreach($this->post->paramName as $key => $name)
  422. {
  423. $param = new stdclass();
  424. $param->name = $name;
  425. $param->type = $this->post->paramType[$key];
  426. $param->desc = $this->post->paramDesc[$key];
  427. $param->value = $this->post->paramValue[$key];
  428. $params[$key] = $param;
  429. }
  430. }
  431. $data = new stdclass();
  432. $data->app = $datasource->app;
  433. $data->module = $datasource->module;
  434. $data->method = $datasource->method;
  435. $data->methodDesc = $datasource->methodDesc;
  436. $data->params = $params;
  437. $datasource->datasource = helper::jsonEncode($data);
  438. }
  439. elseif($datasource->type == 'sql')
  440. {
  441. if(empty($datasource->sql)) $errors['sql'] = sprintf($this->lang->error->notempty, $this->lang->workflowdatasource->sql);
  442. if(empty($datasource->keyField)) $errors['keyField'] = sprintf($this->lang->error->notempty, $this->lang->workflowdatasource->key);
  443. if(empty($datasource->valueField)) $errors['valueField'] = sprintf($this->lang->error->notempty, $this->lang->workflowdatasource->value);
  444. $datasource->datasource = $datasource->sql;
  445. }
  446. elseif($datasource->type == 'lang')
  447. {
  448. $datasource->datasource = $datasource->lang;
  449. }
  450. elseif($datasource->type == 'func')
  451. {
  452. }
  453. return $errors;
  454. }
  455. /**
  456. * Delete a datasource.
  457. *
  458. * @param int $id
  459. * @param int $null
  460. * @access public
  461. * @return bool
  462. */
  463. public function delete($id, $null = null)
  464. {
  465. try
  466. {
  467. $view = "view_datasource_$id";
  468. $sql = "DROP VIEW IF EXISTS $view";
  469. $this->dbh->query($sql);
  470. $this->dao->delete()->from(TABLE_WORKFLOWDATASOURCE)->where('id')->eq($id)->exec();
  471. }
  472. catch(PDOException $exception)
  473. {
  474. dao::$errors = $exception->getMessage();
  475. }
  476. return !dao::isError();
  477. }
  478. /**
  479. * 检查动作是否可以点击。
  480. * Check if the action is clickable.
  481. *
  482. * @param object $datasource
  483. * @param string $action
  484. * @access public
  485. * @return bool
  486. */
  487. public function isClickable($datasource, $action)
  488. {
  489. $action = strtolower($action);
  490. if(!common::hasPriv('workflowdatasource', $action)) return false;
  491. if($action == 'edit') return $datasource->buildin != 1;
  492. if($action == 'delete') return $datasource->buildin != 1;
  493. if($action == 'manage') return $datasource->buildin != 1 && $datasource->type == 'category' && common::hasPriv('tree', 'browse');
  494. return true;
  495. }
  496. }