model.php 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. <?php
  2. /**
  3. * The model file of api module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Chunsheng Wang <chunsheng@cnezsoft.com>
  8. * @package api
  9. * @version $Id$
  10. * @link https://www.zentao.net
  11. */
  12. class apiModel extends model
  13. {
  14. /* Status. */
  15. const STATUS_DOING = 'doing';
  16. const STATUS_DONE = 'done';
  17. const STATUS_HIDDEN = 'hidden';
  18. /* Scope. */
  19. const SCOPE_QUERY = 'query';
  20. const SCOPE_FORM_DATA = 'formData';
  21. const SCOPE_PATH = 'path';
  22. const SCOPE_BODY = 'body';
  23. const SCOPE_HEADER = 'header';
  24. const SCOPE_COOKIE = 'cookie';
  25. /* Params. */
  26. const PARAMS_TYPE_CUSTOM = 'custom';
  27. /**
  28. * 发布接口。
  29. * Create release.
  30. *
  31. * @param object $formData
  32. * @access public
  33. * @return bool
  34. */
  35. public function publishLib($formData)
  36. {
  37. /* Get lib modules list. */
  38. $modules = $this->dao->select('*')->from(TABLE_MODULE)
  39. ->where('root')->eq((int)$formData->lib)
  40. ->andWhere('type')->eq('api')
  41. ->andWhere('deleted')->eq(0)
  42. ->orderBy('grade desc, `order`')
  43. ->fetchAll();
  44. /* Get all api list. */
  45. $apis = $this->dao->select('id,version')->from(TABLE_API)
  46. ->where('lib')->eq($formData->lib)
  47. ->andWhere('deleted')->eq(0)
  48. ->fetchAll();
  49. /* Get all struct list. */
  50. $structs = $this->dao->select('id,version')->from(TABLE_APISTRUCT)
  51. ->where('lib')->eq($formData->lib)
  52. ->andWhere('deleted')->eq(0)
  53. ->fetchAll();
  54. $snap = array('modules' => $modules, 'apis' => $apis, 'structs' => $structs);
  55. $formData->snap = json_encode($snap);
  56. $this->dao->insert(TABLE_API_LIB_RELEASE)->data($formData)
  57. ->autoCheck()
  58. ->batchCheck($this->config->api->createrelease->requiredFields, 'notempty')
  59. ->exec();
  60. return !dao::isError();
  61. }
  62. /**
  63. * 删除一条发布。
  64. * Delete a lib publish.
  65. *
  66. * @param int $id
  67. * @access public
  68. * @return bool
  69. */
  70. public function deleteRelease($id)
  71. {
  72. $this->dao->delete()->from(TABLE_API_LIB_RELEASE)->where('id')->eq($id)->exec();
  73. return !dao::isError();
  74. }
  75. /**
  76. * 创建一个接口。
  77. * Create an api doc.
  78. *
  79. * @param object $formData
  80. * @access public
  81. * @return int|false
  82. */
  83. public function create($formData)
  84. {
  85. $this->dao->insert(TABLE_API)->data($formData)
  86. ->autoCheck()
  87. ->batchCheck($this->config->api->create->requiredFields, 'notempty')
  88. ->check('title', 'unique', "lib = $formData->lib AND module = $formData->module")
  89. ->check('path', 'unique', "lib = $formData->lib AND module = $formData->module AND method = '$formData->method'")
  90. ->exec();
  91. if(dao::isError()) return false;
  92. /* 维护历史记录。 */
  93. $apiID = $this->dao->lastInsertID();
  94. $this->loadModel('action')->create('api', $apiID, 'Created', '', '', '', false);
  95. /* 维护接口文档的历史版本。 */
  96. $formData->id = $apiID;
  97. $apiSpec = $this->getApiSpecByData($formData);
  98. $this->dao->insert(TABLE_API_SPEC)->data($apiSpec)->exec();
  99. return $apiID;
  100. }
  101. /**
  102. * 更新一个接口。
  103. * Update an api doc.
  104. *
  105. * @param object $formData
  106. * @access public
  107. * @return bool
  108. */
  109. public function update($formData)
  110. {
  111. $oldApi = $this->dao->findByID($formData->id)->from(TABLE_API)->fetch();
  112. if(empty($formData->lib)) $formData->lib = $oldApi->lib;
  113. if(!empty($formData->editedDate) && $oldApi->editedDate != $formData->editedDate)
  114. {
  115. /* 如果提交之前已有其他人变更接口则提示错误信息。 */
  116. dao::$errors['message'][] = $this->lang->error->editedByOther;
  117. return false;
  118. }
  119. $formData->editedDate = helper::now();
  120. /* 仅在有变更的情况下才变更版本号。 */
  121. $changes = common::createChanges($oldApi, $formData);
  122. if(!empty($changes)) $formData->version = $oldApi->version + 1;
  123. $this->dao->update(TABLE_API)
  124. ->data($formData)
  125. ->autoCheck()
  126. ->batchCheck($this->config->api->edit->requiredFields, 'notempty')
  127. ->check('title', 'unique', "id != $formData->id AND lib = $formData->lib AND module = $formData->module")
  128. ->check('path', 'unique', "id != $formData->id AND lib = $formData->lib AND module = $formData->module AND method = '$formData->method'")
  129. ->where('id')->eq($formData->id)
  130. ->exec();
  131. if(dao::isError()) return false;
  132. /* 维护历史记录。 */
  133. if($changes)
  134. {
  135. $actionID = $this->loadModel('action')->create('api', $formData->id, 'edited', '', '', '', false);
  136. $this->action->logHistory($actionID, $changes);
  137. }
  138. /* 维护接口文档的历史版本。 */
  139. $apiSpec = $this->getApiSpecByData($formData);
  140. $this->dao->delete()->from(TABLE_API_SPEC)->where('doc')->eq($apiSpec['doc'])->andWhere('version')->eq($apiSpec['version'])->exec();
  141. $this->dao->insert(TABLE_API_SPEC)->data($apiSpec)->exec();
  142. return !dao::isError();
  143. }
  144. /**
  145. * 创建数据结构。
  146. * Create a global struct.
  147. *
  148. * @param object $formData
  149. * @access public
  150. * @return bool
  151. */
  152. public function createStruct($formData)
  153. {
  154. $this->dao->insert(TABLE_APISTRUCT)->data($formData)
  155. ->autoCheck()
  156. ->batchCheck($this->config->api->struct->requiredFields, 'notempty')
  157. ->exec();
  158. if(dao::isError()) return false;
  159. /* 维护历史记录。 */
  160. $structID = $this->dao->lastInsertID();
  161. $this->loadModel('action')->create('apistruct', $structID, 'Created');
  162. /* 维护数据结构的历史版本。 */
  163. $structSpec = $this->getApiStructSpecByData($formData);
  164. $this->dao->insert(TABLE_APISTRUCT_SPEC)->data($structSpec)->exec();
  165. return !dao::isError();
  166. }
  167. /**
  168. * 更新数据结构。
  169. * Update a struct.
  170. *
  171. * @param object $formData
  172. * @access public
  173. * @return bool
  174. */
  175. public function updateStruct($formData)
  176. {
  177. $oldData = $this->dao->findByID($formData->id)->from(TABLE_APISTRUCT)->fetch();
  178. $this->dao->update(TABLE_APISTRUCT)
  179. ->data($formData)->autoCheck()
  180. ->batchCheck($this->config->api->struct->requiredFields, 'notempty')
  181. ->where('id')->eq($formData->id)
  182. ->exec();
  183. if(dao::isError()) return false;
  184. /* 维护历史记录。 */
  185. $changes = common::createChanges($oldData, $formData);
  186. if($changes)
  187. {
  188. $actionID = $this->loadModel('action')->create('apistruct', $formData->id, 'Edited');
  189. $this->action->logHistory($actionID, $changes);
  190. }
  191. /* 维护数据结构的历史版本。 */
  192. $structSpec = $this->getApiStructSpecByData($formData);
  193. $this->dao->insert(TABLE_APISTRUCT_SPEC)->data($structSpec)->exec();
  194. return !dao::isError();
  195. }
  196. /**
  197. * 根据文档库ID获取数据结构列表。
  198. * Get struct list by api doc id.
  199. *
  200. * @param int $id
  201. * @access public
  202. * @return array
  203. */
  204. public function getStructListByLibID($id)
  205. {
  206. $structList = $this->dao->select('*')->from(TABLE_APISTRUCT)->where('lib')->eq($id)->fetchAll();
  207. foreach($structList as $struct)
  208. {
  209. if(!isset($struct->attribute)) continue;
  210. $struct->attribute = json_decode($struct->attribute, true);
  211. }
  212. return $structList;
  213. }
  214. /**
  215. * 根据ID获取数据结构信息。
  216. * Get a struct info.
  217. *
  218. * @param int $id
  219. * @access public
  220. * @return object|false
  221. */
  222. public function getStructByID($id)
  223. {
  224. $struct = $this->dao->select('*')->from(TABLE_APISTRUCT)->where('id')->eq($id)->fetch();
  225. if($struct) $struct->attribute = json_decode($struct->attribute, true);
  226. return $struct;
  227. }
  228. /**
  229. * 根据版本号或者发布ID获取发布信息。
  230. * Get release.
  231. *
  232. * @param int $libID
  233. * @param string $type byVersion | byID
  234. * @param string|int $param
  235. * @access public
  236. * @return object|false
  237. */
  238. public function getRelease($libID = 0, $type = 'byID', $param = '0')
  239. {
  240. $release = $this->dao->select('*')->from(TABLE_API_LIB_RELEASE)
  241. ->where('1 = 1')
  242. ->beginIF($libID)->andWhere('lib')->eq($libID)->fi()
  243. ->beginIF($type == 'byVersion')->andWhere('version')->eq($param)->fi()
  244. ->beginIF($type == 'byID')->andWhere('id')->eq($param)->fi()
  245. ->fetch();
  246. if($release) $release->snap = json_decode($release->snap, true);
  247. return $release;
  248. }
  249. /**
  250. * 根据文档库ID获取发布列表。
  251. * Get releases by lib id.
  252. *
  253. * @param int $libID
  254. * @access public
  255. * @return array
  256. */
  257. public function getReleaseListByLib($libID)
  258. {
  259. return $this->dao->select('*')->from(TABLE_API_LIB_RELEASE)->where('lib')->eq($libID)->fetchAll('id');
  260. }
  261. /**
  262. * 根据接口ID获取接口信息。
  263. * Get api doc by id.
  264. *
  265. * @param int $id
  266. * @param int $version
  267. * @param int $releaseID
  268. * @access public
  269. * @return object|false
  270. */
  271. public function getByID($id, $version = 0, $releaseID = 0)
  272. {
  273. if($releaseID)
  274. {
  275. $release = $this->getRelease(0, 'byID', $releaseID);
  276. if(!empty($release->snap['apis']))
  277. {
  278. foreach($release->snap['apis'] as $api)
  279. {
  280. if($api['id'] == $id) $version = $api['version'];
  281. }
  282. }
  283. }
  284. /* 如果要根据版本号查询,那主要查询的是spec表,否则查询api表即可。 */
  285. if($version)
  286. {
  287. $fields = 'spec.*,api.id,api.product,api.lib,doc.name as libName,module.name as moduleName,api.editedBy,api.editedDate';
  288. }
  289. else
  290. {
  291. $fields = 'api.*,doc.name as libName,module.name as moduleName';
  292. }
  293. $api = $this->dao->select($fields)->from(TABLE_API)->alias('api')
  294. ->beginIF($version)->leftJoin(TABLE_API_SPEC)->alias('spec')->on('api.id = spec.doc')->fi()
  295. ->leftJoin(TABLE_DOCLIB)->alias('doc')->on('api.lib = doc.id')
  296. ->leftJoin(TABLE_MODULE)->alias('module')->on('api.module = module.id')
  297. ->where('api.id')->eq($id)
  298. ->beginIF($version)->andWhere('spec.version')->eq($version)->fi()
  299. ->fetch();
  300. if($api)
  301. {
  302. $api->params = json_decode($api->params, true);
  303. $api->response = json_decode($api->response, true);
  304. }
  305. return $api;
  306. }
  307. /**
  308. * 获取发布下的所有接口文档。
  309. * Get api list by release.
  310. *
  311. * @param object $release
  312. * @param string $where
  313. * @access public
  314. * @return array
  315. */
  316. public function getApiListByRelease($release, $where = '1 = 1 ')
  317. {
  318. /* 根据发布中的apis生成查询条件。 */
  319. $strJoin = array();
  320. if(isset($release->snap['apis']))
  321. {
  322. foreach($release->snap['apis'] as $api)
  323. {
  324. $strJoin[] = "(spec.doc = {$api['id']} and spec.version = {$api['version']} )";
  325. }
  326. }
  327. if($strJoin) $where .= 'and (' . implode(' or ', $strJoin) . ')';
  328. $apiList = $this->dao->select('api.lib,spec.*,api.id')->from(TABLE_API)->alias('api')
  329. ->leftJoin(TABLE_API_SPEC)->alias('spec')->on('api.id = spec.doc')
  330. ->where($where)
  331. ->fetchAll();
  332. return $apiList;
  333. }
  334. /**
  335. * 根据发布ID或者模块ID获取接口列表。
  336. * Get api doc list by module id or release id.
  337. *
  338. * @param int $libID
  339. * @param int $moduleID
  340. * @param int $releaseID
  341. * @param object $pager
  342. * @return array
  343. */
  344. public function getListByModuleID($libID = 0, $moduleID = 0, $releaseID = 0, $pager = null)
  345. {
  346. /* Get release info. */
  347. if($releaseID > 0)
  348. {
  349. /* 根据发布ID获取发信息。 */
  350. $release = $this->getRelease(0, 'byID', $releaseID);
  351. $where = "1 = 1 and lib = $libID ";
  352. if($moduleID > 0 && isset($release->snap['modules']))
  353. {
  354. /* 根据发布中的modules生成查询条件。 */
  355. $sub = array();
  356. foreach($release->snap['modules'] as $module)
  357. {
  358. $tmp = explode(',', $module['path']);
  359. if(in_array($moduleID, $tmp)) $sub[] = $module['id'];
  360. }
  361. if($sub) $where .= 'and module in (' . implode(',', $sub) . ')';
  362. }
  363. $apiList = $this->getApiListByRelease($release, $where);
  364. }
  365. else
  366. {
  367. /* 根据模块ID获取发布信息。 */
  368. if($moduleID > 0)
  369. {
  370. $sub = $this->dao->select('id')->from(TABLE_MODULE)->where('FIND_IN_SET(' . $moduleID . ', path)')->processSQL();
  371. $where = 'module in (' . $sub . ')';
  372. }
  373. else
  374. {
  375. /* 没有模块ID的根据libID来获取发布信息。 */
  376. $where = 'lib = ' . $libID;
  377. }
  378. $apiList = $this->dao->select('*')->from(TABLE_API)->where($where)->andWhere('deleted')->eq(0)->page($pager)->fetchAll('', false);
  379. }
  380. foreach($apiList as $api)
  381. {
  382. $api->params = json_decode($api->params, true);
  383. $api->response = json_decode($api->response, true);
  384. }
  385. return $apiList;
  386. }
  387. /**
  388. * 获取接口状态对应的语言项。
  389. * Get status text by status.
  390. *
  391. * @param string $status
  392. * @access public
  393. * @return string
  394. */
  395. public static function getApiStatusText($status)
  396. {
  397. global $lang;
  398. switch($status)
  399. {
  400. case static::STATUS_DOING:
  401. {
  402. return $lang->api->doing;
  403. }
  404. case static::STATUS_DONE:
  405. {
  406. return $lang->api->done;
  407. }
  408. }
  409. return $status;
  410. }
  411. /**
  412. * 获取指定文档库下的数据结构列表。
  413. * Get struct list by lib id.
  414. *
  415. * @param int $libID
  416. * @param object $pager
  417. * @param string $orderBy
  418. * @access public
  419. * @return array
  420. */
  421. public function getStructByQuery($libID, $pager = null, $orderBy = '')
  422. {
  423. return $this->dao->select('t1.*,t2.realname as addedName')->from(TABLE_APISTRUCT)->alias('t1')
  424. ->leftJoin(TABLE_USER)->alias('t2')->on('t2.account = t1.addedBy')
  425. ->where('t1.deleted')->eq(0)
  426. ->andWhere('t1.lib')->eq($libID)
  427. ->orderBy($orderBy)
  428. ->page($pager)
  429. ->fetchAll();
  430. }
  431. /**
  432. * 获取指定发布下的数据结构列表。
  433. * Get struct list by release.
  434. *
  435. * @param object $release
  436. * @param string $where
  437. * @param object $pager
  438. * @param string $orderBy
  439. * @access public
  440. * @return array
  441. */
  442. public function getStructListByRelease($release, $where = '1 = 1 ', $pager = null, $orderBy = 'id')
  443. {
  444. $strJoin = array();
  445. if(isset($release->snap['structs']))
  446. {
  447. /* 根据发布中的structs生成查询条件。 */
  448. foreach($release->snap['structs'] as $struct)
  449. {
  450. $strJoin[] = "(object.id = {$struct['id']} and spec.version = {$struct['version']} )";
  451. }
  452. }
  453. if($strJoin) $where .= 'and (' . implode(' or ', $strJoin) . ')';
  454. return $this->dao->select('object.id,object.lib,spec.name,spec.type,spec.desc,spec.attribute,spec.version,spec.addedBy,spec.addedDate,user.realname as addedName')
  455. ->from(TABLE_APISTRUCT)->alias('object')
  456. ->leftJoin(TABLE_APISTRUCT_SPEC)->alias('spec')->on('object.name = spec.name')
  457. ->leftJoin(TABLE_USER)->alias('user')->on('user.account = spec.addedBy')
  458. ->where($where)
  459. ->orderBy($orderBy)
  460. ->page($pager)
  461. ->fetchAll();
  462. }
  463. /**
  464. * 获取指定文档库下的数据结构列表。
  465. * Get release list by lib id.
  466. *
  467. * @param array $libID
  468. * @param object $pager
  469. * @param string $orderBy
  470. * @access public
  471. * @return array
  472. */
  473. public function getReleaseByQuery($libID, $pager = null, $orderBy = '')
  474. {
  475. return $this->dao->select('*')->from(TABLE_API_LIB_RELEASE)
  476. ->where('lib')->in($libID)
  477. ->orderBy($orderBy)
  478. ->page($pager)
  479. ->fetchAll();
  480. }
  481. /**
  482. * 查询SQL语句并返回结果。
  483. * Query sql.
  484. *
  485. * @param string $sql
  486. * @param string $keyField
  487. * @access public
  488. * @return array
  489. */
  490. public function sql($sql, $keyField = '')
  491. {
  492. /* 检查允许接口调用SQL的配置项是否打开。 */
  493. if(!$this->config->features->apiSQL) return array('status' => 'fail', 'message' => sprintf($this->lang->api->error->disabled, '$config->features->apiSQL'));
  494. $sql = trim($sql);
  495. if(strpos($sql, ';') !== false) $sql = substr($sql, 0, strpos($sql, ';'));
  496. /* 如果没传SQL参数,则无法进行下一步。 */
  497. if(empty($sql)) return array('status' => 'fail', 'message' => '');
  498. /* 如果SQL语句中没有select单词,则无法进行下一步。 */
  499. if(stripos($sql, 'select ') !== 0) return array('status' => 'fail', 'message' => $this->lang->api->error->onlySelect);
  500. try
  501. {
  502. $stmt = $this->dbh->query($sql);
  503. $rows = array();
  504. if(empty($keyField))
  505. {
  506. $rows = $stmt->fetchAll();
  507. }
  508. else
  509. {
  510. /* 用keyFiled作为键展示查询结果。 */
  511. while($row = $stmt->fetch()) $rows[$row->$keyField] = $row;
  512. }
  513. $result = array('status' => 'success', 'data' => $rows);
  514. }
  515. catch(PDOException $e)
  516. {
  517. $result = array('status' => 'fail', 'message' => $e->getMessage());
  518. }
  519. return $result;
  520. }
  521. /**
  522. * 创建初始数据。
  523. * Create demo data.
  524. *
  525. * @param string $name
  526. * @param string $baseUrl
  527. * @param string $version
  528. * @access public
  529. * @return int
  530. */
  531. public function createDemoData($name, $baseUrl, $version = '16.0')
  532. {
  533. /* Replace the doc lib name to api lib name. */
  534. $this->loadModel('action');
  535. $this->app->loadLang('doc');
  536. $this->lang->doclib->name = $this->lang->doclib->apiLibName;
  537. /* 获取当前用户或者系统首位用户。 */
  538. $firstAccount = $this->dao->select('account')->from(TABLE_USER)->orderBy('id_asc')->limit(1)->fetch('account');
  539. $currentAccount = isset($this->app->user->account) ? $this->app->user->account : $firstAccount;
  540. $libID = $this->createDemoLib($name, $baseUrl, $currentAccount);
  541. $moduleMap = $this->createDemoModule($libID, $version);
  542. $apiMap = $this->createDemoApi($libID, $version, $moduleMap, $currentAccount);
  543. $this->createDemoStruct($libID, $version, $currentAccount);
  544. $this->createDemoStructSpec($version, $currentAccount);
  545. $this->createDemoApiSpec($version, $apiMap, $moduleMap, $currentAccount);
  546. return $libID;
  547. }
  548. /**
  549. * 创建文档库初始数据。
  550. * Create lib demo data.
  551. *
  552. * @param string $name
  553. * @param string $baseUrl
  554. * @param string $currentAccount
  555. * @access private
  556. * @return int
  557. */
  558. private function createDemoLib($name, $baseUrl, $currentAccount)
  559. {
  560. $lib = new stdclass();
  561. $lib->type = 'api';
  562. $lib->name = $name;
  563. $lib->baseUrl = $baseUrl;
  564. $lib->acl = 'open';
  565. $lib->users = ',' . $currentAccount . ',';
  566. $this->dao->insert(TABLE_DOCLIB)->data($lib)->autoCheck()->batchCheck($this->config->api->createlib->requiredFields, 'notempty')->check('name', 'unique', "`type` = 'api'")->exec();
  567. $libID = $this->dao->lastInsertID();
  568. return $libID;
  569. }
  570. /**
  571. * 创建数据结构初始数据。
  572. * Create struct demo data.
  573. *
  574. * @param int $libID
  575. * @param string $version
  576. * @param string $currentAccount
  577. * @access private
  578. * @return bool
  579. */
  580. private function createDemoStruct($libID, $version, $currentAccount)
  581. {
  582. $structs = $this->getDemoData('apistruct', $version);
  583. foreach($structs as $struct)
  584. {
  585. unset($struct->id);
  586. $struct->lib = $libID;
  587. $struct->addedBy = $currentAccount;
  588. $struct->addedDate = helper::now();
  589. $struct->editedBy = $currentAccount;
  590. $struct->editedDate = helper::now();
  591. $this->dao->insert(TABLE_APISTRUCT)->data($struct)->exec();
  592. }
  593. return !dao::isError();
  594. }
  595. /**
  596. * 创建多版本数据结构初始数据。
  597. * Create struct spec demo data.
  598. *
  599. * @param string $version
  600. * @param string $currentAccount
  601. * @access private
  602. * @return bool
  603. */
  604. private function createDemoStructSpec($version, $currentAccount)
  605. {
  606. $specs = $this->getDemoData('apistruct_spec', $version);
  607. foreach($specs as $spec)
  608. {
  609. unset($spec->id);
  610. $spec->addedBy = $currentAccount;
  611. $spec->addedDate = helper::now();
  612. $this->dao->insert(TABLE_APISTRUCT_SPEC)->data($spec)->exec();
  613. }
  614. return !dao::isError();
  615. }
  616. /**
  617. * 创建文档库模块初始数据。
  618. * Create module demo data.
  619. *
  620. * @param int $libID
  621. * @param string $version
  622. * @access private
  623. * @return array
  624. */
  625. private function createDemoModule($libID, $version)
  626. {
  627. $moduleMap = array();
  628. $modules = $this->getDemoData('module', $version);
  629. foreach($modules as $module)
  630. {
  631. if($module->type != 'api') continue;
  632. $oldID = $module->id;
  633. unset($module->id);
  634. $module->root = $libID;
  635. $this->dao->insert(TABLE_MODULE)->data($module)->exec();
  636. $newID = $this->dao->lastInsertID();
  637. $this->dao->update(TABLE_MODULE)->set('path')->eq(",$newID,")->where('id')->eq($newID)->exec();
  638. $moduleMap[$oldID] = $newID;
  639. }
  640. return $moduleMap;
  641. }
  642. /**
  643. * 创建接口文档初始数据。
  644. * Create api demo data.
  645. *
  646. * @param int $libID
  647. * @param string $version
  648. * @param array $moduleMap
  649. * @param string $currentAccount
  650. * @access private
  651. * @return array
  652. */
  653. private function createDemoApi($libID, $version, $moduleMap, $currentAccount)
  654. {
  655. $this->loadModel('action');
  656. $apiMap = array();
  657. $apis = $this->getDemoData('api', $version);
  658. foreach($apis as $api)
  659. {
  660. $oldID = $api->id;
  661. unset($api->id);
  662. $api->lib = $libID;
  663. $api->module = $moduleMap[$api->module];
  664. $api->addedBy = $currentAccount;
  665. $api->addedDate = helper::now();
  666. $api->editedBy = $currentAccount;
  667. $api->editedDate = helper::now();
  668. $this->dao->insert(TABLE_API)->data($api)->exec();
  669. $newID = $this->dao->lastInsertID();
  670. $this->action->create('api', $newID, 'Created', '', '', $currentAccount);
  671. $apiMap[$oldID] = $newID;
  672. }
  673. return $apiMap;
  674. }
  675. /**
  676. * 创建多版本接口文档初始化数据。
  677. * Create api spec demo data.
  678. *
  679. * @param string $version
  680. * @param array $apiMap
  681. * @param array $moduleMap
  682. * @param string $currentAccount
  683. * @access private
  684. * @return bool
  685. */
  686. private function createDemoApiSpec($version, $apiMap, $moduleMap, $currentAccount)
  687. {
  688. $specs = $this->getDemoData('apispec', $version);
  689. foreach($specs as $spec)
  690. {
  691. unset($spec->id);
  692. $spec->doc = $apiMap[$spec->doc];
  693. $spec->module = zget($moduleMap, $spec->module, 0);
  694. $spec->owner = $currentAccount;
  695. $spec->addedBy = $currentAccount;
  696. $spec->addedDate = helper::now();
  697. $this->dao->insert(TABLE_API_SPEC)->data($spec)->exec();
  698. }
  699. return !dao::isError();
  700. }
  701. /**
  702. * 获取指定表的初始化数据。
  703. * Get demo data.
  704. *
  705. * @param string $table
  706. * @param string $version
  707. * @access private
  708. * @return array
  709. */
  710. public function getDemoData($table, $version)
  711. {
  712. $file = $this->app->getAppRoot() . 'db' . DS . 'api' . DS . $version . DS . $table;
  713. return unserialize(preg_replace_callback('#s:(\d+):"(.*?)";#s', function($match){return 's:'.strlen($match[2]).':"'.$match[2].'";';}, file_get_contents($file)));
  714. }
  715. /**
  716. * 根据搜索条件查询并返回接口文档列表。
  717. * Get api by search.
  718. *
  719. * @param int $libID
  720. * @param int $queryID
  721. * @param string $objectType product|project
  722. * @param array $libs
  723. * @access public
  724. * @return array
  725. */
  726. public function getApiListBySearch($libID, $queryID, $objectType = '', $libs = array())
  727. {
  728. $queryName = $objectType ? $objectType . 'apiDocQuery' : 'apiQuery';
  729. $queryForm = $objectType ? $objectType . 'apiDocForm' : 'apiForm';
  730. if($queryID)
  731. {
  732. $query = $this->loadModel('search')->getQuery($queryID);
  733. if($query)
  734. {
  735. $this->session->set($queryName, $query->sql);
  736. $this->session->set($queryForm, $query->form);
  737. }
  738. else
  739. {
  740. $this->session->set($queryName, ' 1 = 1');
  741. }
  742. }
  743. else
  744. {
  745. if($this->session->$queryName == false) $this->session->set($queryName, ' 1 = 1');
  746. }
  747. $apiQuery = $this->session->$queryName;
  748. if(strpos($apiQuery, "`lib` = 'all'") !== false) $apiQuery = str_replace("`lib` = 'all'", '1', $apiQuery);
  749. $apiList = $this->dao->select('*')->from(TABLE_API)
  750. ->where('deleted')->eq(0)
  751. ->andWhere($apiQuery)
  752. ->beginIF($libID)->andWhere('`lib`')->eq($libID)->fi()
  753. ->beginIF(!empty($libs))->andWhere('`lib`')->in($libs)->fi()
  754. ->fetchAll();
  755. return $apiList;
  756. }
  757. /**
  758. * 获取文档库所属产品或者项目的下拉菜单。
  759. * Get ordered objects for dic.
  760. *
  761. * @access public
  762. * @return array
  763. */
  764. public function getOrderedObjects()
  765. {
  766. $normalObjects = $closedObjects = array();
  767. /* 获取接口库所属产品的产品列表。 */
  768. $libs = $this->loadModel('doc')->getApiLibs();
  769. $products = $this->dao->select('t1.id, t1.order, t1.name, t1.status')->from(TABLE_PRODUCT)->alias('t1')
  770. ->leftJoin(TABLE_DOCLIB)->alias('t2')->on('t2.product=t1.id')
  771. ->where('t2.id')->gt(0)
  772. ->andWhere('t1.vision')->eq($this->config->vision)
  773. ->andWhere('t1.deleted')->eq(0)
  774. ->andWhere('t2.id')->in(array_keys($libs))
  775. ->orderBy('order_asc')
  776. ->fetchAll('id');
  777. foreach($products as $id => $product)
  778. {
  779. /* 筛选出正常的和关闭产品名称。 */
  780. if($product->status == 'normal') $normalObjects['product'][$id] = $product->name;
  781. if($product->status == 'closed') $closedObjects['product'][$id] = $product->name;
  782. }
  783. /* 获取接口库所属项目的项目列表。 */
  784. $projects = $this->dao->select('t1.id, t1.order, t1.name, t1.status')->from(TABLE_PROJECT)->alias('t1')
  785. ->leftJoin(TABLE_DOCLIB)->alias('t2')->on('t2.project=t1.id')
  786. ->where('t2.id')->gt(0)
  787. ->andWhere('t1.vision')->eq($this->config->vision)
  788. ->andWhere('t1.deleted')->eq(0)
  789. ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->projects)->fi()
  790. ->andWhere('t2.id')->in(array_keys($libs))
  791. ->orderBy('t1.hasProduct_asc, order_asc')
  792. ->fetchAll('id');
  793. foreach($projects as $id => $project)
  794. {
  795. /* 筛选出正常的和关闭项目名称。 */
  796. if($project->status != 'done' && $project->status != 'closed') $normalObjects['project'][$id] = $project->name;
  797. if($project->status == 'done' || $project->status == 'closed') $closedObjects['project'][$id] = $project->name;
  798. }
  799. return array($normalObjects, $closedObjects);
  800. }
  801. /**
  802. * 获取分组后的对象列表。
  803. *
  804. * @access public
  805. * @return array
  806. */
  807. public function getGroupedObjects()
  808. {
  809. $libs = $this->loadModel('doc')->getApiLibs();
  810. $libIDs = array_keys($libs);
  811. /* 获取接口库所属产品的产品列表。 */
  812. $products = $this->dao->select('t1.id, t1.order, t1.name, t1.status, t1.program')->from(TABLE_PRODUCT)->alias('t1')
  813. ->leftJoin(TABLE_DOCLIB)->alias('t2')->on('t2.product=t1.id')
  814. ->where('t2.id')->gt(0)
  815. ->andWhere('t1.vision')->eq($this->config->vision)
  816. ->andWhere('t1.deleted')->eq(0)
  817. ->andWhere('t2.id')->in($libIDs)
  818. ->orderBy('order_asc')
  819. ->fetchAll('id');
  820. /* 获取接口库所属项目的项目列表。 */
  821. $projects = $this->dao->select('t1.id, t1.order, t1.name, t1.status, t1.parent')->from(TABLE_PROJECT)->alias('t1')
  822. ->leftJoin(TABLE_DOCLIB)->alias('t2')->on('t2.project=t1.id')
  823. ->where('t2.id')->gt(0)
  824. ->andWhere('t1.vision')->eq($this->config->vision)
  825. ->andWhere('t1.deleted')->eq(0)
  826. ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->projects)->fi()
  827. ->andWhere('t2.id')->in($libIDs)
  828. ->orderBy('t1.hasProduct_asc, order_asc')
  829. ->fetchAll('id');
  830. $nolinks = array();
  831. foreach($libs as $lib)
  832. {
  833. if($lib->product != 0 && isset($products[$lib->product]) && !isset($products[$lib->product]->firstLib)) $products[$lib->product]->firstLib = $lib->id;
  834. if($lib->project != 0 && isset($projects[$lib->project]) && !isset($projects[$lib->project]->firstLib)) $projects[$lib->project]->firstLib = $lib->id;
  835. if($lib->product != 0 || $lib->project != 0 || $lib->execution != 0) continue;
  836. $nolinks[$lib->id] = $lib;
  837. }
  838. return array('product' => $products, 'project' => $projects, 'nolink' => $nolinks);
  839. }
  840. /**
  841. * 获取有权限的接口文档列表。
  842. * Get priv Apis.
  843. *
  844. * @param string $mode
  845. * @access public
  846. * @return array
  847. */
  848. public function getPrivApis($mode = '')
  849. {
  850. $libs = $this->dao->select('*')->from(TABLE_DOCLIB)
  851. ->where('type')->eq('api')
  852. ->andWhere('vision')->eq($this->config->vision)
  853. ->fetchAll('id');
  854. /* 过滤掉没有权限的文档库。 */
  855. $this->loadModel('doc');
  856. foreach($libs as $libID => $lib)
  857. {
  858. if(!$this->doc->checkPrivLib($lib)) unset($libs[$libID]);
  859. }
  860. return $this->dao->select('id')->from(TABLE_API)
  861. ->where('lib')->in(array_keys($libs))
  862. ->beginIF($mode != 'all')->andWhere('deleted')->eq(0)->fi()
  863. ->fetchAll('id');
  864. }
  865. /**
  866. * 初始化搜索表单。
  867. * Build search form.
  868. *
  869. * @param object $lib
  870. * @param int $queryID
  871. * @param string $actionURL
  872. * @param array $libs
  873. * @param string $type product|project
  874. * @access public
  875. * @return void
  876. */
  877. public function buildSearchForm($lib, $queryID, $actionURL, $libs = array(), $type = '')
  878. {
  879. if(empty($lib)) return;
  880. $libPairs = array('' => '', $lib->id => $lib->name);
  881. $this->config->api->search['module'] = 'api';
  882. if(!empty($libs))
  883. {
  884. foreach($libs as $lib)
  885. {
  886. if(empty($lib)) continue;
  887. if($lib->type != 'api') continue;
  888. $libPairs[$lib->id] = $lib->name;
  889. }
  890. $this->config->api->search['module'] = !empty($type) ? $type . 'apiDoc' : 'api';
  891. }
  892. $this->config->api->search['queryID'] = $queryID;
  893. $this->config->api->search['actionURL'] = $actionURL;
  894. $this->config->api->search['params']['lib']['values'] = $libPairs + array('all' => $this->lang->api->allLibs);
  895. $this->loadModel('search')->setSearchParams($this->config->api->search);
  896. }
  897. /**
  898. * 获取创建接口版本时所需的数据。
  899. * Get spec of api.
  900. *
  901. * @param object $data
  902. * @access private
  903. * @return array
  904. */
  905. private function getApiSpecByData($data)
  906. {
  907. return array(
  908. 'doc' => $data->id,
  909. 'title' => $data->title,
  910. 'path' => $data->path,
  911. 'module' => !empty($data->module) ? $data->module : 0,
  912. 'protocol' => !empty($data->protocol) ? $data->protocol : 'HTTP',
  913. 'method' => !empty($data->method) ? $data->method : 'GET',
  914. 'requestType' => !empty($data->requestType) ? $data->requestType : '',
  915. 'responseType' => !empty($data->responseType) ? $data->responseType : '',
  916. 'status' => !empty($data->status) ? $data->status : 'done',
  917. 'owner' => !empty($data->owner) ? $data->owner : '',
  918. 'desc' => !empty($data->desc) ? $data->desc : '',
  919. 'version' => !empty($data->version) ? $data->version : 1,
  920. 'params' => !empty($data->params) ? $data->params : '',
  921. 'paramsExample' => !empty($data->paramsExample) ? $data->paramsExample : '',
  922. 'responseExample' => !empty($data->responseExample) ? $data->responseExample : '',
  923. 'response' => !empty($data->response) ? $data->response : '',
  924. 'addedBy' => $this->app->user->account,
  925. 'addedDate' => helper::now(),
  926. );
  927. }
  928. /**
  929. * 获取创建数据结构版本时所需的数据。
  930. * Get struct spec of api.
  931. *
  932. * @param object $data
  933. * @access private
  934. * @return array
  935. */
  936. private function getApiStructSpecByData($data)
  937. {
  938. return array(
  939. 'name' => $data->name,
  940. 'type' => !empty($data->type) ? $data->type : '',
  941. 'desc' => !empty($data->desc) ? $data->desc : '',
  942. 'version' => !empty($data->version) ? $data->version : 1,
  943. 'attribute' => !empty($data->attribute) ? $data->attribute : '',
  944. 'addedBy' => !empty($data->addedBy) ? $data->addedBy : $this->app->user->account,
  945. 'addedDate' => !empty($data->addedDate) ? $data->addedDate : helper::now()
  946. );
  947. }
  948. /**
  949. * 获取接口类型数据。
  950. * Get Type list.
  951. *
  952. * @param int $libID
  953. * @access protected
  954. * @return array
  955. */
  956. public function getTypeList($libID)
  957. {
  958. $typeList = array();
  959. foreach($this->lang->api->paramsTypeOptions as $key => $item)
  960. {
  961. $typeList[$key] = $item;
  962. }
  963. /* Get all struct by libID. */
  964. $structs = $this->getStructListByLibID($libID);
  965. foreach($structs as $struct)
  966. {
  967. $typeList[$struct->id] = $struct->name;
  968. }
  969. return $typeList;
  970. }
  971. }