438 lines
13 KiB
PHP
438 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* The xmind library of zentaopms, can be used to bakup and restore a database.
|
|
*
|
|
* @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
|
|
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
* @author Mengyi Liu <liumengyi@easycorp.ltd>
|
|
* @package Xmind
|
|
* @version $Id$
|
|
* @link http://www.zentao.net
|
|
*/
|
|
class xmind
|
|
{
|
|
/**
|
|
* Add suffix before string.
|
|
*
|
|
* @param string $str
|
|
* @param string $suffix
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
public function toText($str, $suffix)
|
|
{
|
|
if(empty($suffix)) return $str;
|
|
return $str . '[' . $suffix . ']';
|
|
}
|
|
|
|
/**
|
|
* Create module node.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $context
|
|
* @param DOMElement $productTopics
|
|
* @param array $moduleTopics
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
function createModuleTopic($xmlDoc, $context, $productTopics, &$moduleTopics)
|
|
{
|
|
$config = $context['config'];
|
|
$moduleList = $context['moduleList'];
|
|
$caseModules = array_column($context['caseList'], 'moduleID');
|
|
$caseModules = array_filter($caseModules);
|
|
$caseModules = array_combine($caseModules, $caseModules);
|
|
|
|
foreach($moduleList as $key => $name)
|
|
{
|
|
if(!isset($caseModules[$key])) continue;
|
|
|
|
$suffix = $config['module'] . ':' . $key;
|
|
$moduleTopic = $this->createTopic($xmlDoc, $name, $suffix, array('nodeType' => 'module'));
|
|
|
|
$moduleChildrenTopics = $this->createTopics($xmlDoc);
|
|
$moduleChildren = $xmlDoc->createElement('children');
|
|
$moduleChildren->appendChild($moduleChildrenTopics);
|
|
|
|
$moduleTopic->appendChild($moduleChildren);
|
|
$productTopics->appendChild($moduleTopic);
|
|
|
|
$moduleTopics[$key] = $moduleChildrenTopics;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create scene node.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $context
|
|
* @param DOMElement $productTopics
|
|
* @param array $moduleTopics
|
|
* @param array $sceneTopics
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
function createSceneTopic($xmlDoc, $context, $productTopics, &$moduleTopics, &$sceneTopics)
|
|
{
|
|
$config = $context['config'];
|
|
$topScenes = $context['topScenes'];
|
|
$caseScenes = array_column($context['caseList'], 'moduleID');
|
|
$caseScenes = array_filter($caseScenes);
|
|
$caseScenes = array_combine($caseScenes, $caseScenes);
|
|
|
|
foreach($topScenes as $key => $scene)
|
|
{
|
|
if(!isset($caseScenes[$key])) continue;
|
|
|
|
$suffix = $config['scene'] . ':' . $scene->sceneID;
|
|
$sceneTopic = $this->createTopic($xmlDoc, $scene->sceneName, $suffix, array('nodeType' => 'scene'));
|
|
|
|
$sceneChildrenTopics = $this->createTopics($xmlDoc);
|
|
$sceneChildren = $xmlDoc->createElement('children');
|
|
$sceneChildren->appendChild($sceneChildrenTopics);
|
|
$sceneTopic->appendChild($sceneChildren);
|
|
|
|
$this->createNextChildScenesTopic($scene, $sceneTopic, $xmlDoc, $context, $moduleTopics, $sceneTopics);
|
|
|
|
if(isset($moduleTopics[$scene->moduleID]))
|
|
{
|
|
$moduleTopic = $moduleTopics[$scene->moduleID];
|
|
$moduleTopic->appendChild($sceneTopic);
|
|
}
|
|
else
|
|
{
|
|
$productTopics->appendChild($sceneTopic);
|
|
}
|
|
|
|
$sceneTopics[$scene->sceneID] = $sceneChildrenTopics;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create next child scene node.
|
|
*
|
|
* @param object $parentScene
|
|
* @param object $parentTopic
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $context
|
|
* @param array $moduleTopics
|
|
* @param array $sceneTopics
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
function createNextChildScenesTopic($parentScene,$parentTopic, $xmlDoc, $context, &$moduleTopics, &$sceneTopics)
|
|
{
|
|
$sceneMaps = $context['sceneMaps'];
|
|
$config = $context['config'];
|
|
|
|
foreach($sceneMaps as $scene)
|
|
{
|
|
if($scene->parentID != $parentScene->sceneID) continue;
|
|
|
|
$suffix = $config['scene'] . ':' . $scene->sceneID;
|
|
$sceneTopic = $this->createTopic($xmlDoc, $scene->sceneName, $suffix, array('nodeType'=>'scene'));
|
|
|
|
$this->createNextChildScenesTopic($scene, $sceneTopic, $xmlDoc, $context, $moduleTopics, $sceneTopics);
|
|
|
|
$sceneChildrenTopics = $this->createTopics($xmlDoc);
|
|
$sceneChildren = $xmlDoc->createElement('children');
|
|
$sceneChildren->appendChild($sceneChildrenTopics);
|
|
$sceneTopic->appendChild($sceneChildren);
|
|
|
|
$sceneTopics[$scene->sceneID] = $sceneChildrenTopics;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create test case node.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $context
|
|
* @param object $productTopic
|
|
* @param array $moduleTopics
|
|
* @param array $sceneTopics
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
function createTestcaseTopic($xmlDoc, $context, $productTopic, &$moduleTopics, &$sceneTopics)
|
|
{
|
|
$caseList = $context['caseList'];
|
|
|
|
foreach($caseList as $case)
|
|
{
|
|
if(empty($case->testcaseID)) continue;
|
|
|
|
if($case->sceneID && isset($sceneTopics[$case->sceneID]))
|
|
{
|
|
$this->createOneTestcaseTopic($case, $xmlDoc, $context, $sceneTopics[$case->sceneID]);
|
|
}
|
|
else
|
|
{
|
|
if($case->moduleID && isset($moduleTopics[$case->moduleID]))
|
|
{
|
|
$this->createOneTestcaseTopic($case, $xmlDoc, $context, $moduleTopics[$case->moduleID]);
|
|
}
|
|
else
|
|
{
|
|
$this->createOneTestcaseTopic($case, $xmlDoc, $context, $productTopic);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create one test case node.
|
|
*
|
|
* @param object $case
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $context
|
|
* @param object $parentTopic
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
function createOneTestcaseTopic($case, $xmlDoc, $context, $parentTopic)
|
|
{
|
|
$stepList = $context['stepList'];
|
|
$config = $context['config'];
|
|
$suffix = $config['case'] . ':'.$case->testcaseID . ','.$config['pri'] . ':'.$case->pri;
|
|
$caseTopic = $this->createTopic($xmlDoc, $case->name, $suffix, array('nodeType'=>'testcase'));
|
|
|
|
$caseChildrenTopics = $this->createTopics($xmlDoc);
|
|
$caseChildren = $xmlDoc->createElement('children');
|
|
$caseChildren->appendChild($caseChildrenTopics);
|
|
$caseTopic->appendChild($caseChildren);
|
|
|
|
$parentTopic->appendChild($caseTopic);
|
|
|
|
$this->createPreconditionTopic($xmlDoc, $config, $caseChildrenTopics, $case->precondition);
|
|
|
|
$topStepList = $this->findTopStepListByCase($case, $stepList);
|
|
$this->createStepTopic($xmlDoc, $config, $caseChildrenTopics, $stepList, $topStepList);
|
|
}
|
|
|
|
/**
|
|
* 生成用例前置条件节点。
|
|
* Create precondition node.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $config
|
|
* @param object $parentTopic
|
|
* @param string $precondition
|
|
* @access private
|
|
* @return void
|
|
*/
|
|
private function createPreconditionTopic($xmlDoc, $config, $parentTopics, $precondition)
|
|
{
|
|
if(empty($precondition)) return false;
|
|
$preconditionTopic = $this->createTopic($xmlDoc, $precondition, $config['precondition'], array('nodeType' => 'precondition'));
|
|
$parentTopics->appendChild($preconditionTopic);
|
|
}
|
|
|
|
/**
|
|
* 生成用例步骤节点。
|
|
* Create step node.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @param array $config
|
|
* @param object $parentTopic
|
|
* @param array $allSteps
|
|
* @param array $steps
|
|
* @access private
|
|
* @return void
|
|
*/
|
|
private function createStepTopic($xmlDoc, $config, $parentTopics, $allSteps, $steps)
|
|
{
|
|
foreach($steps as $step)
|
|
{
|
|
$subSteps = $this->findSubStepListByStep($step, $allSteps);
|
|
$suffix = count($subSteps) > 0 ? $config['group'] : '';
|
|
|
|
$stepTopic = $this->createTopic($xmlDoc, $step->desc, $suffix, array('nodeType' => 'step'));
|
|
|
|
$stepChildrenTopics = $this->createTopics($xmlDoc);
|
|
$stepChildren = $xmlDoc->createElement('children');
|
|
$stepChildren->appendChild($stepChildrenTopics);
|
|
|
|
if($subSteps)
|
|
{
|
|
$this->createStepTopic($xmlDoc, $config, $stepChildrenTopics, $allSteps, $subSteps);
|
|
}
|
|
else if(!empty($step->expect))
|
|
{
|
|
$expectTopic = $this->createTopic($xmlDoc, $step->expect, '', array('nodeType' => 'expect'));
|
|
$stepChildrenTopics->appendChild($expectTopic);
|
|
}
|
|
|
|
$stepTopic->appendChild($stepChildren);
|
|
|
|
$parentTopics->appendChild($stepTopic);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find substep list by step.
|
|
*
|
|
* @param object $step
|
|
* @param array $stepList
|
|
* @access public
|
|
* @return array
|
|
*/
|
|
function findSubStepListByStep($step, $stepList)
|
|
{
|
|
$subList = array();
|
|
foreach($stepList as $one)
|
|
{
|
|
if($one->parentID == $step->stepID) $subList[] = $one;
|
|
}
|
|
|
|
return $subList;
|
|
}
|
|
|
|
/**
|
|
* Find top step list by case.
|
|
*
|
|
* @param object $case
|
|
* @param array $stepList
|
|
* @access public
|
|
* @return array
|
|
*/
|
|
public function findTopStepListByCase($case, $stepList)
|
|
{
|
|
$topList = array();
|
|
foreach($stepList as $step)
|
|
{
|
|
if($step->parentID == '0' && $step->testcaseID == $case->testcaseID) $topList[] = $step;
|
|
}
|
|
|
|
return $topList;
|
|
}
|
|
|
|
/**
|
|
* Create xmind topic.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @param string $text
|
|
* @param string $suffix
|
|
* @param array $attrs
|
|
* @access public
|
|
* @return object
|
|
*/
|
|
public function createTopic($xmlDoc, $text, $suffix = '', $attrs = array())
|
|
{
|
|
$topic = $xmlDoc->createElement('topic');
|
|
|
|
$titleAttr = $xmlDoc->createElement('title', $this->toText($text, $suffix));
|
|
$topic->appendChild($titleAttr);
|
|
|
|
$idAttr = $xmlDoc->createElement('id', uniqid());
|
|
$topic->appendChild($idAttr);
|
|
|
|
foreach($attrs as $key => $value)
|
|
{
|
|
$attr = $xmlDoc->createAttribute($key);
|
|
$attrValue = $xmlDoc->createTextNode($value);
|
|
|
|
$attr->appendChild($attrValue);
|
|
$topic->appendChild($attr);
|
|
}
|
|
|
|
return $topic;
|
|
}
|
|
|
|
/**
|
|
* Get substring between mark1 and mark2 from kw.
|
|
*
|
|
* @param string $str
|
|
* @param string $suffix
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
function getBetween($kw1, $mark1, $mark2)
|
|
{
|
|
$kw = $kw1;
|
|
$kw = '123' . $kw . '123';
|
|
$st = strripos($kw, $mark1);
|
|
$ed = strripos($kw, $mark2);
|
|
|
|
if(($st == false || $ed == false) || $st >= $ed) return 0;
|
|
|
|
$kw = substr($kw, ($st + 1), ($ed - $st - 1));
|
|
return $kw;
|
|
}
|
|
|
|
/**
|
|
* Judgment ends with a string.
|
|
*
|
|
* @param string $haystack
|
|
* @param string $needle
|
|
* @access public
|
|
* @return string
|
|
*/
|
|
function endsWith($haystack, $needle)
|
|
{
|
|
return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
|
|
}
|
|
|
|
/**
|
|
* Create children topics.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
function createChildrenTopics($xmlDoc)
|
|
{
|
|
$topics = $this->createTopics($xmlDoc);
|
|
|
|
$children = $xmlDoc->createElement('children');
|
|
$children->appendChild($topics);
|
|
return $children;
|
|
}
|
|
|
|
/**
|
|
* Create topics.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function createTopics($xmlDoc)
|
|
{
|
|
$type = $xmlDoc->createAttribute('type');
|
|
$type->value = 'attached';
|
|
|
|
$topics = $xmlDoc->createElement('topics');
|
|
$topics->appendChild($type);
|
|
|
|
return $topics;
|
|
}
|
|
|
|
/**
|
|
* Init xmap content.
|
|
*
|
|
* @param DOMDocument $xmlDoc
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function initXmapContent($xmlDoc)
|
|
{
|
|
$xmapContent = $xmlDoc->createElement('xmap-content');
|
|
$attrs = array();
|
|
$attrs['xmlns'] = "urn:xmind:xmap:xmlns:content:2.0";
|
|
$attrs['xmlns:fo'] = "http://www.w3.org/1999/XSL/Format";
|
|
$attrs['xmlns:svg'] = "http://www.w3.org/2000/svg";
|
|
$attrs['xmlns:xhtml'] = "http://www.w3.org/1999/xhtml";
|
|
$attrs['xmlns:xlink'] = "http://www.w3.org/1999/xlink";
|
|
|
|
foreach($attrs as $key => $value)
|
|
{
|
|
$attr = $xmlDoc->createAttribute($key);
|
|
$attrValue = $xmlDoc->createTextNode($value);
|
|
|
|
$attr->appendChild($attrValue);
|
|
$xmapContent->appendChild($attr);
|
|
}
|
|
return $xmapContent;
|
|
}
|
|
}
|