xmind.class.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <?php
  2. /**
  3. * The xmind library of zentaopms, can be used to bakup and restore a database.
  4. *
  5. * @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(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 Mengyi Liu <liumengyi@easycorp.ltd>
  8. * @package Xmind
  9. * @version $Id$
  10. * @link http://www.zentao.net
  11. */
  12. class xmind
  13. {
  14. /**
  15. * Add suffix before string.
  16. *
  17. * @param string $str
  18. * @param string $suffix
  19. * @access public
  20. * @return string
  21. */
  22. public function toText($str, $suffix)
  23. {
  24. if(empty($suffix)) return $str;
  25. return $str . '[' . $suffix . ']';
  26. }
  27. /**
  28. * Create module node.
  29. *
  30. * @param DOMDocument $xmlDoc
  31. * @param array $context
  32. * @param DOMElement $productTopics
  33. * @param array $moduleTopics
  34. * @access public
  35. * @return void
  36. */
  37. function createModuleTopic($xmlDoc, $context, $productTopics, &$moduleTopics)
  38. {
  39. $config = $context['config'];
  40. $moduleList = $context['moduleList'];
  41. $caseModules = array_column($context['caseList'], 'moduleID');
  42. $caseModules = array_filter($caseModules);
  43. $caseModules = array_combine($caseModules, $caseModules);
  44. foreach($moduleList as $key => $name)
  45. {
  46. if(!isset($caseModules[$key])) continue;
  47. $suffix = $config['module'] . ':' . $key;
  48. $moduleTopic = $this->createTopic($xmlDoc, $name, $suffix, array('nodeType' => 'module'));
  49. $moduleChildrenTopics = $this->createTopics($xmlDoc);
  50. $moduleChildren = $xmlDoc->createElement('children');
  51. $moduleChildren->appendChild($moduleChildrenTopics);
  52. $moduleTopic->appendChild($moduleChildren);
  53. $productTopics->appendChild($moduleTopic);
  54. $moduleTopics[$key] = $moduleChildrenTopics;
  55. }
  56. }
  57. /**
  58. * Create scene node.
  59. *
  60. * @param DOMDocument $xmlDoc
  61. * @param array $context
  62. * @param DOMElement $productTopics
  63. * @param array $moduleTopics
  64. * @param array $sceneTopics
  65. * @access public
  66. * @return void
  67. */
  68. function createSceneTopic($xmlDoc, $context, $productTopics, &$moduleTopics, &$sceneTopics)
  69. {
  70. $config = $context['config'];
  71. $topScenes = $context['topScenes'];
  72. $caseScenes = array_column($context['caseList'], 'moduleID');
  73. $caseScenes = array_filter($caseScenes);
  74. $caseScenes = array_combine($caseScenes, $caseScenes);
  75. foreach($topScenes as $key => $scene)
  76. {
  77. if(!isset($caseScenes[$key])) continue;
  78. $suffix = $config['scene'] . ':' . $scene->sceneID;
  79. $sceneTopic = $this->createTopic($xmlDoc, $scene->sceneName, $suffix, array('nodeType' => 'scene'));
  80. $sceneChildrenTopics = $this->createTopics($xmlDoc);
  81. $sceneChildren = $xmlDoc->createElement('children');
  82. $sceneChildren->appendChild($sceneChildrenTopics);
  83. $sceneTopic->appendChild($sceneChildren);
  84. $this->createNextChildScenesTopic($scene, $sceneTopic, $xmlDoc, $context, $moduleTopics, $sceneTopics);
  85. if(isset($moduleTopics[$scene->moduleID]))
  86. {
  87. $moduleTopic = $moduleTopics[$scene->moduleID];
  88. $moduleTopic->appendChild($sceneTopic);
  89. }
  90. else
  91. {
  92. $productTopics->appendChild($sceneTopic);
  93. }
  94. $sceneTopics[$scene->sceneID] = $sceneChildrenTopics;
  95. }
  96. }
  97. /**
  98. * Create next child scene node.
  99. *
  100. * @param object $parentScene
  101. * @param object $parentTopic
  102. * @param DOMDocument $xmlDoc
  103. * @param array $context
  104. * @param array $moduleTopics
  105. * @param array $sceneTopics
  106. * @access public
  107. * @return void
  108. */
  109. function createNextChildScenesTopic($parentScene,$parentTopic, $xmlDoc, $context, &$moduleTopics, &$sceneTopics)
  110. {
  111. $sceneMaps = $context['sceneMaps'];
  112. $config = $context['config'];
  113. foreach($sceneMaps as $scene)
  114. {
  115. if($scene->parentID != $parentScene->sceneID) continue;
  116. $suffix = $config['scene'] . ':' . $scene->sceneID;
  117. $sceneTopic = $this->createTopic($xmlDoc, $scene->sceneName, $suffix, array('nodeType'=>'scene'));
  118. $this->createNextChildScenesTopic($scene, $sceneTopic, $xmlDoc, $context, $moduleTopics, $sceneTopics);
  119. $sceneChildrenTopics = $this->createTopics($xmlDoc);
  120. $sceneChildren = $xmlDoc->createElement('children');
  121. $sceneChildren->appendChild($sceneChildrenTopics);
  122. $sceneTopic->appendChild($sceneChildren);
  123. $sceneTopics[$scene->sceneID] = $sceneChildrenTopics;
  124. }
  125. }
  126. /**
  127. * Create test case node.
  128. *
  129. * @param DOMDocument $xmlDoc
  130. * @param array $context
  131. * @param object $productTopic
  132. * @param array $moduleTopics
  133. * @param array $sceneTopics
  134. * @access public
  135. * @return void
  136. */
  137. function createTestcaseTopic($xmlDoc, $context, $productTopic, &$moduleTopics, &$sceneTopics)
  138. {
  139. $caseList = $context['caseList'];
  140. foreach($caseList as $case)
  141. {
  142. if(empty($case->testcaseID)) continue;
  143. if($case->sceneID && isset($sceneTopics[$case->sceneID]))
  144. {
  145. $this->createOneTestcaseTopic($case, $xmlDoc, $context, $sceneTopics[$case->sceneID]);
  146. }
  147. else
  148. {
  149. if($case->moduleID && isset($moduleTopics[$case->moduleID]))
  150. {
  151. $this->createOneTestcaseTopic($case, $xmlDoc, $context, $moduleTopics[$case->moduleID]);
  152. }
  153. else
  154. {
  155. $this->createOneTestcaseTopic($case, $xmlDoc, $context, $productTopic);
  156. }
  157. }
  158. }
  159. }
  160. /**
  161. * Create one test case node.
  162. *
  163. * @param object $case
  164. * @param DOMDocument $xmlDoc
  165. * @param array $context
  166. * @param object $parentTopic
  167. * @access public
  168. * @return void
  169. */
  170. function createOneTestcaseTopic($case, $xmlDoc, $context, $parentTopic)
  171. {
  172. $stepList = $context['stepList'];
  173. $config = $context['config'];
  174. $suffix = $config['case'] . ':'.$case->testcaseID . ','.$config['pri'] . ':'.$case->pri;
  175. $caseTopic = $this->createTopic($xmlDoc, $case->name, $suffix, array('nodeType'=>'testcase'));
  176. $caseChildrenTopics = $this->createTopics($xmlDoc);
  177. $caseChildren = $xmlDoc->createElement('children');
  178. $caseChildren->appendChild($caseChildrenTopics);
  179. $caseTopic->appendChild($caseChildren);
  180. $parentTopic->appendChild($caseTopic);
  181. $this->createPreconditionTopic($xmlDoc, $config, $caseChildrenTopics, $case->precondition);
  182. $topStepList = $this->findTopStepListByCase($case, $stepList);
  183. $this->createStepTopic($xmlDoc, $config, $caseChildrenTopics, $stepList, $topStepList);
  184. }
  185. /**
  186. * 生成用例前置条件节点。
  187. * Create precondition node.
  188. *
  189. * @param DOMDocument $xmlDoc
  190. * @param array $config
  191. * @param object $parentTopic
  192. * @param string $precondition
  193. * @access private
  194. * @return void
  195. */
  196. private function createPreconditionTopic($xmlDoc, $config, $parentTopics, $precondition)
  197. {
  198. if(empty($precondition)) return false;
  199. $preconditionTopic = $this->createTopic($xmlDoc, $precondition, $config['precondition'], array('nodeType' => 'precondition'));
  200. $parentTopics->appendChild($preconditionTopic);
  201. }
  202. /**
  203. * 生成用例步骤节点。
  204. * Create step node.
  205. *
  206. * @param DOMDocument $xmlDoc
  207. * @param array $config
  208. * @param object $parentTopic
  209. * @param array $allSteps
  210. * @param array $steps
  211. * @access private
  212. * @return void
  213. */
  214. private function createStepTopic($xmlDoc, $config, $parentTopics, $allSteps, $steps)
  215. {
  216. foreach($steps as $step)
  217. {
  218. $subSteps = $this->findSubStepListByStep($step, $allSteps);
  219. $suffix = count($subSteps) > 0 ? $config['group'] : '';
  220. $stepTopic = $this->createTopic($xmlDoc, $step->desc, $suffix, array('nodeType' => 'step'));
  221. $stepChildrenTopics = $this->createTopics($xmlDoc);
  222. $stepChildren = $xmlDoc->createElement('children');
  223. $stepChildren->appendChild($stepChildrenTopics);
  224. if($subSteps)
  225. {
  226. $this->createStepTopic($xmlDoc, $config, $stepChildrenTopics, $allSteps, $subSteps);
  227. }
  228. else if(!empty($step->expect))
  229. {
  230. $expectTopic = $this->createTopic($xmlDoc, $step->expect, '', array('nodeType' => 'expect'));
  231. $stepChildrenTopics->appendChild($expectTopic);
  232. }
  233. $stepTopic->appendChild($stepChildren);
  234. $parentTopics->appendChild($stepTopic);
  235. }
  236. }
  237. /**
  238. * Find substep list by step.
  239. *
  240. * @param object $step
  241. * @param array $stepList
  242. * @access public
  243. * @return array
  244. */
  245. function findSubStepListByStep($step, $stepList)
  246. {
  247. $subList = array();
  248. foreach($stepList as $one)
  249. {
  250. if($one->parentID == $step->stepID) $subList[] = $one;
  251. }
  252. return $subList;
  253. }
  254. /**
  255. * Find top step list by case.
  256. *
  257. * @param object $case
  258. * @param array $stepList
  259. * @access public
  260. * @return array
  261. */
  262. public function findTopStepListByCase($case, $stepList)
  263. {
  264. $topList = array();
  265. foreach($stepList as $step)
  266. {
  267. if($step->parentID == '0' && $step->testcaseID == $case->testcaseID) $topList[] = $step;
  268. }
  269. return $topList;
  270. }
  271. /**
  272. * Create xmind topic.
  273. *
  274. * @param DOMDocument $xmlDoc
  275. * @param string $text
  276. * @param string $suffix
  277. * @param array $attrs
  278. * @access public
  279. * @return object
  280. */
  281. public function createTopic($xmlDoc, $text, $suffix = '', $attrs = array())
  282. {
  283. $topic = $xmlDoc->createElement('topic');
  284. $titleAttr = $xmlDoc->createElement('title', $this->toText($text, $suffix));
  285. $topic->appendChild($titleAttr);
  286. $idAttr = $xmlDoc->createElement('id', uniqid());
  287. $topic->appendChild($idAttr);
  288. foreach($attrs as $key => $value)
  289. {
  290. $attr = $xmlDoc->createAttribute($key);
  291. $attrValue = $xmlDoc->createTextNode($value);
  292. $attr->appendChild($attrValue);
  293. $topic->appendChild($attr);
  294. }
  295. return $topic;
  296. }
  297. /**
  298. * Get substring between mark1 and mark2 from kw.
  299. *
  300. * @param string $str
  301. * @param string $suffix
  302. * @access public
  303. * @return string
  304. */
  305. function getBetween($kw1, $mark1, $mark2)
  306. {
  307. $kw = $kw1;
  308. $kw = '123' . $kw . '123';
  309. $st = strripos($kw, $mark1);
  310. $ed = strripos($kw, $mark2);
  311. if(($st == false || $ed == false) || $st >= $ed) return 0;
  312. $kw = substr($kw, ($st + 1), ($ed - $st - 1));
  313. return $kw;
  314. }
  315. /**
  316. * Judgment ends with a string.
  317. *
  318. * @param string $haystack
  319. * @param string $needle
  320. * @access public
  321. * @return string
  322. */
  323. function endsWith($haystack, $needle)
  324. {
  325. return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
  326. }
  327. /**
  328. * Create children topics.
  329. *
  330. * @param DOMDocument $xmlDoc
  331. * @access public
  332. * @return void
  333. */
  334. function createChildrenTopics($xmlDoc)
  335. {
  336. $topics = $this->createTopics($xmlDoc);
  337. $children = $xmlDoc->createElement('children');
  338. $children->appendChild($topics);
  339. return $children;
  340. }
  341. /**
  342. * Create topics.
  343. *
  344. * @param DOMDocument $xmlDoc
  345. * @access public
  346. * @return void
  347. */
  348. public function createTopics($xmlDoc)
  349. {
  350. $type = $xmlDoc->createAttribute('type');
  351. $type->value = 'attached';
  352. $topics = $xmlDoc->createElement('topics');
  353. $topics->appendChild($type);
  354. return $topics;
  355. }
  356. /**
  357. * Init xmap content.
  358. *
  359. * @param DOMDocument $xmlDoc
  360. * @access public
  361. * @return void
  362. */
  363. public function initXmapContent($xmlDoc)
  364. {
  365. $xmapContent = $xmlDoc->createElement('xmap-content');
  366. $attrs = array();
  367. $attrs['xmlns'] = "urn:xmind:xmap:xmlns:content:2.0";
  368. $attrs['xmlns:fo'] = "http://www.w3.org/1999/XSL/Format";
  369. $attrs['xmlns:svg'] = "http://www.w3.org/2000/svg";
  370. $attrs['xmlns:xhtml'] = "http://www.w3.org/1999/xhtml";
  371. $attrs['xmlns:xlink'] = "http://www.w3.org/1999/xlink";
  372. foreach($attrs as $key => $value)
  373. {
  374. $attr = $xmlDoc->createAttribute($key);
  375. $attrValue = $xmlDoc->createTextNode($value);
  376. $attr->appendChild($attrValue);
  377. $xmapContent->appendChild($attr);
  378. }
  379. return $xmapContent;
  380. }
  381. }