control.php 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. <?php
  2. /**
  3. * The control file of api 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: control.php 5143 2013-07-15 06:11:59Z thanatos thanatos915@163.com $
  10. * @link https://www.zentao.net
  11. */
  12. class api extends control
  13. {
  14. public $objectType = 'nolink';
  15. public $objectID = 0;
  16. /**
  17. * @param string $moduleName
  18. * @param string $methodName
  19. * @param string $appName
  20. */
  21. public function __construct($moduleName = '', $methodName = '', $appName = '')
  22. {
  23. parent::__construct($moduleName, $methodName, $appName);
  24. $this->user = $this->loadModel('user');
  25. $this->doc = $this->loadModel('doc');
  26. $this->action = $this->loadModel('action');
  27. if($this->cookie->objectType) $this->objectType = $this->cookie->objectType;
  28. if($this->cookie->objectID) $this->objectID = $this->cookie->objectID;
  29. }
  30. /**
  31. * 文档应用下接口空间页面。
  32. * Api doc index page.
  33. *
  34. * @param int $libID
  35. * @param int $moduleID
  36. * @param int $apiID
  37. * @param int $version
  38. * @param int $release
  39. * @param string $browseType
  40. * @param string $params
  41. * @access public
  42. * @return void
  43. * @param string $orderBy
  44. * @param int $recTotal
  45. * @param int $recPerPage
  46. * @param int $pageID
  47. * @param string $mode
  48. * @param string $search
  49. */
  50. public function index($libID = 0, $moduleID = 0, $apiID = 0, $version = 0, $release = 0, $browseType = 'nolink', $params = '', $orderBy = 'order_asc', $recTotal = 0, $recPerPage = 20, $pageID = 1, $mode = '', $search = '')
  51. {
  52. /* 设置空间类型。 */
  53. $this->session->set('spaceType', 'api', 'doc');
  54. /* 详情页返回上一页用的链接。 */
  55. $this->session->set('structList', inLink('index', "libID=$libID&moduleID=$moduleID"), 'doc');
  56. setCookie("docSpaceParam", '', $this->config->cookieLife, $this->config->webRoot, '', false, true);
  57. if(empty($libID) && !empty($apiID))
  58. {
  59. $api = $this->api->getByID($apiID, $version, $release);
  60. if($api) $libID = $api->lib;
  61. }
  62. if(empty($mode))
  63. {
  64. if(!$libID) $mode = 'home';
  65. elseif($apiID) $mode = 'view';
  66. else $mode = 'list';
  67. }
  68. $this->setMenu($libID);
  69. $objectType = $this->objectType;
  70. $objectID = $this->objectID;
  71. /* 获取文档目录列表和当前选中的文档目录. */
  72. $libs = $this->doc->getApiLibs($libID, $objectType, (int)$objectID);
  73. if(empty($libs) && $objectType != 'nolink')
  74. {
  75. $objectType = 'nolink';
  76. $objectID = 0;
  77. $libs = $this->doc->getApiLibs($libID, 'nolink');
  78. }
  79. if($libID && !isset($libs[$libID])) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->doc->accessDenied, 'locate' => $this->createLink('api', 'index'))));
  80. $lib = $libID ? zget($libs, $libID) : current($libs);
  81. $libID = !empty($lib->id) ? $lib->id : 0;
  82. $objectType = !empty($lib->product) ? 'product' : (!empty($lib->project) ? 'project' : 'nolink');
  83. $objectID = !empty($lib->product) ? $lib->product : (!empty($lib->project) ? $lib->project : 0);
  84. $this->view->libID = $libID;
  85. $this->view->moduleID = $moduleID;
  86. $this->view->apiID = (int)$apiID;
  87. $this->view->release = (int)$release;
  88. $this->view->apiVersion = (int)$version;
  89. $this->view->mode = $mode;
  90. $this->view->filterType = $browseType;
  91. $this->view->search = $search;
  92. $this->view->recTotal = $recTotal;
  93. $this->view->recPerPage = $recPerPage;
  94. $this->view->pageID = $pageID;
  95. $this->view->orderBy = $orderBy;
  96. $this->view->objectType = $objectType;
  97. $this->view->objectID = $objectID;
  98. $this->view->params = $params;
  99. $this->view->users = $this->loadModel('user')->getPairs('noclosed,noletter');
  100. $this->view->title = $this->lang->api->pageTitle;
  101. $this->display();
  102. }
  103. /**
  104. * 获取接口空间首页页面。
  105. * Get the api home page.
  106. *
  107. * @param string $type
  108. * @param string $params
  109. * @param int $recPerPage
  110. * @param int $pageID
  111. * @access public
  112. * @return void
  113. */
  114. public function ajaxGetHome($type = 'nolink', $params = 'notempty_unclosed', $recPerPage = 20, $pageID = 1)
  115. {
  116. if(!in_array($type, array('product', 'project', 'nolink'))) $type = 'nolink';
  117. $libs = $this->doc->getApiLibs(0, $type);
  118. $flags = explode('_', $params);
  119. $unclosed = in_array('unclosed', $flags);
  120. $notempty = in_array('notempty', $flags);
  121. $apis = $this->api->getApiListBySearch(0, 0);
  122. $recTotal = 0;
  123. $recPerPage = $recPerPage ? max(1, $recPerPage) : 20;
  124. $productsCount = array();
  125. $projectsCount = array();
  126. foreach($apis as $api)
  127. {
  128. if(!isset($libs[$api->lib])) continue;
  129. $lib = $libs[$api->lib];
  130. if(isset($lib->apiCount)) $lib->apiCount++;
  131. else $lib->apiCount = 1;
  132. if($lib->product)
  133. {
  134. if(isset($productsCount[$lib->product])) $productsCount[$lib->product]++;
  135. else $productsCount[$lib->product] = 1;
  136. }
  137. if($lib->project)
  138. {
  139. if(isset($projectsCount[$lib->project])) $projectsCount[$lib->project]++;
  140. else $projectsCount[$lib->project] = 1;
  141. }
  142. }
  143. if($type === 'product' || $type === 'project')
  144. {
  145. $this->loadModel('program');
  146. $this->app->loadLang('project');
  147. $this->app->loadLang('product');
  148. $programPairs = $this->loadModel('program')->getTopPairs($unclosed ? 'noclosed' : '');
  149. $programs[] = (object)array('id' => 0, 'name' => $this->lang->$type->emptyProgram);
  150. foreach($programPairs as $id => $name)
  151. {
  152. $program = new stdclass();
  153. $program->id = $id;
  154. $program->name = $name;
  155. $programs[$id] = $program;
  156. }
  157. if($type == 'product')
  158. {
  159. $products = $this->loadModel('product')->getList(0, $unclosed ? 'noclosed' : 'all', 0, 0);
  160. foreach($products as $product)
  161. {
  162. if(!isset($programs[$product->program])) continue;
  163. $program = $programs[$product->program];
  164. $product->apiCount = isset($productsCount[$product->id]) ? $productsCount[$product->id] : 0;
  165. if($notempty && $product->apiCount == 0) continue;
  166. $program->products[] = $product;
  167. $program->apiCount = isset($program->apiCount) ? $program->apiCount + $product->apiCount : $product->apiCount;
  168. }
  169. }
  170. else
  171. {
  172. $projects = $this->program->getProjectList(0, $unclosed ? 'unclosed' : 'all', 0, 'order_asc,id_desc');
  173. foreach($projects as $project)
  174. {
  175. $topParent = $project->parent ? explode(',', trim($project->path, ','))[0] : 0;
  176. if(!isset($programs[$topParent])) continue;
  177. $program = $programs[$topParent];
  178. $project->apiCount = isset($projectsCount[$project->id]) ? $projectsCount[$project->id] : 0;
  179. if($notempty && $project->apiCount == 0) continue;
  180. $program->apiCount = isset($program->apiCount) ? $program->apiCount + $project->apiCount : $project->apiCount;
  181. $program->projects[] = $project;
  182. }
  183. }
  184. if($notempty) $programs = array_filter($programs, function($program) {return isset($program->apiCount) && $program->apiCount > 0;});
  185. $recTotal = count($programs);
  186. $pageID = max(1, min($pageID, ceil($recTotal / $recPerPage)));
  187. $programs = array_slice($programs, ($pageID - 1) * $recPerPage, $recPerPage);
  188. }
  189. else
  190. {
  191. if($notempty) $libs = array_filter($libs, function($lib) {return isset($lib->apiCount) && $lib->apiCount > 0;});
  192. $recTotal = count($libs);
  193. $pageID = max(1, min($pageID, ceil($recTotal / $recPerPage)));
  194. $libs = array_slice($libs, ($pageID - 1) * $recPerPage, $recPerPage);
  195. }
  196. $this->app->loadClass('pager', true);
  197. $this->view->programs = isset($programs) ? $programs : array();
  198. $this->view->unclosed = $unclosed;
  199. $this->view->notempty = $notempty;
  200. $this->view->libs = $libs;
  201. $this->view->type = $type;
  202. $this->view->pager = new pager($recTotal, $recPerPage, $pageID);
  203. $this->display();
  204. }
  205. /**
  206. * 获取接口界面数据。
  207. * Get the api UI data.
  208. *
  209. * @param string $spaceID
  210. * @param string $picks
  211. * @access public
  212. * @return void
  213. */
  214. public function ajaxGetData($spaceID = 'nolink', $picks = '')
  215. {
  216. $noPicks = empty($picks);
  217. $picks = $noPicks ? '' : ",$picks,";
  218. $pickLib = $noPicks || strpos($picks, ',lib,') !== false;
  219. $pickModule = $noPicks || strpos($picks, ',module,') !== false;
  220. $data = array('spaceID' => $spaceID);
  221. $isNolink = $spaceID == 'nolink';
  222. list($objectType, $objectID) = $isNolink ? array('', 0) : explode('.', $spaceID . '.');
  223. if($noPicks || strpos($picks, ',space,') !== false)
  224. {
  225. $spaces['nolink'] = array('id' => 'nolink', 'name' => $this->lang->api->noLinked, 'type' => 'api');
  226. list($normalObjects, $closedObjects) = $this->api->getOrderedObjects();
  227. foreach($normalObjects as $type => $list)
  228. {
  229. foreach($list as $id => $name) $spaces["$type.{$id}"] = array('id' => "$type.{$id}", 'name' => $name, 'type' => 'api', 'objectType' => $type);
  230. }
  231. foreach($closedObjects as $type => $list)
  232. {
  233. foreach($list as $id => $name) $spaces["$type.{$id}"] = array('id' => "$type.{$id}", 'name' => $name, 'type' => 'api', 'objectType' => $type, 'closed' => true);
  234. }
  235. if(!$isNolink && !isset($spaces[$spaceID]))
  236. {
  237. $object = $this->loadModel($objectType)->getByID((int)$objectID);
  238. $spaces[$spaceID] = array('id' => $spaceID, 'name' => $object->name, 'type' => 'api');
  239. }
  240. $data['spaces'] = array_values($spaces);
  241. }
  242. if($pickLib || $pickModule)
  243. {
  244. $libs = $isNolink ? $this->doc->getApiLibs(0, 'nolink') : $this->doc->getApiLibs(0, $objectType, (int)$objectID);
  245. $libIds = array_keys($libs);
  246. if($pickLib)
  247. {
  248. $releases = $this->api->getReleaseByQuery($libIds);
  249. $releaseMap = array();
  250. foreach($releases as $release) $releaseMap[$release->lib][] = $release;
  251. foreach($libs as $lib)
  252. {
  253. $lib->versions = isset($releaseMap[$lib->id]) ? $releaseMap[$lib->id] : array();
  254. if(!empty($lib->product)) $lib->space = "product.{$lib->product}";
  255. elseif(!empty($lib->project)) $lib->space = "project.{$lib->project}";
  256. else $lib->space = 'nolink';
  257. }
  258. $data['libs'] = array_values($libs);
  259. }
  260. }
  261. if($pickModule) $data['modules'] = array_values($this->doc->getModulesOfLibs($libIds, 'api'));
  262. if($noPicks || strpos($picks, ',doc,') !== false)
  263. {
  264. $apis = $this->api->getApiListBySearch(0, 0, $objectType);
  265. $unsetProps = array('commonParams', 'params', 'paramsExample', 'response', 'responseExample');
  266. foreach($apis as $api)
  267. {
  268. foreach($unsetProps as $prop) unset($api->$prop);
  269. $api->originTitle = $api->title;
  270. $api->icon = "api is-$api->method";
  271. $api->api = true;
  272. $api->title = "$api->method $api->path " . htmlspecialchars_decode($api->title);
  273. $api->editable = common::hasPriv('api', 'edit');
  274. }
  275. $data['docs'] = array_values($apis);
  276. }
  277. echo json_encode($data);
  278. }
  279. /**
  280. * 获取指定库的 API 列表。
  281. * Get the API list of the specified library.
  282. *
  283. * @param int $libID
  284. * @param int $releaseID
  285. * @access public
  286. * @return void
  287. */
  288. public function ajaxGetLibApiList($libID, $releaseID = 0)
  289. {
  290. if($releaseID)
  291. {
  292. $release = $this->api->getRelease(0, 'byID', $releaseID);
  293. $apis = $release ? $this->api->getApiListByRelease($release) : array();
  294. }
  295. else
  296. {
  297. $apis = $this->api->getApiListBySearch($libID, 0);
  298. }
  299. $unsetProps = array('commonParams', 'params', 'paramsExample', 'response', 'responseExample');
  300. foreach($apis as $api)
  301. {
  302. foreach($unsetProps as $prop) unset($api->$prop);
  303. $api->originTitle = $api->title;
  304. $api->icon = "api is-$api->method";
  305. $api->api = true;
  306. $api->title = "$api->method $api->path " . htmlspecialchars_decode($api->title);
  307. }
  308. echo json_encode($apis);
  309. }
  310. /**
  311. * 获取接口数据。
  312. *
  313. * @param int $apiID
  314. * @param int $version
  315. * @param int $release
  316. * @access public
  317. * @return void
  318. */
  319. public function ajaxGetApi($apiID, $version = 0, $release = 0)
  320. {
  321. $api = $this->api->getByID($apiID, $version, $release);
  322. if($api)
  323. {
  324. $api->originTitle = $api->title;
  325. $api->icon = "api is-$api->method";
  326. $api->title = "$api->method $api->path $api->title";
  327. $api->api = true;
  328. $api->editable = common::hasPriv('api', 'edit');
  329. }
  330. $this->send($api);
  331. }
  332. /**
  333. * API详情页面。
  334. * View api.
  335. *
  336. * @param int $libID
  337. * @param int $apiID
  338. * @param int $moduleID
  339. * @param int $version
  340. * @param int $release
  341. * @access public
  342. * @return void
  343. */
  344. public function view($libID, $apiID, $moduleID = 0, $version = 0, $release = 0)
  345. {
  346. if(helper::isAjaxRequest('fetch'))
  347. {
  348. $api = $this->api->getByID($apiID, $version, $release);
  349. $this->view->api = $api;
  350. $this->view->typeList = $this->api->getTypeList($api->lib);
  351. $this->display();
  352. return;
  353. }
  354. echo $this->fetch('api', 'index', "libID=$libID&moduleID=$moduleID&apiID=$apiID&version=$version&release=$release");
  355. }
  356. /**
  357. * 版本管理列表页面。
  358. * Release list.
  359. *
  360. * @param int $libID
  361. * @param string $orderBy
  362. * @access public
  363. * @return void
  364. */
  365. public function releases($libID, $orderBy = 'id')
  366. {
  367. $this->app->loadLang('custom');
  368. /* Append id for second sort. */
  369. $sort = common::appendOrder($orderBy);
  370. $releases = $this->api->getReleaseByQuery(array($libID), null, $sort);
  371. $this->view->title = $this->lang->api->managePublish;
  372. $this->view->releases = $releases;
  373. $this->view->orderBy = $orderBy;
  374. $this->view->libID = $libID;
  375. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  376. $this->display();
  377. }
  378. /**
  379. * 删除一个版本。
  380. * Delete a release.
  381. *
  382. * @param int $libID
  383. * @param int $id
  384. * @access public
  385. * @return void
  386. */
  387. public function deleteRelease($libID, $id = 0)
  388. {
  389. $this->api->deleteRelease($id);
  390. if(dao::isError()) return $this->sendError(dao::getError());
  391. return $this->sendSuccess(array('load' => true, 'closeModal' => true, 'docApp' => array(array('executeCommand', 'loadLazyContent', array('.api-release-list')), array('load', null, null, null, array('noLoading' => true, 'picks' => 'lib')))));
  392. }
  393. /**
  394. * 创建一个接口版本。
  395. * Create a api doc lib.
  396. *
  397. * @param int $libID
  398. * @access public
  399. * @return void
  400. */
  401. public function createRelease($libID)
  402. {
  403. if(!empty($_POST))
  404. {
  405. $formData = form::data($this->config->api->form->createRelease)->add('lib', $libID)->add('addedBy', $this->app->user->account)->add('addedDate', helper::now())->get();
  406. /* Check version is exist. */
  407. if(!empty($formData->version) && $this->api->getRelease($libID, 'byVersion', $formData->version)) return $this->sendError($this->lang->api->noUniqueVersion);
  408. $this->api->publishLib($formData);
  409. if(dao::isError()) return $this->sendError(dao::getError());
  410. return $this->sendSuccess(array('load' => true, 'closeModal' => true, 'docApp' => array(array('executeCommand', 'loadLazyContent', array('.api-release-list')), array('load', null, null, null, array('noLoading' => true, 'picks' => 'lib')))));
  411. }
  412. $this->display();
  413. }
  414. /**
  415. * 接口数据结构列表页面。
  416. * Api doc global struct page.
  417. *
  418. * @param int $libID
  419. * @param int $releaseID
  420. * @param string $orderBy
  421. * @param int $recTotal
  422. * @param int $recPerPage
  423. * @param int $pageID
  424. * @access public
  425. * @return void
  426. */
  427. public function struct($libID = 0, $releaseID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
  428. {
  429. $this->setMenu($libID);
  430. /* Append id for second sort. */
  431. $sort = common::appendOrder($orderBy);
  432. $this->app->loadClass('pager', $static = true);
  433. $pager = new pager($recTotal, $recPerPage, $pageID);
  434. if($releaseID)
  435. {
  436. $release = $this->api->getRelease($libID, 'byID', $releaseID);
  437. $structs = $this->api->getStructListByRelease($release, '1 = 1 ', $pager, $sort);
  438. }
  439. else
  440. {
  441. $structs = $this->api->getStructByQuery($libID, $pager, $sort);
  442. }
  443. $this->view->title = $this->lang->api->struct;
  444. $this->view->libID = $libID;
  445. $this->view->releaseID = $releaseID;
  446. $this->view->structs = $structs;
  447. $this->view->orderBy = $orderBy;
  448. $this->view->pager = $pager;
  449. $this->view->users = $this->loadModel('user')->getPairs('noclosed,noletter');
  450. $this->display();
  451. }
  452. /**
  453. * 创建数据结构页面。
  454. * Create struct page.
  455. *
  456. * @param int $libID
  457. * @access public
  458. * @return void
  459. */
  460. public function createStruct($libID = 0)
  461. {
  462. $this->setMenu($libID);
  463. if(!empty($_POST))
  464. {
  465. $this->lang->api->name = $this->lang->api->structName;
  466. $formData = form::data($this->config->api->form->createStruct)->add('lib', $libID)->add('version', 1)->add('addedBy', $this->app->user->account)->add('addedDate', helper::now())->get();
  467. $this->api->createStruct($formData);
  468. if(dao::isError()) return $this->sendError(dao::getError());
  469. return $this->sendSuccess(array('locate' => helper::createLink('api', 'struct', "libID=$libID"), 'docApp' => array('executeCommand', 'loadLazyContent', array('.api-struct-list'))));
  470. }
  471. $options = array();
  472. foreach($this->lang->api->paramsTypeOptions as $key => $item)
  473. {
  474. $options[] = array('label' => $item, 'value' => $key);
  475. }
  476. $this->view->title = $this->lang->api->createStruct;
  477. $this->view->typeOptions = $options;
  478. $this->view->gobackLink = $this->createLink('api', 'struct', "libID=$libID");
  479. $this->display();
  480. }
  481. /**
  482. * 编辑数据结构页面。
  483. * Edit struct
  484. *
  485. * @param int $libID
  486. * @param int $structID
  487. * @access public
  488. * @return void
  489. */
  490. public function editStruct($libID, $structID)
  491. {
  492. $this->setMenu($libID);
  493. $struct = $this->api->getStructByID($structID);
  494. if(!empty($_POST))
  495. {
  496. $formData = form::data($this->config->api->form->editStruct)->add('id', $structID)->add('lib', $libID)->add('editedBy', $this->app->user->account)->add('editedDate', helper::now())->get();
  497. $formData->version = $struct->version + 1;
  498. $this->api->updateStruct($formData);
  499. if(dao::isError()) return $this->sendError(dao::getError());
  500. return $this->sendSuccess(array('locate' => helper::createLink('api', 'struct', "libID={$struct->lib}"), 'docApp' => array('executeCommand', 'loadLazyContent', array('.api-struct-list'))));
  501. }
  502. $options = array();
  503. foreach($this->lang->api->paramsTypeOptions as $key => $item)
  504. {
  505. $options[] = array('label' => $item, 'value' => $key);
  506. }
  507. $this->view->title = $struct->name . $this->lang->api->edit;
  508. $this->view->struct = $struct;
  509. $this->view->typeOptions = $options;
  510. $this->display();
  511. }
  512. /**
  513. * 删除一条数据结构。
  514. * Delete a struct.
  515. *
  516. * @param int $libID
  517. * @param int $structID
  518. * @access public
  519. * @return void
  520. */
  521. public function deleteStruct($libID, $structID = 0)
  522. {
  523. $this->api->delete(TABLE_APISTRUCT, $structID);
  524. if(dao::isError()) return $this->sendError(dao::getError());
  525. return $this->sendSuccess(array('load' => inlink('struct', "libID=$libID"), 'docApp' => array('executeCommand', 'loadLazyContent', array('.api-struct-list'))));
  526. }
  527. /**
  528. * 创建一个接口文档库。
  529. * Create a api doc library.
  530. *
  531. * @param string $type project|product
  532. * @param int $objectID
  533. * @access public
  534. * @return void
  535. */
  536. public function createLib($type = 'product', $objectID = 0)
  537. {
  538. if(!empty($_POST))
  539. {
  540. /* 组装formData。 */
  541. $fields = $this->config->api->form->createLib;
  542. $libType = $this->post->libType;
  543. if($libType == 'project') $fields['project']['required'] = true;
  544. if($libType == 'product') $fields['product']['required'] = true;
  545. $formData = form::data($fields)->add('addedBy', $this->app->user->account)->add('addedDate', helper::now())->get();
  546. $formData->product = $formData->libType == 'product' && !empty($formData->product) ? $formData->product : 0;
  547. $formData->project = $formData->libType == 'project' && !empty($formData->project) ? $formData->project : 0;
  548. $formData->execution = $formData->libType == 'project' && !empty($formData->execution) ? $formData->execution : 0;
  549. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  550. $libID = $this->doc->createApiLib($formData);
  551. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  552. $objectID = $libType == 'project' ? $this->post->project : $this->post->product;
  553. if(helper::isAjaxRequest('modal')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'load' => true, 'docApp' => array("selectSpace", ($libType == 'product' || $libType == 'project') ? "$libType.$objectID" : 'nolink', $libID, true)));
  554. /* Set locate object data. */
  555. setCookie("objectType", $libType, $this->config->cookieLife, $this->config->webRoot);
  556. setCookie("objectID", $objectID, $this->config->cookieLife, $this->config->webRoot);
  557. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $this->createLink('api', 'index', "libID=$libID"), 'closeModal' => true, 'docApp' => array("selectSpace", ($libType == 'product' || $libType == 'project') ? "$libType.$objectID" : 'nolink', $libID, true)));
  558. }
  559. /* 设置默认访问控制的语言项。 */
  560. $defaultAclLang = in_array($type, array('product', 'product')) ? $this->lang->{$type}->common : $this->lang->product->common;
  561. $this->lang->api->aclList['default'] = sprintf($this->lang->api->aclList['default'], $defaultAclLang);
  562. $this->view->type = $type;
  563. $this->view->objectID = $objectID;
  564. $this->view->groups = $this->loadModel('group')->getPairs();
  565. $this->view->users = $this->user->getPairs('nocode|noclosed');
  566. $this->display();
  567. }
  568. /**
  569. * 编辑一个接口文档库。
  570. * Edit an api doc library
  571. *
  572. * @param int $id
  573. * @access public
  574. * @return void
  575. */
  576. public function editLib($id)
  577. {
  578. $lib = $this->doc->getLibByID($id);
  579. if(!empty($_POST))
  580. {
  581. /* 组装formData。 */
  582. $formData = form::data($this->config->api->form->editLib)->add('id', $id)->get();
  583. $formData->product = $lib->product;
  584. $formData->project = $lib->project;
  585. $formData->execution = $lib->execution;
  586. $this->doc->updateApiLib($id, $formData);
  587. if(dao::isError()) return $this->sendError(dao::getError());
  588. return $this->sendSuccess(array('message' => $this->lang->saveSuccess, 'closeModal' => true, 'load' => true, 'docApp' => array('load', null, null, null, array('noLoading' => true, 'picks' => 'lib'))));
  589. }
  590. $type = $lib->product ? 'product' : ($lib->project ? 'project' : 'nolink');
  591. $object = $lib->product ? $this->loadModel('product')->getByID($lib->product) : $this->loadModel('project')->getById($lib->project);
  592. if($type != 'nolink') $this->lang->api->aclList['default'] = sprintf($this->lang->doclib->aclList['default'], $this->lang->{$type}->common);
  593. if($type == 'nolink') unset($this->lang->api->aclList['default']);
  594. $this->view->lib = $lib;
  595. $this->view->type = $type;
  596. $this->view->groups = $this->loadModel('group')->getPairs();
  597. $this->view->users = $this->user->getPairs('nocode|noclosed');
  598. $this->view->projects = $this->loadModel('project')->getPairsByModel();
  599. $this->view->products = $this->loadModel('product')->getPairs();
  600. $this->view->object = $object;
  601. $this->display();
  602. }
  603. /**
  604. * 删除一个接口文档库。
  605. * Delete api library.
  606. *
  607. * @param int $libID
  608. * @access public
  609. * @return void
  610. */
  611. public function deleteLib($libID)
  612. {
  613. $this->doc->delete(TABLE_DOCLIB, $libID);
  614. if(isInModal()) return $this->send(array('result' => 'success', 'load' => $this->createLink('api', 'index'), 'closeModal' => true, 'app' => $this->app->tab));
  615. return $this->send(array('result' => 'success', 'load' => true, 'closeModal' => true, 'app' => $this->app->tab));
  616. }
  617. /**
  618. * 创建一个接口文档。
  619. * Create an api doc.
  620. *
  621. * @param int $libID
  622. * @param int $moduleID
  623. * @param string $space api|project|product
  624. * @access public
  625. * @return void
  626. */
  627. public function create($libID, $moduleID = 0, $space = '')
  628. {
  629. if(!empty($_POST))
  630. {
  631. $formData = form::data($this->config->api->form->create)
  632. ->add('product', 0)
  633. ->add('version', 1)
  634. ->add('addedBy', $this->app->user->account)
  635. ->add('addedDate', helper::now())
  636. ->add('editedDate', helper::now())
  637. ->get();
  638. $apiID = $this->api->create($formData);
  639. if(dao::isError()) return $this->sendError(dao::getError());
  640. if(isInModal()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'load' => true));
  641. return $this->sendSuccess(array('locate' => helper::createLink('api', 'index', "libID={$formData->lib}&moduleID={$formData->module}&apiID={$apiID}"), 'docApp' => array('executeCommand', 'loadApi', array($apiID, 0, 0, true))));
  642. }
  643. $this->setMenu($libID, $space);
  644. $lib = $this->doc->getLibByID($libID);
  645. $libName = isset($lib->name) ? $lib->name . $this->lang->hyphen : '';
  646. $this->view->title = $libName . $this->lang->api->create;
  647. $this->view->allUsers = $this->loadModel('user')->getPairs('devfirst|noclosed');
  648. $this->view->libID = $libID;
  649. $this->view->libName = $lib->name;
  650. $this->view->moduleID = $moduleID;
  651. $this->view->moduleOptionMenu = $this->loadModel('tree')->getOptionMenu($libID, 'api', $startModuleID = 0);
  652. $this->display();
  653. }
  654. /**
  655. * 编辑一个接口文档。
  656. * Edit library.
  657. *
  658. * @param int $apiID
  659. * @access public
  660. * @return void
  661. */
  662. public function edit($apiID)
  663. {
  664. $api = $this->api->getByID($apiID);
  665. if(!empty($_POST))
  666. {
  667. $formData = form::data($this->config->api->form->edit)->add('id', $apiID)->add('version', $api->version)->add('editedBy', $this->app->user->account)->get();
  668. /* params 字段不进行 Unicode 编码,前端传过来的 params 是 Unicode 编码后的,导致 common::createChanges 时会始终认为 params 改变。 */
  669. $formData->params = json_encode(json_decode(html_entity_decode($formData->params), true), JSON_UNESCAPED_UNICODE);
  670. $this->api->update($formData);
  671. if(dao::isError()) return $this->sendError(dao::getError());
  672. return $this->sendSuccess(array('locate' => helper::createLink('api', 'index', "libID=$api->lib&moduleID=0&apiID=$apiID"), 'docApp' => array(array('executeCommand', 'selectApi', array($apiID)), array('executeCommand', 'loadApi'))));
  673. }
  674. $this->setMenu($api->lib);
  675. $this->getTypeOptions($api->lib);
  676. $this->view->title = $api->title . $this->lang->hyphen . $this->lang->api->edit;
  677. $this->view->api = $api;
  678. $this->view->allUsers = $this->loadModel('user')->getPairs('devfirst|noclosed');;
  679. $this->view->moduleOptionMenu = $this->loadModel('tree')->getOptionMenu($api->lib, 'api', $startModuleID = 0);
  680. $this->display();
  681. }
  682. /**
  683. * 删除一个接口文档。
  684. * Delete an api.
  685. *
  686. * @param int $apiID
  687. * @access public
  688. * @return void
  689. */
  690. public function delete($apiID)
  691. {
  692. $api = $this->api->getByID($apiID);
  693. $this->api->delete(TABLE_API, $apiID);
  694. if(dao::isError()) $this->sendError(dao::getError());
  695. return $this->sendSuccess(array('load' => inlink('index', "libID=$api->lib&module=$api->module")));
  696. }
  697. /**
  698. * Ajax获取接口允许的参数类型列表。
  699. * AJAX: Get params type options by scope.
  700. *
  701. * @access public
  702. * @return void
  703. */
  704. public function ajaxGetParamsTypeOptions()
  705. {
  706. $options = array();
  707. foreach($this->lang->api->paramsTypeOptions as $key => $item)
  708. {
  709. $options[] = array('label' => $item, 'value' => $key);
  710. }
  711. $this->sendSuccess(array('data' => $options));
  712. }
  713. /**
  714. * Ajax获取指定目录的数据结构。
  715. * AJAX: Get ref options.
  716. *
  717. * @param int $libID
  718. * @param int $structID
  719. * @access public
  720. * @return void
  721. */
  722. public function ajaxGetRefOptions($libID = 0, $structID = 0)
  723. {
  724. $res = $this->api->getStructListByLibID($libID);
  725. $options = array();
  726. foreach($res as $item)
  727. {
  728. if($item->id == $structID) continue;
  729. $options[$item->id] = $item->name;
  730. }
  731. echo html::select('refTarget', $options, '', "class='form-control'");
  732. }
  733. /**
  734. * Ajax获取指定ID的数据结构。
  735. * AJAX: Get ref info.
  736. *
  737. * @param int $refID
  738. * @access public
  739. * @return void
  740. */
  741. public function ajaxGetRefInfo($refID = 0)
  742. {
  743. $info = $this->api->getStructByID($refID);
  744. $this->sendSuccess(array('info' => $info));
  745. }
  746. /**
  747. * Ajax获取当前接口库的子目录结构。
  748. * AJAX: Get all child module.
  749. *
  750. * @param int $libID
  751. * @param string $type
  752. * @access public
  753. * @return void
  754. */
  755. public function ajaxGetChild($libID, $type = 'module')
  756. {
  757. $this->loadModel('tree');
  758. $childModules = $this->tree->getOptionMenu($libID, 'api');
  759. $select = ($type == 'module') ? html::select('module', $childModules, '0', "class='form-control chosen'") : html::select('parent', $childModules, '0', "class='form-control chosen'");
  760. echo $select;
  761. }
  762. /**
  763. * 设置接口文档页面的导航菜单。
  764. * Set api menu by method name.
  765. *
  766. * @param int $libID
  767. * @param string $space |null|api|project|product
  768. * @access public
  769. * @return void
  770. */
  771. private function setMenu($libID = 0, $space = '')
  772. {
  773. common::setMenuVars('doc', $libID);
  774. if($space && strpos('|api|project|product|', "|{$space}|") === false) $space = '';
  775. $lib = $this->loadModel('doc')->getLibByID($libID);
  776. if($this->app->tab == 'product')
  777. {
  778. $this->loadModel('product')->setMenu($lib->product);
  779. }
  780. elseif($this->app->tab == 'project')
  781. {
  782. $this->loadModel('project')->setMenu($lib->project);
  783. }
  784. if($space)
  785. {
  786. $spaceType = $space;
  787. $this->session->set('spaceType', $space, 'doc');
  788. }
  789. else
  790. {
  791. $spaceType = $this->session->spaceType ? $this->session->spaceType : 'api';
  792. }
  793. if(in_array($spaceType, array('product', 'project')))
  794. {
  795. $this->lang->doc->menu->api['exclude'] = 'api-' . $this->app->rawMethod . ',' . $this->app->rawMethod;
  796. $this->lang->doc->menu->{$spaceType}['subModule'] = 'api';
  797. }
  798. else
  799. {
  800. $this->lang->doc->menu->{$spaceType}['alias'] .= ',' . $this->app->rawMethod;
  801. }
  802. }
  803. /**
  804. * 返回当前客户端的session信息。
  805. * Return session to the client.
  806. *
  807. * @access public
  808. * @return void
  809. */
  810. public function getSessionID()
  811. {
  812. $this->session->set('rand', mt_rand(0, 10000));
  813. $this->view->sessionName = session_name();
  814. $this->view->sessionID = session_id();
  815. $this->view->rand = $this->session->rand;
  816. $this->display();
  817. }
  818. /**
  819. * 调用指定模型下的指定函数,并返回结果。
  820. * Execute a module's model's method, return the result.
  821. *
  822. * @param string $moduleName
  823. * @param string $methodName
  824. * @param string $params param1=value1,param2=value2, don't use & to join them.
  825. * @access public
  826. * @return string
  827. */
  828. public function getModel($moduleName, $methodName, $params = '')
  829. {
  830. if(!$this->config->features->apiGetModel) return printf($this->lang->api->error->disabled, '$config->features->apiGetModel');
  831. $params = explode(',', $params);
  832. $newParams = array_shift($params);
  833. foreach($params as $param)
  834. {
  835. $sign = strpos($param, '=') !== false ? '&' : ',';
  836. $newParams .= $sign . $param;
  837. }
  838. parse_str($newParams, $params);
  839. $module = $this->loadModel($moduleName);
  840. $result = call_user_func_array(array(&$module, $methodName), $params);
  841. if(dao::isError()) return print(json_encode(dao::getError()));
  842. $output['status'] = $result !== false ? 'success' : 'fail';
  843. $output['data'] = json_encode($result);
  844. $output['md5'] = md5($output['data']);
  845. $this->output = json_encode($output);
  846. print($this->output);
  847. }
  848. /**
  849. * 请求某个接口并返回测试结果。
  850. * The interface of api.
  851. *
  852. * @param string $filePath
  853. * @param string $action
  854. * @access public
  855. * @return void
  856. */
  857. public function debug($filePath, $action)
  858. {
  859. $filePath = helper::safe64Decode($filePath);
  860. $fileDirPath = realpath(dirname($filePath));
  861. if(strpos($fileDirPath, $this->app->getModuleRoot()) !== 0 && strpos($fileDirPath, $this->app->getExtensionRoot()) !== 0) return;
  862. if($action == 'extendModel')
  863. {
  864. $method = $this->apiZen->getMethod($filePath, 'Model');
  865. }
  866. elseif($action == 'extendControl')
  867. {
  868. $method = $this->apiZen->getMethod($filePath);
  869. }
  870. if(!empty($_POST))
  871. {
  872. $result = $this->apiZen->request($method->className, $method->methodName, $action);
  873. $content = json_decode($result['content']);
  874. $status = zget($content, 'status', '');
  875. $data = isset($content->data) ? json_decode($content->data) : '';
  876. $data = '<xmp>' . print_r($data, true) . '</xmp>';
  877. $response['result'] = 'success';
  878. $response['status'] = $status;
  879. $response['url'] = htmlspecialchars($result['url']);
  880. $response['data'] = $data;
  881. return print(json_encode($response));
  882. }
  883. $this->view->method = $method;
  884. $this->view->filePath = $filePath;
  885. $this->display();
  886. }
  887. /**
  888. * 通过接口进行sql查询并返回结果。
  889. * Query sql.
  890. *
  891. * @param string $keyField
  892. * @access public
  893. * @return string
  894. */
  895. public function sql($keyField = '')
  896. {
  897. if(!$this->config->features->apiSQL) return printf($this->lang->api->error->disabled, '$config->features->apiSQL');
  898. $sql = isset($_POST['sql']) ? $this->post->sql : '';
  899. $output = $this->api->sql($sql, $keyField);
  900. $output['sql'] = $sql;
  901. $this->output = json_encode($output);
  902. print($this->output);
  903. }
  904. /**
  905. * 获取接口类型和数据结构组成的数组。
  906. * Get options of type.
  907. *
  908. * @param int $libID
  909. * @access public
  910. * @return void
  911. */
  912. private function getTypeOptions($libID)
  913. {
  914. $options = array();
  915. /* 获取接口类型。 */
  916. foreach($this->lang->api->paramsTypeOptions as $key => $item)
  917. {
  918. $options[] = array('label' => $item, 'value' => $key);
  919. }
  920. /* Get all struct by libID. */
  921. $structs = $this->api->getStructListByLibID($libID);
  922. foreach($structs as $struct)
  923. {
  924. $options[] = array('label' => $struct->name, 'value' => $struct->id);
  925. }
  926. $this->view->typeOptions = $options;
  927. }
  928. /**
  929. * Ajax获取库所属产品或者项目的下拉菜单。
  930. * Ajax get objectType drop menu.
  931. *
  932. * @param string $objectType
  933. * @param int $objectID
  934. * @param int $libID
  935. * @access public
  936. * @return void
  937. */
  938. public function ajaxGetDropMenu($objectType, $objectID, $libID = 0)
  939. {
  940. $objects = $this->api->getGroupedObjects();
  941. $programs = $this->loadModel('program')->getList('all', 'order_asc', 'top');
  942. $programs = array_filter($programs, function($program) {return $program->parent == '0';});
  943. $this->view->objectType = $objectType;
  944. $this->view->objectID = $objectID;
  945. $this->view->libID = $libID;
  946. $this->view->programs = $programs;
  947. $this->view->products = $objects['product'];
  948. $this->view->projects = $objects['project'];
  949. $this->view->nolinkLibs = $objects['nolink'];
  950. $this->display();
  951. }
  952. /**
  953. * 编辑接口库下的子目录。
  954. * Edit a catalog.
  955. *
  956. * @param int $moduleID
  957. * @param string $type doc|api
  958. * @access public
  959. * @return void
  960. */
  961. public function editCatalog($moduleID, $type)
  962. {
  963. echo $this->fetch('tree', 'edit', "moduleID=$moduleID&type=$type");
  964. }
  965. /**
  966. * 删除接口库下的子目录。
  967. * Delete a catalog.
  968. *
  969. * @param int $moduleID
  970. * @access public
  971. * @return void
  972. */
  973. public function deleteCatalog($moduleID)
  974. {
  975. echo $this->fetch('tree', 'delete', "moduleID=$moduleID&confirm=yes");
  976. }
  977. /**
  978. * 排序接口库下的子目录。
  979. * Catalog sort.
  980. *
  981. * @access public
  982. * @return void
  983. */
  984. public function sortCatalog()
  985. {
  986. if(!empty($_POST['orders']))
  987. {
  988. foreach($_POST['orders'] as $id => $order)
  989. {
  990. $this->dao->update(TABLE_MODULE)->set('`order`')->eq($order)->where('id')->eq($id)->andWhere('type')->eq('api')->exec();
  991. }
  992. }
  993. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  994. return $this->send(array('result' => 'success'));
  995. }
  996. /**
  997. * 点击dropMenu后的页面跳转。
  998. * Get api list.
  999. *
  1000. * @param int $objectID
  1001. * @param string $objectType
  1002. * @access public
  1003. * @return void
  1004. */
  1005. public function ajaxGetList($objectID, $objectType)
  1006. {
  1007. helper::setcookie('objectType', $objectType);
  1008. helper::setcookie('objectID', (string)$objectID);
  1009. $this->objectType = $objectType;
  1010. $this->objectID = $objectID;
  1011. $this->locate(inlink('index'));
  1012. }
  1013. }