| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399 |
- <?php
- /**
- * The zen file of testcase module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
- * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Mengyi Liu <liumengyi@easycorp.ltd>
- * @package testcase
- * @link https://www.zentao.net
- */
- class testcaseZen extends testcase
- {
- /**
- * 检查是否有产品,如果没有则跳转到创建产品的页面。
- * Check products.
- *
- * @access protected
- * @return void
- */
- protected function checkProducts()
- {
- $objectID = 0;
- $tab = $this->app->tab == 'project' || $this->app->tab == 'execution' ? $this->app->tab : 'qa';
- if($this->app->tab == 'project')
- {
- $objectID = $this->session->project;
- }
- elseif($this->app->tab == 'execution')
- {
- $objectID = $this->session->execution;
- }
- if(empty($this->products) && (helper::isAjaxRequest('zin') || helper::isAjaxRequest('fetch'))) $this->locate($this->createLink('product', 'showErrorNone', "moduleName=$tab&activeMenu=testcase&objectID=$objectID"));
- }
- /**
- * 设置列表页面的 cookie。
- * Set browse cookie.
- *
- * @param int $productID
- * @param string|bool $branch
- * @param string $browseType
- * @param string $param
- * @access protected
- * @return void
- */
- protected function setBrowseCookie($productID, $branch, $browseType = '', $param = '')
- {
- helper::setcookie('preProductID', $productID);
- helper::setcookie('preBranch', $branch);
- $productChanged = $this->cookie->preProductID != $productID;
- $branchChanged = $this->cookie->preBranch != $branch;
- if($productChanged || $branchChanged || $browseType == 'bysearch')
- {
- $_COOKIE['caseModule'] = 0;
- helper::setcookie('caseModule', '0');
- }
- if($browseType == 'bymodule') helper::setcookie('caseModule', $param);
- if($browseType == 'bysuite') helper::setcookie('caseSuite', $param);
- }
- /**
- * 获取列表页面的 branch 参数。
- * Get browse branch param.
- *
- * @param string $branch
- * @access protected
- * @return string
- */
- protected function getBrowseBranch($branch)
- {
- if($branch === '') $branch = $this->cookie->preBranch;
- if($branch === '' || $branch === false) $branch = '0';
- return $branch;
- }
- /**
- * 设置列表页面的 session。
- * Set Browse session.
- *
- * @param int $productID
- * @param string|bool $branch
- * @param int $moduleID
- * @param string $browseType
- * @param string $orderBy
- * @access protected
- * @return void
- */
- protected function setBrowseSession($productID, $branch, $moduleID, $browseType = '', $orderBy = '')
- {
- if($browseType != 'bymodule') $this->session->set('caseBrowseType', $browseType);
- $this->session->set('caseList', $this->app->getURI(true), $this->app->tab);
- $this->session->set('productID', $productID);
- $this->session->set('branch', $branch, 'qa');
- $this->session->set('moduleID', $moduleID);
- $this->session->set('browseType', $browseType);
- $this->session->set('orderBy', $orderBy);
- $this->session->set('testcaseOrderBy', '`sort` asc', $this->app->tab);
- $this->session->set('testcaseOrderBy', '`sort` asc');
- }
- /**
- * 设置列表页面的导航。
- * Set menu in browse.
- *
- * @param int $productID
- * @param string|bool $branch
- * @param int $projectID
- * @access protected
- * @return array
- */
- protected function setBrowseMenu($productID, $branch, $projectID = 0)
- {
- /* 在不同的应用中,设置不同的导航。 */
- /* Set menu, save session. */
- if($this->app->tab == 'project')
- {
- if(empty($projectID)) $projectID = (int)$this->session->project;
- if(empty($projectID)) return array($productID, $branch);
- $linkedProducts = $this->product->getProducts($projectID, 'all', '', false);
- $this->products = count($linkedProducts) > 1 ? array('0' => $this->lang->product->all) + $linkedProducts : $linkedProducts;
- $productID = count($linkedProducts) > 1 ? $productID : key($linkedProducts);
- $hasProduct = $this->dao->findById($projectID)->from(TABLE_PROJECT)->fetch('hasProduct');
- if(!$hasProduct) unset($this->config->testcase->search['fields']['product']);
- $branch = intval($branch) > 0 ? $branch : 'all';
- $this->loadModel('project')->setMenu($projectID);
- $this->view->products = $this->products;
- $this->view->projectID = $projectID;
- $this->view->hasProduct = $hasProduct;
- }
- else
- {
- $this->loadModel('qa')->setMenu($productID, $branch);
- }
- return array($productID, $branch);
- }
- /**
- * 设置菜单。
- * Set menu.
- *
- * @param int $projectID
- * @param int $executionID
- * @param int $productID
- * @param string|int $branch
- * @access protected
- * @return void
- */
- protected function setMenu($projectID = 0, $executionID = 0, $productID = 0, $branch = '')
- {
- if($this->app->tab == 'project') $this->loadModel('project')->setMenu($projectID);
- if($this->app->tab == 'execution') $this->loadModel('execution')->setMenu($executionID);
- if($this->app->tab == 'qa') $this->testcase->setMenu($productID, $branch);
- $this->view->projectID = $projectID;
- $this->view->executionID = $executionID;
- }
- /**
- * 构建搜索表单。
- * Build the search form.
- *
- * @param int $productID
- * @param int $queryID
- * @param int $projectID
- * @access protected
- * @return void
- * @param string $actionURL
- */
- protected function buildBrowseSearchForm($productID, $queryID, $projectID, $actionURL)
- {
- if($this->app->rawModule == 'testcase') $this->config->testcase->search['onMenuBar'] = 'yes';
- $searchProducts = $this->product->getPairs('', 0, '', 'all');
- $this->testcase->buildSearchForm($productID, $searchProducts, $queryID, $actionURL, $projectID);
- }
- /**
- * 展示从用例库导入的用例。
- * Assign the cases imported from the library.
- *
- * @param int $productID
- * @param string $branch
- * @param int $libID
- * @param string $orderBy
- * @param int $queryID
- * @param array $libraries
- * @param array $cases
- * @access protected
- * @return void
- * @param int $projectID
- */
- protected function assignForImportFromLib($productID, $branch, $libID, $orderBy, $queryID, $libraries, $projectID, $cases)
- {
- $product = $this->loadModel('product')->getById($productID);
- $branches = array();
- if($product->type != 'normal')
- {
- $this->loadModel('branch');
- $branches = array(BRANCH_MAIN => $this->lang->branch->main) + $this->branch->getPairs($productID, 'active', $projectID);
- }
- foreach($branches as $branchID => $branchName) $canImportModules[$branchID] = $this->testcase->getCanImportedModules($productID, $libID, $branchID, 'items', $cases);
- if(empty($branches)) $canImportModules[0] = $this->testcase->getCanImportedModules($productID, $libID, 0, 'items', $cases);
- /* Build the search form. */
- $actionURL = $this->createLink('testcase', 'importFromLib', "productID={$productID}&branch={$branch}&libID={$libID}&orderBy={$orderBy}&browseType=bySearch&queryID=myQueryID");
- $this->config->testcase->search['module'] = 'testsuite';
- $this->config->testcase->search['onMenuBar'] = 'no';
- $this->config->testcase->search['actionURL'] = $actionURL;
- $this->config->testcase->search['queryID'] = $queryID;
- $this->config->testcase->search['fields']['lib'] = $this->lang->testcase->lib;
- $this->config->testcase->search['params']['lib'] = array('operator' => '=', 'control' => 'select', 'values' => array('' => '', $libID => $libraries[$libID], 'all' => $this->lang->caselib->all));
- $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($libID, 'caselib');
- if(!$this->config->testcase->needReview) unset($this->config->testcase->search['params']['status']['values']['wait']);
- unset($this->config->testcase->search['fields']['product']);
- unset($this->config->testcase->search['fields']['branch']);
- $this->loadModel('search')->setSearchParams($this->config->testcase->search);
- $this->view->productID = $productID;
- $this->view->branch = $branch;
- $this->view->libID = $libID;
- $this->view->orderBy = $orderBy;
- $this->view->queryID = $queryID;
- $this->view->product = $product;
- $this->view->branches = $branches;
- $this->view->canImportModules = $canImportModules;
- }
- /**
- * 展示创建 testcase 的相关变量。
- * Show the variables associated with the creation testcase.
- *
- * @param int $productID
- * @param string $branch
- * @param int $moduleID
- * @param string $from
- * @param int $param
- * @param int $storyID
- * @access protected
- * @return void
- */
- protected function assignCreateVars($productID, $branch = '', $moduleID = 0, $from = '', $param = 0, $storyID = 0)
- {
- $product = $this->product->getById($productID);
- if(!isset($this->products[$productID])) $this->products[$productID] = $product->name;
- $projectID = $from == 'project' ? $param : $this->session->project;
- $executionID = $from == 'execution' ? $param : 0;
- $testcaseID = $from && strpos('testcase|work|contribute', $from) !== false ? $param : 0;
- /* 设置分支。 */
- /* Set branches. */
- if($this->app->tab == 'project' || $this->app->tab == 'execution')
- {
- $objectID = $this->app->tab == 'project' ? $this->session->project : $executionID;
- $productBranches = isset($product->type) && $product->type != 'normal' ? $this->loadModel('execution')->getBranchByProduct(array($productID), $objectID, 'noclosed|withMain') : array();
- $branches = isset($productBranches[$productID]) ? $productBranches[$productID] : array('');
- $branch = empty($branch) ? (string)key($branches) : $branch;
- }
- else
- {
- $branches = isset($product->type) && $product->type != 'normal' ? $this->loadModel('branch')->getPairs($productID, 'active') : array();
- }
- /* 设置菜单。 */
- /* Set menu. */
- $executionID = $executionID ? $executionID : (int)$this->session->execution;
- $this->setMenu((int)$this->session->project, $executionID, $productID, $branch);
- /* 初始化用例数据。 */
- /* Initialize the testcase. */
- $case = $this->initTestcase($storyID, $testcaseID, $from == 'bug' ? $param : 0);
- if($case->story && $this->loadModel('story')->fetchByID($case->story)->product != $productID) $case->story = 0;
- /* 设置模块和需求。 */
- /* Set modules. */
- $this->assignModulesForCreate($productID, $moduleID, $branch, $case->story, $branches);
- $this->view->product = $product;
- $this->view->projectID = isset($projectID) ? $projectID : 0;
- $this->view->currentSceneID = $testcaseID > 0 ? $case->scene : (int)$this->cookie->lastCaseScene;
- $this->view->case = $case;
- $this->view->executionID = $executionID;
- $this->view->branch = $branch;
- $this->view->branches = $branches;
- $this->view->from = $from;
- $this->view->param = $param;
- }
- /**
- * 展示创建场景的相关变量。
- * Show the variables associated with the creation scene.
- *
- * @param int $productID
- * @param string $branch
- * @param int $moduleID
- * @access protected
- * @return void
- */
- protected function assignCreateSceneVars($productID, $branch = '', $moduleID = 0)
- {
- $product = $this->product->getById($productID);
- if(!isset($this->products[$productID])) $this->products[$productID] = $product->name;
- /* 获取分支键值对及当前分支。*/
- /* Get branch pairs and set current branch. */
- if($this->app->tab == 'project' || $this->app->tab == 'execution')
- {
- /* 在项目或执行中显示时只显示项目或执行关联的分支键值对。*/
- /* When showing in a project or execution, only the branch key-value pairs associated with the project or execution are shown. */
- $objectID = $this->app->tab == 'project' ? $this->session->project : 0;
- $productBranches = isset($product->type) && $product->type != 'normal' ? $this->loadModel('execution')->getBranchByProduct(array($productID), $objectID, 'noclosed|withMain') : array();
- $branches = isset($productBranches[$productID]) ? $productBranches[$productID] : array();
- if(!empty($branches)) $branch = (string)key($branches);
- }
- else
- {
- $branches = isset($product->type) && $product->type != 'normal' ? $this->loadModel('branch')->getPairs($productID, 'active') : array();
- }
- /* 设置菜单。 */
- /* Set menu. */
- $this->setMenu((int)$this->session->project, (int)$this->session->execution, $productID, $branch);
- $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testcase->newScene;
- $this->view->modules = $this->tree->getOptionMenu($productID, 'case', 0, ($branch === 'all' || !isset($branches[$branch])) ? 'all' : (string)$branch);
- $this->view->scenes = $this->testcase->getSceneMenu($productID, $moduleID, ($branch === 'all' || !isset($branches[$branch])) ? 'all' : (string)$branch);
- $this->view->moduleID = $moduleID ? (int)$moduleID : (int)$this->cookie->lastCaseModule;
- $this->view->parent = (int)$this->cookie->lastCaseScene;
- $this->view->product = $product;
- $this->view->branch = $branch;
- $this->view->branches = $branches;
- }
- /**
- * 处理编辑场景相关的变量。
- * Assign variables of edit a scene.
- *
- * @param object $oldScene
- * @access protected
- * @return void
- */
- protected function assignEditSceneVars($oldScene)
- {
- $productID = $oldScene->product;
- $branchID = (string)$oldScene->branch;
- $moduleID = $oldScene->module;
- $parentID = $oldScene->parent;
- /* 设置菜单。 */
- /* Set menu. */
- $this->setMenu((int)$this->session->project, (int)$this->session->execution, $productID, $branchID);
- $product = $this->product->getByID($productID);
- if(!isset($this->products[$productID])) $this->products[$productID] = $product->name;
- /* Display status of branch. */
- $branches = array();
- $branchList = $this->loadModel('branch')->getList($productID, 0, 'all');
- foreach($branchList as $branch) $branches[$branch->id] = $branch->name . ($branch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
- if(!isset($branches[$branchID]))
- {
- $sceneBranch = $this->branch->getByID($branchID, $productID, '');
- if($sceneBranch) $branches[$branchID] = $sceneBranch->name . ($sceneBranch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
- }
- $modules = $this->tree->getOptionMenu($productID, 'case', 0, $branchID);
- if(!isset($modules[$moduleID])) $modules += $this->tree->getModulesName($moduleID);
- $scenes = $this->testcase->getSceneMenu($productID, $moduleID, $branchID, 0, $oldScene->id);
- if(!isset($scenes[$parentID])) $scenes += $this->testcase->getScenesName((array)$parentID);
- $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testcase->editScene;
- $this->view->products = $this->products;
- $this->view->product = $product;
- $this->view->branches = $branches;
- $this->view->modules = $modules;
- $this->view->scenes = $scenes;
- $this->view->scene = $oldScene;
- }
- /**
- * 展示创建 testcase 的模块变量。
- * Show the modules associated with the creation testcase.
- *
- * @param int $productID
- * @param int $moduleID
- * @param string $branch
- * @param int $storyID
- * @param array $branches
- * @access protected
- * @return void
- */
- protected function assignModulesForCreate($productID, $moduleID, $branch, $storyID, $branches)
- {
- if($storyID)
- {
- $story = $this->loadModel('story')->getByID($storyID);
- if(empty($moduleID)) $moduleID = $story->module;
- }
- $currentModuleID = !$moduleID && $productID == (int)$this->cookie->lastCaseProduct ? (int)$this->cookie->lastCaseModule : $moduleID;
- $this->view->currentModuleID = $currentModuleID;
- $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, 'case', 0, $branch === 'all' || !isset($branches[$branch]) ? '0' : $branch);
- $this->view->sceneOptionMenu = $this->testcase->getSceneMenu($productID, $moduleID, $branch === 'all' || !isset($branches[$branch]) ? '0' : $branch);
- }
- /**
- * 处理浏览页面的用例列表。
- * Process cases for browse page.
- *
- * @param array $cases
- * @access public
- * @return array
- */
- public function processCasesForBrowse($cases)
- {
- if(!$cases) return [];
- foreach($cases as $case)
- {
- $case->caseID = $case->id;
- $case->id = 'case_' . $case->id; // 给用例 ID 加前缀以防止和场景 ID 重复。Add prefix to case ID to prevent it from conflicting with scene ID.
- $case->parent = 0;
- $case->isScene = false;
- $case->title = htmlspecialchars_decode($case->title);
- }
- $caseScenes = array_unique(array_filter(array_column($cases, 'scene'))); // 获取用例的场景 ID。Get unique scene IDs from cases.
- if(!$caseScenes) return $cases;
- $pathList = $this->dao->select('path')->from(TABLE_SCENE)->where('deleted')->eq('0')->andWhere('id')->in($caseScenes)->fetchPairs(); // 获取场景的路径列表。Get path list of scenes.
- $idList = array_unique(array_filter(explode(',', implode(',', $pathList))));
- $scenes = $this->dao->select('*')->from(TABLE_SCENE)->where('deleted')->eq('0')->andWhere('id')->in($idList)->orderBy('grade_desc, sort_asc')->fetchAll('id'); // 获取场景列表。Get scene list.
- foreach($cases as $case)
- {
- if(!isset($scenes[$case->scene])) continue;
- $scene = $scenes[$case->scene];
- $scene->hasCase = true;
- $case->parent = $scene->id;
- $case->grade = $scene->grade + 1;
- $case->path = $scene->path . $case->id . ',';
- }
- $this->dao->setTable(TABLE_CASE);
- $fieldTypes = $this->dao->getFieldsType();
- foreach($scenes as $scene)
- {
- $scene = $this->testcase->buildSceneBaseOnCase($scene, $fieldTypes);
- $scene->scene = $scene->parent;
- if(isset($scene->hasCase))
- {
- if (isset($scenes[$scene->parent])) $scenes[$scene->parent]->hasCase = true; // 如果子场景有用例,那么父场景也有用例。If the child scene has a use case, the parent scene also has a use case.
- }
- else
- {
- $scene->hasCase = false; // hasCase 为 false 时在页面上显示“暂无用例”。If hasCase is false, show "No use case" on the page.
- }
- }
- return array_merge($scenes, $cases);
- }
- /**
- * 指定浏览用例页面的用例列表。
- * Assign cases for browse page.
- *
- * @param int $productID
- * @param string $branch
- * @param string $browseType
- * @param int $queryID
- * @param int $moduleID
- * @param string $caseType
- * @param string $orderBy
- * @param int $recTotal
- * @param int $recPerPage
- * @param int $pageID
- * @access protected
- * @return void
- * @param string $from
- */
- protected function assignCasesForBrowse($productID, $branch, $browseType, $queryID, $moduleID, $caseType, $orderBy, $recTotal, $recPerPage, $pageID, $from = 'testcase')
- {
- $this->app->loadClass('pager', $static = true);
- $pager = new pager($recTotal, $recPerPage, $pageID);
- $sort = common::appendOrder($orderBy);
- if(strpos($sort, 'caseID') !== false) $sort = str_replace('caseID', 'id', $sort);
- $cases = $this->testcase->getTestCases($productID, $branch, $browseType, $queryID, $moduleID, $caseType, 'no', $sort, $pager, $from);
- $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
- $cases = $this->loadModel('story')->checkNeedConfirm($cases);
- $cases = $this->testcase->appendData($cases);
- if($this->config->edition != 'open')
- {
- $caseRelatedObjectList = $this->loadModel('custom')->getRelatedObjectList(array_keys($cases), 'testcase', 'byRelation', true);
- foreach($cases as $caseID => $case) $case->relatedObject = zget($caseRelatedObjectList, $caseID, 0);
- }
- $this->view->cases = $this->processCasesForBrowse($cases);
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
- }
- /**
- *
- * 指定模块树。
- * Assign module tree in browse page.
- *
- * @param int $productID
- * @param string $branch
- * @param int $projectID
- * @access protected
- * @return void
- */
- protected function assignModuleTreeForBrowse($productID, $branch, $projectID)
- {
- if($projectID && empty($productID))
- {
- $this->view->moduleTree = $this->tree->getCaseTreeMenu($projectID, $productID, 0, array('treeModel', 'createCaseLink'));
- }
- else
- {
- $this->view->moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('projectID' => $projectID, 'productID' => $productID), $branch);
- }
- }
- /**
- *
- * 指定产品和分支。
- * Assign product and branch.
- *
- * @param int $productID
- * @param string $branch
- * @param int $projectID
- * @access protected
- * @return void
- */
- protected function assignProductAndBranchForBrowse($productID, $branch, $projectID = 0)
- {
- /* 根据产品类型判断是否展示分支,获取分支选项信息和带标签的分支选项信息。*/
- /* Judge whether to show branch according to the type of product, get branch option and branch tag option. */
- $product = $this->product->getByID($productID);
- $showBranch = false;
- $branchOption = array();
- $branchTagOption = array();
- if($product && $product->type != 'normal')
- {
- /* Display of branch label. */
- $showBranch = $this->loadModel('branch')->showBranch($productID);
- /* Display status of branch. */
- $branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
- foreach($branches as $branchInfo)
- {
- $branchOption[$branchInfo->id] = $branchInfo->name;
- $branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
- }
- }
- $this->view->productID = $productID;
- $this->view->productName = zget($this->products, $productID, '');
- $this->view->product = $product;
- $this->view->branch = (!empty($product) and $product->type != 'normal') ? $branch : 0;
- $this->view->branchOption = $branchOption;
- $this->view->branchTagOption = $branchTagOption;
- }
- /**
- * 指定变量。
- * Assign variables.
- *
- * @param int $productID
- * @param string $branch
- * @param string $browseType
- * @param int $projectID
- * @param int $param
- * @param int $moduleID
- * @param int $suiteID
- * @param string $caseType
- * @access protected
- * @return void
- */
- protected function assignForBrowse($productID, $branch, $browseType, $projectID, $param, $moduleID, $suiteID, $caseType)
- {
- $showModule = !empty($this->config->testcase->browse->showModule) ? $this->config->testcase->browse->showModule : '';
- $tree = $moduleID ? $this->tree->getByID($moduleID) : '';
- $this->view->title = zget($this->products, $productID, '') . $this->lang->hyphen . $this->lang->testcase->common;
- $this->view->projectID = $projectID;
- $this->view->projectType = !empty($projectID) ? $this->dao->select('model')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch('model') : '';
- $this->view->browseType = $browseType;
- $this->view->param = $param;
- $this->view->moduleID = $moduleID;
- $this->view->moduleName = $moduleID ? $tree->name : $this->lang->tree->all;
- $this->view->suiteID = $suiteID;
- $this->view->caseType = $caseType;
- $this->view->users = $this->user->getPairs('noletter');
- $this->view->modules = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch == 'all' ? '0' : $branch);
- $this->view->iscenes = $this->testcase->getSceneMenu($productID, $moduleID);
- $this->view->suiteList = $this->loadModel('testsuite')->getSuites($productID);
- $this->view->modulePairs = $showModule ? $this->tree->getModulePairs($productID, 'case', $showModule) : array();
- $this->view->libraries = $this->loadModel('caselib')->getLibraries();
- $this->view->stories = array('') + $this->loadModel('story')->getPairs($productID);
- $this->view->automation = $this->loadModel('zanode')->getAutomationByProduct($productID);
- if($projectID)
- {
- $productPairs = $this->product->getProductPairsByProject($projectID);
- $this->view->switcherParams = "projectID={$projectID}&productID={$productID}¤tMethod=testcase";
- $this->view->switcherText = zget($productPairs, $productID, $this->lang->product->all);
- $this->view->project = $this->loadModel('project')->getByID($projectID);
- $this->view->switcherObjectID = $productID;
- }
- }
- /**
- * 处理更新请求数据。
- * Processing request data.
- *
- * @param form $formData
- * @param object $oldBug
- * @access protected
- * @return object|false
- * @param object $oldCase
- */
- protected function prepareEditExtras($formData, $oldCase)
- {
- foreach($formData->data->expects as $key => $value)
- {
- if(!empty($value) && empty($formData->data->steps[$key]))
- {
- dao::$errors['message'][] = sprintf($this->lang->testcase->stepsEmpty, $key);
- return false;
- }
- }
- if(!empty($_FILES['scriptFile'])) unset($_FILES['scriptFile']);
- $result = $this->getStatusForUpdate($oldCase);
- if(!$result || !is_array($result)) return $result;
- list($stepChanged, $status) = $result;
- $case = $formData->add('id', $oldCase->id)
- ->add('version', $stepChanged ? (int)$oldCase->version + 1 : (int)$oldCase->version)
- ->add('lastEditedBy', $this->app->user->account)
- ->add('lastEditedDate', helper::now())
- ->add('stepChanged', $stepChanged)
- ->setForce('status', $status)
- ->setDefault('story,branch', 0)
- ->setDefault('stage', '')
- ->setDefault('deleteFiles', array())
- ->setDefault('storyVersion', $oldCase->storyVersion)
- ->setDefault('script', $oldCase->script)
- ->setIF($formData->data->story != false && $formData->data->story != $oldCase->story, 'storyVersion', $this->loadModel('story')->getVersion((int)$formData->data->story))
- ->setIF(!$formData->data->linkCase, 'linkCase', '')
- ->setIF($formData->data->auto == 'auto' && $formData->data->script, 'script', htmlentities($formData->data->script))
- ->setIF($formData->data->auto == 'no', 'script', '')
- ->join('stage', ',')
- ->join('linkCase', ',')
- ->cleanInt('story,product,branch,module')
- ->skipSpecial('script')
- ->remove('files,labels,scriptFile,scriptName')
- ->removeIF($formData->data->auto == 'auto' && !$formData->data->script, 'script')
- ->get();
- if(!empty($oldCase->lib) && empty($oldCase->product) && !empty($_POST['lib'])) $case->lib = $this->post->lib;
- return !empty($this->config->testcase->editor->edit['id']) ? $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->edit['id'], $this->post->uid) : $case;
- }
- /**
- * 提前处理用例数据。
- * Preprocess case.
- *
- * @param object $case
- * @access protected
- * @return object
- */
- protected function preProcessForEdit($case)
- {
- /* 初始化用例步骤。*/
- /* Unit the steps of case. */
- if(empty($case->steps))
- {
- $step = new stdclass();
- $step->type = 'step';
- $step->desc = '';
- $step->name = '';
- $step->expect = '';
- $case->steps[] = $step;
- }
- return $case;
- }
- /**
- * 设置编辑用例库用例的导航。
- * Set menu for editing lib case.
- *
- * @param object $case
- * @param array $libraries
- * @access protected
- * @return void
- */
- protected function setMenuForLibCaseEdit($case, $libraries)
- {
- if($this->app->tab == 'project')
- {
- $this->loadModel('project')->setMenu($this->session->project);
- }
- else
- {
- $this->loadModel('caselib')->setLibMenu($libraries, $case->lib);
- }
- }
- /**
- * 设置编辑用例的导航。
- * Set menu for editing case.
- *
- * @param object $case
- * @param int $executionID
- * @access protected
- * @return void
- */
- protected function setMenuForCaseEdit($case, $executionID)
- {
- if($this->app->tab == 'project')
- {
- $this->loadModel('project')->setMenu($case->project);
- $this->view->projectID = $case->project;
- }
- if($this->app->tab == 'execution')
- {
- if(!$executionID) $executionID = $case->execution;
- $this->loadModel('execution')->setMenu($executionID);
- $this->view->executionID = $executionID;
- }
- if($this->app->tab == 'qa') $this->testcase->setMenu($case->product, $case->branch);
- }
- /**
- * 指定编辑用例库用例的数据。
- * Assign data for editint lib case.
- *
- * @param object $case
- * @param array $libraries
- * @access protected
- * @return void
- */
- protected function assignForEditLibCase($case, $libraries)
- {
- $this->view->title = "CASE #$case->id $case->title - " . $libraries[$case->lib];
- $this->view->isLibCase = true;
- $this->view->libraries = $libraries;
- $this->view->moduleOptionMenu = $this->tree->getOptionMenu($case->lib, 'caselib', 0);
- $this->view->libName = $libraries[$case->lib];
- $this->view->libID = $case->lib;
- }
- /**
- * 指定编辑用例的数据。
- * Assign for editing case.
- *
- * @param object $case
- * @param int $executionID
- * @access protected
- * @return void
- */
- protected function assignForEditCase($case, $executionID)
- {
- $product = $this->product->getByID($case->product);
- if(!isset($this->products[$case->product])) $this->products[$case->product] = $product->name;
- $this->view->title = $this->products[$case->product] . $this->lang->hyphen . $this->lang->testcase->edit;
- $this->view->isLibCase = false;
- $this->view->product = $product;
- $this->view->products = $this->products;
- $this->view->branch = $this->cookie->preBranch;
- $this->assignBranchForEdit($case, $executionID);
- $this->assignModuleOptionMenuForEdit($case);
- }
- /**
- * 指定编辑用例的分支。
- * Assign branch data for editing case.
- *
- * @param object $case
- * @param int $executionID
- * @access private
- * @return void
- */
- private function assignBranchForEdit($case, $executionID)
- {
- $objectID = 0;
- if($this->app->tab == 'execution') $objectID = $executionID;
- if($this->app->tab == 'project') $objectID = $case->project;
- $branches = $this->loadModel('branch')->getList($case->product, $objectID, 'all');
- $branchTagOption = array();
- foreach($branches as $branchInfo) $branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
- if(!isset($branchTagOption[$case->branch]))
- {
- $caseBranch = $this->branch->getByID($case->branch, $case->product, '');
- $branchTagOption[$case->branch] = $case->branch == BRANCH_MAIN ? $caseBranch : ($caseBranch->name . ($caseBranch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
- }
- $this->view->branchTagOption = $branchTagOption;
- }
- /**
- * 指定编辑用的模块选项。
- * Assign module option menu for editing case.
- *
- * @param object $case
- * @access private
- * @return void
- */
- private function assignModuleOptionMenuForEdit($case)
- {
- $moduleOptionMenu = $this->tree->getOptionMenu($case->product, 'case', 0, (string)$case->branch);
- if($case->lib && $case->fromCaseID)
- {
- $lib = $this->loadModel('caselib')->getByID($case->lib);
- $libModules = $this->tree->getOptionMenu($case->lib, 'caselib');
- foreach($libModules as $moduleID => $moduleName)
- {
- if($moduleID == 0) continue;
- $moduleOptionMenu[$moduleID] = $lib->name . $moduleName;
- }
- }
- if(!isset($moduleOptionMenu[$case->module])) $moduleOptionMenu += $this->tree->getModulesName((array)$case->module);
- $this->view->moduleOptionMenu = $moduleOptionMenu;
- }
- /**
- * 指定编辑用例的其他数据。
- * Assign other data for editing case.
- *
- * @param int $productID
- * @param object $case
- * @param array $testtasks
- * @access protected
- * @return void
- */
- protected function assignForEdit($productID, $case, $testtasks)
- {
- $sceneOptionMenu = $this->testcase->getSceneMenu($productID, $case->module);
- if(!isset($sceneOptionMenu[$case->scene])) $sceneOptionMenu += $this->testcase->getScenesName((array)$case->scene);
- $forceNotReview = $this->testcase->forceNotReview();
- if($forceNotReview) unset($this->lang->testcase->statusList['wait']);
- $this->view->case = $case;
- $this->view->testtasks = $testtasks;
- $this->view->forceNotReview = $forceNotReview;
- $this->view->sceneOptionMenu = $sceneOptionMenu;
- $this->view->users = $this->user->getPairs('noletter');
- $this->view->actions = $this->loadModel('action')->getList('case', $case->id);
- }
- /**
- * 指定批量编辑用例的数据。
- * Assign for editing case.
- *
- * @param int $productID
- * @param string $branch
- * @param string $type
- * @param array $cases
- * @access protected
- * @return void
- */
- protected function assignForBatchEdit($productID, $branch, $type, $cases)
- {
- list($productIdList, $libIdList) = $this->assignTitleForBatchEdit($productID, $branch, $type, $cases);
- /* 设置模块。 */
- /* Set modules. */
- $modules = array();
- $branchProduct = false;
- $branchTagOption = array();
- $products = $this->product->getByIdList($productIdList);
- $branches = array(0 => 0);
- foreach($products as $product)
- {
- if($product->type != 'normal')
- {
- $branches = $this->loadModel('branch')->getList($product->id, 0, 'all');
- foreach($branches as $branchInfo) $branchTagOption[$product->id][$branchInfo->id] = "/{$product->name}/{$branchInfo->name}" . ($branchInfo->status == 'closed' ? " ({$this->lang->branch->statusList['closed']})" : '');
- $branchProduct = true;
- }
- $modulePairs = $this->tree->getOptionMenu($product->id, 'case', 0, array_keys($branches));
- foreach($modulePairs as $branchID => $branchModules)
- {
- $modules['case'][$product->id][$branchID] = array();
- foreach($branchModules as $moduleID => $module) $modules['case'][$product->id][$branchID][] = array('text' => $module, 'value' => $moduleID);
- }
- }
- foreach($libIdList as $libID)
- {
- $libModules = $this->tree->getOptionMenu($libID, 'caselib');
- $modules['lib'][$libID][0] = array();
- foreach($libModules as $moduleID => $module) $modules['lib'][$libID][0][] = array('text' => $module, 'value' => $moduleID);
- }
- if($this->app->tab == 'project') $branchTagOption = $this->loadModel('branch')->getPairsByProjectProduct($this->session->project, $productID);
- /* 指派模块和场景。 */
- /* Assign modules and scenes. */
- $this->assignModuleAndSceneForBatchEdit($productID, $branch, $branches, $cases, $modules);
- /* 设置自定义字段。 */
- /* Set custom fields. */
- foreach(explode(',', $this->config->testcase->list->customBatchEditFields) as $field) $customFields[$field] = $this->lang->testcase->$field;
- $this->view->customFields = $customFields;
- $this->view->showFields = $this->config->testcase->custom->batchEditFields;
- $this->view->branchTagOption = $branchTagOption;
- $this->view->products = $products;
- $this->view->branchProduct = $branchProduct;
- }
- /**
- * 指派用例库下批量编辑用例的数据。
- * Assign for batch editing case in caselib.
- *
- * @param int $libID
- * @access protected
- * @return void
- */
- protected function assignLibForBatchEdit($libID)
- {
- $libraries = $this->loadModel('caselib')->getLibraries();
- $this->loadModel('caselib')->setLibMenu($libraries, $libID);
- $this->view->libID = $libID;
- }
- /**
- * 指定批量编辑用例的页面标题。
- * Assign title for editing case.
- *
- * @param int $productID
- * @param string $branch
- * @param string $type
- * @param array $cases
- * @access protected
- * @return array
- */
- protected function assignTitleForBatchEdit($productID, $branch, $type, $cases)
- {
- $productIdList = array();
- $libIdList = array();
- /* 指派用例库用例。 */
- /* Assign lib cases. */
- if($type == 'lib')
- {
- $libID = $productID;
- $libIdList = array($libID);
- $libraries = $this->loadModel('caselib')->getLibraries();
- /* Remove story custom fields from caselib */
- $this->config->testcase->list->customBatchEditFields = str_replace(',story', '', $this->config->testcase->list->customBatchEditFields);
- $this->config->testcase->custom->batchEditFields = str_replace(',story', '', $this->config->testcase->custom->batchEditFields);
- /* Set caselib menu. */
- $this->caselib->setLibMenu($libraries, $libID);
- $this->view->title = $libraries[$libID] . $this->lang->hyphen . $this->lang->testcase->batchEdit;
- }
- /* 指派测试用例。 */
- /* Assign test cases. */
- elseif($productID)
- {
- $product = $this->product->getByID($productID);
- $productIdList = array($productID);
- $this->setMenu((int)$this->session->project, (int)$this->session->execution, $productID, $branch);
- $this->view->title = $product->name . $this->lang->hyphen . $this->lang->testcase->batchEdit;
- }
- /* 指派地盘标签下的用例。 */
- /* Assign cases of my tab. */
- else
- {
- foreach($cases as $case)
- {
- if($case->lib == 0) $productIdList[$case->product] = $case->product;
- if($case->lib > 0) $libIdList[$case->lib] = $case->lib;
- }
- $this->view->title = $this->lang->testcase->batchEdit;
- }
- return array($productIdList, $libIdList);
- }
- /**
- * 指定批量编辑用例的模块和场景标题。
- * Assign modules and scenes for editing case.
- *
- * @param int $productID
- * @param string $branch
- * @param array $branches
- * @param array $cases
- * @param array $modules
- * @access protected
- * @return void
- */
- protected function assignModuleAndSceneForBatchEdit($productID, $branch, $branches, $cases, $modules)
- {
- $moduleScenes = array();
- $moduleScenesPairs = array();
- $modulePairs = array();
- $scenePairs = array();
- foreach($cases as $case)
- {
- $case->story = $case->story ? $case->story : '';
- /* 设置用例模块。 */
- /* Set case module. */
- $objectID = $case->lib > 0 ? $case->lib : $case->product;
- $objectType = $case->lib > 0 ? 'lib' : 'case';
- if(isset($modules[$objectType][$objectID][$case->branch]))
- {
- $modulePairs[$case->id] = $modules[$objectType][$objectID][$case->branch];
- }
- elseif(isset($modules[$objectType][$objectID]))
- {
- $modulePairs[$case->id] = $modules[$objectType][$objectID][0];
- }
- else
- {
- $module = $this->tree->getByID($case->module);
- $modulePairs[$case->id][] = array('text' => zget($module, 'name', ''), 'value' => $case->module);
- }
- /* 设置用例场景。 */
- /* Set case 场景. */
- if(!isset($moduleScenesPairs[$case->module]))
- {
- $moduleScenesPairs[$case->module] = array();
- $moduleScenes = $this->testcase->getSceneMenu($productID, $case->module, $branch !== 'all' && !isset($branches[$branch]) ? '0' : $branch);
- foreach($moduleScenes as $sceneID => $scene) $moduleScenesPairs[$case->module][] = array('text' => $scene, 'value' => $sceneID);
- }
- $scenePairs[$case->id][] = $moduleScenesPairs[$case->module];
- if(!isset($scenes[$case->scene])) $scenePairs[$case->id][] = array('text' => '/' . $this->testcase->fetchSceneName($case->scene), 'value' => $case->scene);
- }
- $this->view->scenePairs = $scenePairs;
- $this->view->modulePairs = $modulePairs;
- }
- /**
- * 指派导入的数据。
- * Assign show imported data.
- *
- * @param int $productID
- * @param string $branch
- * @param array $caseData
- * @param int $stepVars
- * @param int $pagerID
- * @param int $maxImport
- * @access protected
- * @return void
- */
- protected function assignShowImportVars($productID, $branch, $caseData, $stepVars, $pagerID, $maxImport)
- {
- if(empty($caseData)) return $this->sendError($this->lang->error->noData, $this->createLink('testcase', 'browse', "productID={$productID}&branch={$branch}"));
- /* 设置模块。 */
- /* Set modules. */
- $modules = array();
- $branches = $this->loadModel('branch')->getPairs($productID, 'active');
- $branchModules = $this->loadModel('tree')->getOptionMenu($productID, 'case', 0, empty($branches) ? array(0) : array_keys($branches));
- foreach($branchModules as $branchID => $moduleList)
- {
- $modules[$branchID] = array();
- foreach($moduleList as $moduleID => $moduleName)
- {
- $modules[$branchID][$moduleID] = $moduleName;
- }
- }
- /* 如果导入的用例数大于最大导入数,则在最大导入时截取。 */
- /* If the number of imported cases is greater than max import, intercept at max import. */
- $allCount = count($caseData);
- $allPager = 1;
- if($allCount > $this->config->file->maxImport)
- {
- if(empty($maxImport))
- {
- $this->view->allCount = $allCount;
- $this->view->maxImport = $maxImport;
- $this->view->productID = $productID;
- $this->view->branch = $branch;
- $this->display();
- exit;
- }
- $allPager = ceil($allCount / $maxImport);
- $caseData = array_slice($caseData, ($pagerID - 1) * $maxImport, $maxImport, true);
- }
- if(empty($caseData)) return $this->sendError($this->lang->error->noData, $this->createLink('testcase', 'browse', "productID={$productID}&branch={$branch}"));
- /* 判断输入的用例是否超出限制,并设定session。 */
- /* Judge whether the imported cases is too large and set session. */
- $countInputVars = count($caseData) * 12 + $stepVars;
- $showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
- if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
- $this->view->modules = $modules;
- $this->view->caseData = $caseData;
- $this->view->branches = $branches;
- $this->view->allCount = $allCount;
- $this->view->allPager = $allPager;
- $this->view->isEndPage = $pagerID >= $allPager;
- $this->view->pagerID = $pagerID;
- }
- /**
- * Add edit action.
- *
- * @param int $caseID
- * @param string $oldStatus
- * @param string $status
- * @param array $changes
- * @param string $comment
- * @access protected
- * @return void
- */
- protected function addEditAction($caseID, $oldStatus, $status, $changes = array(), $comment = '')
- {
- $this->loadModel('action');
- $action = !empty($changes) ? 'Edited' : 'Commented';
- $actionID = $this->action->create('case', $caseID, $action, $comment);
- $this->action->logHistory($actionID, $changes);
- if($oldStatus != 'wait' && $status == 'wait') $this->action->create('case', $caseID, 'submitReview');
- }
- /**
- * 指定 testcase 查看的关联的变量。
- * Assign testcase related variables.
- *
- * @param object $case
- * @param string $from
- * @param int $taskID
- * @access protected
- * @return void
- */
- protected function assignCaseForView($case, $from, $taskID)
- {
- $case = $this->loadModel('story')->checkNeedConfirm($case);
- if($from == 'testtask')
- {
- $run = $this->loadModel('testtask')->getRunByCase($taskID, $case->id);
- $case->assignedTo = $run->assignedTo;
- $case->lastRunner = $run->lastRunner;
- $case->lastRunDate = $run->lastRunDate;
- $case->lastRunResult = $run->lastRunResult;
- $case->caseStatus = $case->status;
- $case->status = $run->status;
- $results = $this->testtask->getResults($run->id);
- $result = array_shift($results);
- if($result)
- {
- $case->xml = $result->xml;
- $case->duration = $result->duration;
- }
- }
- $case = $this->testcase->appendCaseFails($case, $from, $taskID);
- $case = $this->processStepsForMindMap($case);
- $sceneOptionMenu = $this->testcase->getSceneMenu($case->product, $case->module);
- if(!isset($sceneOptionMenu[$case->scene])) $sceneOptionMenu += $this->testcase->getScenesName((array)$case->scene);
- $this->view->from = $from;
- $this->view->taskID = $taskID;
- $this->view->runID = $from == 'testcase' || $from == 'testsuite' ? 0 : $run->id;
- $this->view->case = $case;
- $this->view->caseFails = $case->caseFails;
- $this->view->modulePath = $this->tree->getParents($case->module);
- $this->view->caseModule = empty($case->module) ? '' : $this->tree->getById($case->module);
- $this->view->preAndNext = !isOnlybody() ? $this->loadModel('common')->getPreAndNextObject('testcase', $case->id) : '';
- $this->view->users = $this->user->getPairs('noletter');
- $this->view->actions = $this->loadModel('action')->getList('case', $case->id);
- $this->view->scenes = $sceneOptionMenu;
- }
- /**
- * 指定批量创建用例的相关变量。
- * Assign for batch creating case.
- *
- * @param int $productID
- * @param string $branch
- * @param int $moduleID
- * @param int $storyID
- * @access protected
- * @return void
- */
- protected function assignForBatchCreate($productID, $branch = '', $moduleID = 0, $storyID = 0)
- {
- $product = $this->product->getById($productID);
- /* 设置分支。 */
- /* Set branches. */
- if($this->app->tab == 'project' and $product->type != 'normal')
- {
- $this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
- $productBranches = $this->loadModel('execution')->getBranchByProduct(array($productID), $this->session->project, 'noclosed|withMain');
- $branches = isset($productBranches[$productID]) ? $productBranches[$productID] : array();
- $branch = key($branches);
- }
- else
- {
- $branches = $this->loadModel('branch')->getPairs($productID, 'active');
- }
- /* 设置自定义字段和展示字段。 */
- /* Set custom fields and show fields. */
- foreach(explode(',', $this->config->testcase->list->customBatchCreateFields) as $field)
- {
- if($product->type != 'normal') $customFields[$product->type] = $this->lang->product->branchName[$product->type];
- $customFields[$field] = $this->lang->testcase->$field;
- }
- $showFields = sprintf($this->config->testcase->custom->batchCreateFields, $product->type);
- if($product->type == 'normal')
- {
- $showFields = str_replace(array(",branch,", ",platform,"), '', ",$showFields,");
- $showFields = trim($showFields, ',');
- }
- /* 设置需求键对。 */
- /* Set story pairs. */
- $storyPairs = $this->loadModel('story')->getProductStoryPairs($productID, $branch === 'all' ? 0 : $branch, array(), 'active,reviewing', 'id_desc', 50, '', 'story', false);
- $story = $storyID ? $this->story->fetchByID($storyID) : '';
- $storyPairs += $storyID ? array($storyID => $story->id . ':' . $story->title) : array();
- if($storyID && empty($moduleID)) $moduleID = $story->module;
- $this->view->product = $product;
- $this->view->branches = $branches;
- $this->view->customFields = $customFields;
- $this->view->showFields = $showFields;
- $this->view->story = $story;
- $this->view->storyPairs = $this->story->addGradeLabel($storyPairs);
- $this->view->sceneOptionMenu = $this->testcase->getSceneMenu($productID, $moduleID, $branch === 'all' || !isset($branches[$branch]) ? '0' : $branch);
- $this->view->currentModuleID = $moduleID;
- }
- /**
- * 构建创建 testcase 页面数据。
- * Build form fields for creating testcase.
- *
- * @param string $from
- * @param int $param
- * @access protected
- * @return void
- */
- protected function buildCaseForCreate($from, $param)
- {
- $status = $this->getStatusForCreate();
- $case = form::data($this->config->testcase->form->create)
- ->add('status', $status)
- ->setIF($from == 'bug', 'fromBug', $param)
- ->setIF($from == 'project' && $param, 'project', $param)
- ->setIF($from == 'execution' && $param, 'execution', $param)
- ->setIF($from != 'project' && $this->app->tab == 'project', 'project', $this->session->project)
- ->setIF($from != 'execution' && $this->app->tab == 'execution', 'execution', $this->session->execution)
- ->setIF($this->post->project, 'project', $this->post->project) // API will post project param
- ->setIF($this->post->execution, 'execution', $this->post->execution) // API will post execution param
- ->setIF($this->post->auto, 'auto', 'auto')
- ->setIF($this->post->auto && $this->post->script, 'script', $this->post->script ? htmlentities($this->post->script) : '')
- ->setIF($this->post->story, 'storyVersion', $this->loadModel('story')->getVersion((int)$this->post->story))
- ->get();
- /* 如果用例产品是影子产品,同步用例到项目中。 */
- $product = $this->loadModel('product')->getById($case->product);
- if($product->shadow && empty($case->project))
- {
- $project = $this->loadModel('project')->getByShadowProduct($case->product);
- $case->project = $project->id;
- }
- /* 如果用例的项目不为空,且不启用迭代,同步用例到影子迭代中。 */
- if(!empty($case->project))
- {
- if(!isset($project)) $project = $this->loadModel('project')->fetchByID($case->project);
- if(empty($project->multiple)) $case->execution = $this->loadModel('execution')->getNoMultipleID($case->project);
- }
- return !empty($this->config->testcase->editor->create['id']) ? $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->create['id'], $this->post->uid) : $case;
- }
- /**
- * 构建批量创建用例的数据。
- * Build cases for batch creating.
- *
- * @param int $productID
- * @access protected
- * @return array
- */
- protected function buildCasesForBathcCreate($productID)
- {
- $now = helper::now();
- $account = $this->app->user->account;
- $forceNotReview = $this->testcase->forceNotReview();
- $storyVersions = array();
- $testcases = form::batchData($this->config->testcase->form->batchCreate)->get();
- $projectID = $this->app->tab == 'project' ? $this->session->project : 0;
- $executionID = 0;
- if($projectID)
- {
- $project = $this->loadModel('project')->getByID($projectID);
- if(!$project->multiple) $executionID = $this->dao->select('id')->from(TABLE_PROJECT)->where('parent')->eq($projectID)->fetch('id');
- }
- foreach($testcases as $testcase)
- {
- $testcase->product = $productID;
- $testcase->project = $projectID;
- $testcase->execution = $executionID;
- $testcase->openedBy = $account;
- $testcase->openedDate = $now;
- $testcase->status = $forceNotReview || $testcase->review == 0 ? 'normal' : 'wait';
- $testcase->version = 1;
- $testcase->storyVersion = isset($storyVersions[$testcase->story]) ? $storyVersions[$testcase->story] : 0;
- $testcase->stepType = array();
- if($testcase->story && !isset($storyVersions[$testcase->story]))
- {
- if(count($storyVersions) == 0) $this->loadModel('story');
- $testcase->storyVersion = $this->story->getVersion((int)$testcase->story);
- $storyVersions[$testcase->story] = $testcase->storyVersion;
- }
- unset($testcase->review);
- list($testcase->steps, $testcase->stepType) = $this->testcase->processStepsOrExpects($testcase->steps);
- list($testcase->expects) = $this->testcase->processStepsOrExpects($testcase->expects);
- }
- return $testcases;
- }
- /**
- * 构建批量编辑用例的数据。
- * Build cases for batch editing.
- *
- * @param array $oldCases
- * @access protected
- * @return array
- * @param mixed[] $oldSteps
- */
- protected function buildCasesForBathcEdit($oldCases, $oldSteps)
- {
- $caseIdList = array_keys($oldCases);
- if(empty($caseIdList)) return array();
- $now = helper::now();
- $account = $this->app->user->account;
- $cases = form::batchData($this->config->testcase->form->batchEdit)->get();
- $forceNotReview = $this->testcase->forceNotReview();
- foreach($cases as $caseID => $case)
- {
- $oldCase = $oldCases[$caseID];
- $case->id = $caseID;
- $case->product = $oldCase->product;
- $case->lastEditedBy = $account;
- $case->lastEditedDate = $now;
- if(!isset($case->precondition)) $case->precondition = $oldCase->precondition;
- $versionChanged = false;
- if($case->title && $case->title != $oldCase->title) $versionChanged = true;
- if($case->precondition && $case->precondition != $oldCase->precondition) $versionChanged = true;
- list($case->steps, $case->stepType) = $this->testcase->processStepsOrExpects($case->steps);
- list($case->expects) = $this->testcase->processStepsOrExpects($case->expects);
- $oldStep = zget($oldSteps, $caseID, array());
- $stepChanged = $this->testcase->processStepsChanged($case, $oldStep);
- if($stepChanged && !$forceNotReview) $case->status = 'wait';
- if($stepChanged) $versionChanged = true;
- $case->version = $versionChanged ? (int)$oldCase->version + 1 : (int)$oldCase->version;
- $case->stepChanged = $stepChanged;
- }
- return $cases;
- }
- /**
- * 构建导入用例的数据。
- * Build cases for showing imported.
- *
- * @param int $productID
- * @access protected
- * @return array
- */
- protected function buildCasesForShowImport($productID)
- {
- /* 初始化变量。 */
- /* Initialize variables. */
- $now = helper::now();
- $account = $this->app->user->account;
- $cases = form::batchData($this->config->testcase->form->showImport)->get();
- $forceNotReview = $this->testcase->forceNotReview();
- $insert = $this->post->insert;
- $caseIdList = !$insert ? array_keys($this->post->title) : array();
- $oldCases = $this->testcase->getByList($caseIdList);
- $oldSteps = $this->testcase->fetchStepsByList($caseIdList);
- $storyVersionPairs = $this->loadModel('story')->getVersions($this->post->story);
- foreach($cases as $case)
- {
- list($case->steps, $case->stepType) = $this->testcase->processStepsOrExpects($case->steps);
- list($case->expects) = $this->testcase->processStepsOrExpects($case->expects);
- /* 构建更新的用例. */
- /* Build updated case. */
- if(!empty($case->rawID) && !$insert)
- {
- $oldCase = zget($oldCases, $case->rawID, new stdclass());
- $oldStep = zget($oldSteps, $case->rawID, array());
- $stepChanged = $this->testcase->processStepsChanged($case, $oldStep);
- $case->id = $case->rawID;
- $case->product = $productID;
- $case->lastEditedBy = $account;
- $case->lastEditedDate = $now;
- $case->version = $stepChanged ? $oldCase->version + 1 : $oldCase->version;
- if($case->story != $oldCase->story) $case->storyVersion = zget($storyVersionPairs, $case->story, 1);
- $changes = common::createChanges($oldCase, $case);
- if(!$changes && !$stepChanged) unset($cases[$case->rawID]);
- }
- /* 构建插入的用例. */
- /* Build inserted case. */
- else
- {
- $case->product = $productID;
- $case->version = 1;
- $case->openedBy = $this->app->user->account;
- $case->openedDate = $now;
- $case->status = !$forceNotReview ? 'wait' : 'normal';
- if($this->app->tab == 'project') $case->project = $this->session->project;
- if($case->story) $case->storyVersion = zget($storyVersionPairs, $case->story, 1);
- }
- $case->frequency = 1;
- unset($case->rawID);
- }
- return $cases;
- }
- /**
- * 根据 xmind 构建导入用例的数据。
- * Build imported cases by xmind data.
- *
- * @param int $productID
- * @param string $branch
- * @param array $caseList
- * @param bool $isInsert
- * @access protected
- * @return array
- */
- protected function buildCasesByXmind($productID, $branch, $caseList, $isInsert)
- {
- $caseIdList = array_filter(array_map(function($case){return zget($case, 'id', 0);}, $caseList));
- $now = helper::now();
- $forceNotReview = $this->testcase->forceNotReview();
- $account = $this->app->user->account;
- $oldCases = $this->testcase->getByList($caseIdList);
- $oldSteps = $this->testcase->fetchStepsByList($caseIdList);
- $branch = (int)$branch;
- $modules = $this->loadModel('tree')->getOptionMenu($productID, 'case');
- $cases = array();
- foreach($caseList as $caseData)
- {
- $moduleID = (int)$caseData['module'];
- $case = new stdclass();
- $case->module = isset($modules[$moduleID]) ? $moduleID : 0;
- $case->product = $productID;
- $case->branch = $branch;
- $case->title = $caseData['name'];
- $case->pri = $caseData['pri'];
- $case->precondition = $caseData['precondition'];
- $case->tmpPId = $caseData['tmpPId'];
- $case->version = 1;
- $case = $this->testcase->processCaseSteps($case, (object)$caseData);
- $caseID = (int)zget($caseData, 'id', 0);
- $oldCase = zget($oldCases, $caseID, null);
- if(empty($oldCase) || $isInsert)
- {
- $case->type = 'feature';
- $case->status = !$forceNotReview ? 'wait' : 'normal';
- $case->openedBy = $account;
- $case->openedDate = $now;
- }
- else
- {
- $oldStep = zget($oldSteps, $caseID, array());
- $stepChanged = $this->testcase->processStepsChanged($case, $oldStep);
- $case->version = $stepChanged ? (int)$oldCase->version + 1 : (int)$oldCase->version;
- $case->stepChanged = $stepChanged;
- if($stepChanged && !$forceNotReview) $case->status = 'wait';
- $case->id = $caseID;
- $case->lastEditedBy = $account;
- $case->lastEditedDate = $now;
- }
- $cases[] = $case;
- }
- return $cases;
- }
- /**
- * 构建从用例库导入的数据。
- * Build data for importing from lib.
- *
- * @param int $productID
- * @param string $branch
- * @param int $libID
- * @access protected
- * @return array
- */
- protected function buildDataForImportFromLib($productID, $branch, $libID)
- {
- /* 处理模块。 */
- /* Process modules. */
- $preModule = 0;
- $modules = $this->post->module ? $this->post->module : array();
- foreach($modules as $caseID => $module)
- {
- if($module != 'ditto') $preModule = $module;
- if($module == 'ditto') $modules[$caseID] = $preModule;
- }
- /* 处理分支。 */
- /* Process branches. */
- $preBranch = 0;
- $caseModules = array();
- $branches = $this->post->branch;
- $caseIdList = $this->post->caseIdList;
- if(!empty($branches))
- {
- foreach($branches as $caseID => $branch)
- {
- if($branch != 'ditto') $prevBranch = $branch;
- if($branch == 'ditto') $branches[$caseID] = $prevBranch;
- if(!isset($caseModules[$branch]) && in_array($caseID, $caseIdList) !== false) $caseModules[$branch] = $this->testcase->getCanImportedModules($productID, $libID, $branch, 'pairs', $caseIdList);
- }
- }
- else
- {
- $caseModules[$branch] = $this->testcase->getCanImportedModules($productID, $libID, $branch, 'pairs', $caseIdList);
- }
- /* 构建用例。 */
- /* Build cases. */
- $hasImported = '';
- $cases = array();
- $steps = array();
- $files = array();
- $fromCases = $this->testcase->getByList($caseIdList);
- $fromSteps = $this->testcase->getRelatedSteps($caseIdList);
- $fromFiles = $this->testcase->getRelatedFiles($caseIdList);
- foreach($caseIdList as $caseID)
- {
- if(!isset($fromCases[$caseID])) continue;
- $case = clone $fromCases[$caseID];
- $case->lib = 0;
- $case->steps = array();
- $case->expects = array();
- $case->stepType = array();
- $case->product = $productID;
- $case->fromCaseID = $case->id;
- $case->fromCaseVersion = $case->version;
- if(isset($modules[$case->id])) $case->module = $modules[$case->id];
- if(isset($branches[$case->id])) $case->branch = $branches[$case->id];
- unset($case->id);
- if(!$case->scriptedDate) unset($case->scriptedDate);
- if(!$case->reviewedDate) unset($case->reviewedDate);
- if(!$case->lastEditedDate) unset($case->lastEditedDate);
- if(!$case->lastRunDate) unset($case->lastRunDate);
- $caseBranch = zget($case, 'branch', $branch);
- if(empty($caseModules[$caseBranch][$case->fromCaseID][$case->module]))
- {
- $hasImported .= "$case->fromCaseID,";
- }
- else
- {
- $cases[$caseID] = $case;
- $steps[$caseID] = zget($fromSteps, $caseID, array());
- $files[$caseID] = zget($fromFiles, $caseID, array());
- foreach($files[$caseID] as $file) $file->oldpathname = $file->pathname;
- }
- }
- return array($cases, $steps, $files, $hasImported);
- }
- /**
- * 构建导入到用例库的数据。
- * Build data for import to lib.
- *
- * @param int $caseID
- * @param int $libID
- * @access protected
- * @return array
- */
- protected function buildDataForImportToLib($caseID, $libID)
- {
- $cases = array();
- $steps = array();
- $files = array();
- $caseIdList = !empty($caseID) ? $caseID : $this->post->caseIdList;
- $caseIdList = str_replace('case_' , '', (string)$caseIdList);
- $caseIdList = explode(',' , $caseIdList);
- $fromCases = $this->testcase->getByList($caseIdList);
- $fromSteps = $this->testcase->fetchStepsByList($caseIdList);
- $fromFiles = $this->testcase->getRelatedFiles($caseIdList);
- $libCases = $this->dao->select('*')->from(TABLE_CASE)->where('lib')->eq($libID)->andWhere('product')->eq(0)->andWhere('deleted')->eq('0')->fetchGroup('fromCaseID', 'id');
- $maxOrder = $this->dao->select('max(`order`) as maxOrder')->from(TABLE_CASE)->where('deleted')->eq(0)->fetch('maxOrder');
- $maxModuleOrder = $this->dao->select('max(`order`) as maxOrder')->from(TABLE_MODULE)->where('deleted')->eq(0)->fetch('maxOrder');
- foreach($fromCases as $caseID => $case)
- {
- /* 初始化用例。 */
- /* Init case. */
- $libCase = $this->initLibCase($case, $libID, ++ $maxOrder, $maxModuleOrder, $libCases);
- /* 设置用例步骤。 */
- /* Set case steps. */
- $steps[$caseID] = array();
- if(!isset($fromSteps[$caseID])) $fromSteps[$caseID] = array();
- foreach($fromSteps[$caseID] as $step)
- {
- $stepID = $step->id;
- $step->version = zget($libCase, 'version', 1);
- unset($step->id);
- $steps[$caseID][$stepID] = $step;
- }
- /* 设置用例文件。 */
- /* Set case files. */
- $files[$caseID] = array();
- if(!isset($fromFiles[$caseID])) $fromFiles[$caseID] = array();
- foreach($fromFiles[$caseID] as $file)
- {
- $file->oldpathname = $file->pathname;
- $files[$caseID][$file->id] = $file;
- }
- $cases[$caseID] = $libCase;
- }
- return array($cases, $steps, $files);
- }
- /**
- * 为展示导入用例构建更新的用例。
- * Build update case for showing import.
- *
- * @param object $case
- * @param object $oldCase
- * @param array $oldStep
- * @param bool $forceNotReview
- * @access protected
- * @return bool
- */
- protected function buildUpdateCaseForShowImport($case, $oldCase, $oldStep, $forceNotReview)
- {
- $stepChanged = (count($oldStep) != count($case->desc));
- if(!$stepChanged)
- {
- $desc = array_values($case->desc);
- $expect = array_values($case->expect);
- $stepType = array_values($case->stepType);
- foreach($oldStep as $index => $step)
- {
- if(!isset($desc[$index]) || !isset($expect[$index]) || $step->desc != $desc[$index] || $step->expect != $expect[$index] || $step->type != $stepType[$index])
- {
- $stepChanged = true;
- break;
- }
- }
- }
- $case->version = $stepChanged ? (int)$oldCase->version + 1 : (int)$oldCase->version;
- $case->stepChanged = $stepChanged;
- if($stepChanged && !$forceNotReview) $case->status = 'wait';
- return $stepChanged;
- }
- /**
- * 创建测试用例前检验表单数据是否正确。
- * check from data for create case.
- *
- * @param object $case
- * @access protected
- * @return bool
- */
- protected function checkCreateFormData($case)
- {
- $steps = $case->steps;
- $expects = $case->expects;
- foreach($expects as $key => $value)
- {
- if(!empty($value) && empty($steps[$key])) dao::$errors[] = sprintf($this->lang->testcase->stepsEmpty, $key);
- }
- foreach(explode(',', $this->config->testcase->create->requiredFields) as $field)
- {
- $field = trim($field);
- if($field && empty($case->{$field}))
- {
- $fieldName = $this->config->testcase->form->create[$field]['type'] != 'array' ? "{$field}" : "{$field}[]";
- dao::$errors[$fieldName] = sprintf($this->lang->error->notempty, $this->lang->testcase->{$field});
- }
- }
- if(dao::isError()) return false;
- return true;
- }
- /**
- * 批量创建测试用例前检验数据是否正确。
- * Check testcases for batch creating.
- *
- * @param array $testcases
- * @access protected
- * @return array
- */
- protected function checkTestcasesForBatchCreate($testcases)
- {
- $this->loadModel('common');
- $requiredErrors = array();
- foreach($testcases as $i => $testcase)
- {
- /* 检验必填项。 */
- /* Check reuqired. */
- foreach(explode(',', $this->config->testcase->create->requiredFields) as $field)
- {
- $field = trim($field);
- if($field && empty($testcases[$i]->{$field}))
- {
- $fieldName = $this->config->testcase->form->batchCreate[$field]['type'] != 'array' ? "{$field}[{$i}]" : "{$field}[{$i}][]";
- $requiredErrors[$fieldName] = sprintf($this->lang->error->notempty, $this->lang->testcase->{$field});
- }
- }
- }
- if(!empty($requiredErrors)) dao::$errors = $requiredErrors;
- return $testcases;
- }
- /**
- * 批量创建测试用例前检验数据是否正确。
- * Check testcases for batch editing.
- *
- * @param array $cases
- * @access protected
- * @return array
- */
- protected function checkCasesForBatchEdit($cases)
- {
- $this->loadModel('common');
- $requiredErrors = array();
- foreach($cases as $i => $testcase)
- {
- /* 检验必填项。 */
- /* Check reuqired. */
- foreach(explode(',', $this->config->testcase->edit->requiredFields) as $field)
- {
- $field = trim($field);
- if($field && empty($cases[$i]->{$field}))
- {
- $fieldName = $this->config->testcase->form->batchEdit[$field]['type'] != 'array' ? "{$field}[{$i}]" : "{$field}[{$i}][]";
- $requiredErrors[$fieldName] = sprintf($this->lang->error->notempty, $this->lang->testcase->{$field});
- }
- }
- }
- if(!empty($requiredErrors)) dao::$errors = $requiredErrors;
- return $cases;
- }
- /**
- * 导入测试用例前检验数据是否正确。
- * Check testcases for importing.
- *
- * @param array $cases
- * @access protected
- * @return array
- */
- protected function checkCasesForShowImport($cases)
- {
- if($this->config->edition != 'open')
- {
- $extendFields = $this->testcase->getFlowExtendFields();
- $notEmptyRule = $this->loadModel('workflowrule')->getByTypeAndRule('system', 'notempty');
- foreach($extendFields as $extendField)
- {
- if(strpos(",$extendField->rules,", ",$notEmptyRule->id,") !== false)
- {
- $this->config->testcase->create->requiredFields .= ',' . $extendField->field;
- }
- }
- }
- foreach($cases as $i => $case)
- {
- /* 检查期望对应的步骤是否填写。 */
- /* Check the step which has expect. */
- foreach($case->expects as $exportID => $value)
- {
- if(!empty($value) && empty($case->steps[$exportID]))
- {
- $caseErrors["steps[{$i}]"][] = sprintf($this->lang->testcase->stepsEmpty, $exportID);
- }
- }
- /* 检验必填项。 */
- /* Check reuqired. */
- foreach(explode(',', $this->config->testcase->edit->requiredFields) as $field)
- {
- $field = trim($field);
- if($field && empty($case->{$field}))
- {
- $fieldName = $this->config->testcase->form->showImport[$field]['type'] != 'array' ? "{$field}[{$i}]" : "{$field}[{$i}][]";
- $caseErrors[$fieldName][] = sprintf($this->lang->error->notempty, $this->lang->testcase->{$field});
- }
- }
- }
- if(!empty($caseErrors)) dao::$errors = $caseErrors;
- return $cases;
- }
- /**
- * 检查 mind 配置。
- * Build mind config.
- *
- * @access protected
- * @return array|bool
- * @param string $type
- */
- protected function buildMindConfig($type)
- {
- $configList = array();
- $module = $this->post->module;
- if(!empty($module)) $configList[] = array('key' => 'module', 'value' => $module);
- $scene = $this->post->scene;
- if(!empty($scene)) $configList[] = array('key' => 'scene', 'value' => $scene);
- $case = $this->post->case;
- if(!empty($case)) $configList[] = array('key' => 'case', 'value' => $case);
- $precondition = $this->post->precondition;
- if(!empty($precondition)) $configList[] = array('key' => 'precondition', 'value' => $precondition);
- $pri = $this->post->pri;
- if(!empty($pri)) $configList[] = array('key' => 'pri', 'value' => $pri);
- $group = $this->post->group;
- if(!empty($group)) $configList[] = array('key' => 'group', 'value' => $group);
- $configErrors = array();
- foreach($configList as $config)
- {
- $key = $config['key'];
- $value = $config['value'];
- if(!preg_match("/^[a-zA-Z]{1,10}$/", $value)) $configErrors[$key][] = sprintf($this->lang->testcase->errorMindConfig, $this->lang->testcase->{$key});
- }
- if(!empty($configErrors)) dao::$errors = $configErrors;
- $map = array();
- $map[strtolower($module)] = true;
- $map[strtolower($scene)] = true;
- $map[strtolower($case)] = true;
- $map[strtolower($precondition)] = true;
- $map[strtolower($pri)] = true;
- $map[strtolower($group)] = true;
- if(count($map) < 5 && count($map) > 0) dao::$errors['message'][] = '特征字符串不能重复';
- return !dao::isError() ? $configList : false;
- }
- /**
- * 初始化用例数据。
- * Initialize the testcase.
- *
- * @param int $storyID
- * @param int $testcaseID
- * @param int $bugID
- * @access protected
- * @return object
- */
- protected function initTestcase($storyID, $testcaseID, $bugID)
- {
- /* 初始化用例。 */
- /* Initialize the testcase. */
- $case = new stdclass();
- $case->type = 'feature';
- $case->pri = 3;
- $case->scene = 0;
- $case->story = $storyID;
- $case->stage = $case->title = $case->precondition = $case->keywords = $case->color = $case->auto = $case->script = '';
- $case->steps = array();
- /* 如果用例 id 大于 0,使用这个用例数据作为模板。 */
- /* If testcaseID large than 0, use this testcase as template. */
- if($testcaseID > 0)
- {
- $testcase = $this->testcase->getById($testcaseID);
- $case->product = $testcase->product;
- $case->type = $testcase->type ? $testcase->type : 'feature';
- $case->stage = $testcase->stage;
- $case->pri = $testcase->pri;
- $case->scene = $testcase->scene;
- $case->story = $testcase->story;
- $case->title = $testcase->title;
- $case->precondition = $testcase->precondition;
- $case->keywords = $testcase->keywords;
- $case->steps = $testcase->steps;
- $case->color = $testcase->color;
- $case->auto = $testcase->auto;
- $case->script = $testcase->script;
- $case->files = $testcase->files;
- foreach($case->files as $file)
- {
- $file->name = $file->title;
- $file->url = $this->createLink('file', 'download', "fileID={$file->id}");
- }
- if($this->config->edition != 'open')
- {
- $extendFields = $this->loadModel('flow')->getExtendFields('testcase', 'create');
- foreach($extendFields as $field) $case->{$field->field} = $testcase->{$field->field};
- }
- }
- /* 如果 bug id 大于 0,使用这个 bug 数据作为模板。 */
- /* If bugID large than 0, use this bug as template. */
- if($bugID > 0)
- {
- $bug = $this->loadModel('bug')->getById($bugID);
- $case->type = 'feature';
- $case->pri = $bug->pri ? $bug->pri : $bug->severity;
- $case->story = $bug->story;
- $case->title = $bug->title;
- $case->keywords = $bug->keywords;
- $case->steps = $this->testcase->createStepsFromBug($bug->steps);
- }
- /* 追加步骤到默认的步骤数。 */
- /* Append the steps to the default steps count. */
- $case->steps = $this->testcase->appendSteps(!empty($case->steps) ? $case->steps : array());
- return $case;
- }
- /**
- * 初始化要导入到用例库的用例
- * Init case to import to lib.
- *
- * @param object $case
- * @param int $libID
- * @param int $maxOrder
- * @param int $maxModuleOrder
- * @param array $libCases
- * @access protected
- * @return object
- */
- protected function initLibCase($case, $libID, $maxOrder, $maxModuleOrder, $libCases)
- {
- $libCase = new stdclass();
- $libCase->lib = $libID;
- $libCase->title = $case->title;
- $libCase->precondition = $case->precondition;
- $libCase->keywords = $case->keywords;
- $libCase->pri = $case->pri;
- $libCase->type = $case->type;
- $libCase->stage = $case->stage;
- $libCase->status = $case->status;
- $libCase->fromCaseID = $case->id;
- $libCase->fromCaseVersion = $case->version;
- $libCase->color = $case->color;
- $libCase->order = $maxOrder;
- $libCase->module = empty($case->module) ? 0 : $this->testcase->importCaseRelatedModules($libID, $case->module, $maxModuleOrder);
- if(!isset($libCases[$case->id]))
- {
- $libCase->openedBy = $this->app->user->account;
- $libCase->openedDate = helper::now();
- }
- else
- {
- $libCaseList = array_keys($libCases[$case->id]);
- $libCaseID = $libCaseList[0];
- $libCase->id = $libCaseID;
- $libCase->lastEditedBy = $this->app->user->account;
- $libCase->lastEditedDate = helper::now();
- $libCase->version = (int)$libCases[$case->id][$libCaseID]->version + 1;
- }
- return $libCase;
- }
- /**
- * 导入用例。
- * Import cases.
- *
- * @param array $cases
- * @access protected
- * @return array
- */
- protected function importCases($cases)
- {
- $this->loadModel('action');
- $daoErrors = array();
- foreach($cases as $case)
- {
- if(isset($case->id))
- {
- $oldCase = $this->testcase->getByID($case->id);
- if($oldCase->product != $case->product) continue;
- $changes = $this->testcase->update($case, $oldCase);
- $actionID = $this->action->create('case', $case->id, 'Edited');
- $this->action->logHistory($actionID, $changes);
- $this->testcase->updateCase2Project($oldCase, $case);
- }
- else
- {
- $caseID = $this->testcase->create($case);
- $case->id = $caseID;
- dao::isError() ? $daoErrors = array_merge($daoErrors, dao::getError()) : $this->testcase->syncCase2Project($case, $caseID);
- }
- }
- if(!empty($daoErrors)) dao::$errors = $daoErrors;
- return $cases;
- }
- /**
- * 处理xmind数据
- * Process scene data.
- *
- * @param array $result
- * @access protected
- * @return array
- */
- protected function processScene($result)
- {
- $scenes['id'] = $result['id'];
- $scenes['text'] = $result['title'];
- $scenes['type'] = 'root';
- if(!empty($result['children'] && !empty($result['children']['attached']))) $scenes['children'] = $this->processChildScene($result['children']['attached'], $result['id'], 'sub');
- if(!empty($result['children'] && !empty($result['children']['topics']['topic']))) $scenes['children'] = $this->processChildScene($result['children']['topics']['topic'], $result['id'], 'sub');
- return $scenes;
- }
- /**
- * 处理xmind的节点数据
- * process scene child data.
- *
- * @param array $results
- * @param string $parent
- * @param string $type
- * @access protected
- * @return void
- */
- protected function processChildScene($results, $parent, $type)
- {
- $scenes = array();
- foreach($results as $result)
- {
- if(!isset($result['id'])) continue;
- $scene['id'] = $result['id'];
- $scene['text'] = $result['title'];
- $scene['parent'] = $parent;
- $scene['type'] = $type;
- if(!empty($result['children']) && !empty($result['children']['attached']))
- {
- $scene['children'] = $this->processChildScene($result['children']['attached'], $result['id'], 'node');
- }
- elseif(!empty($result['children']) && !empty($result['children']['topics']))
- {
- if(!isset($result['children']['topics']['type']) || empty($result['children']['topics']['topic'])) continue;
- $topic = $result['children']['topics']['topic'];
- if(isset($topic['id']))
- {
- $sceneChild = array();
- $sceneChild['id'] = $topic['id'];
- $sceneChild['text'] = $topic['title'];
- $sceneChild['parent'] = $result['id'];
- $sceneChild['type'] = 'node';
- $grandChild = array();
- if(!empty($topic['children']) && !empty($topic['children']['topics']['topic'])) $grandChild = $topic['children']['topics']['topic'];
- if(isset($topic['nodeType'])) $grandChild = $topic;
- if(isset($grandChild['id'])) $grandChild = array($grandChild);
- $sceneChild['children'] = $this->processChildScene($grandChild, $topic['id'], 'node');
- $scene['children'][] = $sceneChild;
- }
- else
- {
- $scene['children'] = $this->processChildScene($topic, $result['id'], 'node');
- }
- }
- $scenes[] = $scene;
- }
- return $scenes;
- }
- /**
- * 为展示脑图计算步骤数据。
- * Process steps for mindmap.
- *
- * @param object $case
- * @access protected
- * @return object
- */
- protected function processStepsForMindMap($case)
- {
- $mindMapSteps = array();
- $mindMapSteps['id'] = 'case_' . $case->id;
- $mindMapSteps['text'] = $case->title;
- $mindMapSteps['type'] = 'root';
- $stepItem['subSide'] = 'right';
- $reverseSteps = array_reverse($case->steps);
- $stepList = array();
- $parentSteps = array();
- foreach($reverseSteps as $step)
- {
- if(empty($step->id)) continue;
- if($step->type != 'group')
- {
- $descItem = array();
- $descItem['id'] = 'desc_' . $step->id;
- $descItem['text'] = $step->expect;
- $descItem['type'] = 'node';
- $descItem['parent'] = $step->id;
- $descItem['subSide'] = 'right';
- $parentSteps[$step->id][] = $descItem;
- }
- $stepItem = array();
- $stepItem['id'] = $step->id;
- $stepItem['text'] = $step->step;
- $stepItem['type'] = $step->grade == 1 ? 'sub' : 'node';
- $stepItem['parent'] = $step->parent > 0 ? $step->parent : 'case_' . $case->id;
- $stepItem['subSide'] = 'right';
- if(isset($parentSteps[$step->id])) $stepItem['children'] = array_reverse($parentSteps[$step->id]);
- if($step->parent > 0)
- {
- $parentSteps[$step->parent][] = $stepItem;
- }
- else
- {
- $stepList[] = $stepItem;
- }
- }
- $mindMapSteps['children'] = array_reverse($stepList);
- $case->mindMapSteps = $mindMapSteps;
- return $case;
- }
- /**
- * 计算导入列的键值。
- * Process import column key.
- *
- * @param string $fileName
- * @param array $fields
- * @access protected
- * @return void
- */
- protected function processImportColumnKey($fileName, $fields)
- {
- /* 获取文件内的行,设置头。 */
- /* Get rows and set header. */
- $rows = $this->loadModel('file')->parseCSV($fileName);
- $header = array();
- foreach($rows[0] as $i => $rowValue)
- {
- if(empty($rowValue)) break;
- $header[$i] = $rowValue;
- }
- unset($rows[0]);
- /* 设置列的键值。 */
- /* Set column key. */
- $columnKey = array();
- foreach($header as $title)
- {
- if(isset($fields[$title])) $columnKey[] = $fields[$title];
- }
- return $columnKey;
- }
- /**
- * 获取分组用例。
- * Get group cases.
- *
- * @param int $productID
- * @param string $branch
- * @param string $groupBy
- * @param string $caseType
- * @param string $browseType
- * @access protected
- * @return array
- */
- protected function getGroupCases($productID, $branch, $groupBy, $caseType, $browseType = '')
- {
- /* 获取用例。 */
- /* Get cases. */
- $cases = $this->testcase->getModuleCases($productID, $branch, 0, $browseType, 'no', $caseType, $groupBy);
- $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
- $cases = $this->loadModel('story')->checkNeedConfirm($cases);
- $cases = $this->testcase->appendData($cases);
- foreach($cases as $case) $case->caseID = $case->id;
- /* 获取用例的需求分组。 */
- /* Get story groups of cases. */
- $groupCases = array();
- if($groupBy == 'story')
- {
- foreach($cases as $case) $groupCases[$case->story][] = $case;
- }
- /* 设置用例的需求分组的行占比。 */
- /* Set row span of story group in cases. */
- $story = null;
- foreach($cases as $index => $case)
- {
- if($case->storyDeleted)
- {
- unset($cases[$index]);
- continue;
- }
- $case->rowspan = 0;
- if($story !== $case->story)
- {
- $story = $case->story;
- if(!empty($groupCases[$case->story])) $case->rowspan = count($groupCases[$case->story]);
- }
- }
- return $cases;
- }
- /**
- * 创建完 testcase 后的相关处理。
- * Relevant processing after create testcase.
- *
- * @param object $case
- * @param int $caseID
- * @access protected
- * @return void
- */
- protected function afterCreate($case, $caseID)
- {
- /* 设置 cookie。 */
- /* Set cookie. */
- helper::setcookie('lastCaseModule', (string)$case->module);
- helper::setcookie('lastCaseProduct', (string)$case->product);
- helper::setcookie('lastCaseScene', (string)$case->scene);
- helper::setcookie('caseModule', '0');
- if(!empty($_POST['fileList']))
- {
- $fileList = $this->post->fileList;
- if($fileList) $fileList = json_decode($fileList, true);
- $this->loadModel('file')->saveDefaultFiles($fileList, 'testcase', $caseID);
- }
- /* 如果需求关联到项目,把用例也关联到项目。 */
- /* If the story is linked project, make the case link the project. */
- $this->testcase->syncCase2Project($case, $caseID);
- }
- /**
- * 返回创建 testcase 的结果。
- * Respond after creating testcase.
- *
- * @param int $caseID
- * @access protected
- * @return array|int
- * @param int $moduleID
- */
- protected function responseAfterCreate($caseID, $moduleID = 0)
- {
- $message = $this->executeHooks($caseID);
- if(!$message) $message = $this->lang->saveSuccess;
- if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $message, 'id' => $caseID));
- /* If link from no head then reload. */
- if(isInModal() || helper::isAjaxRequest('modal')) return $this->send(array('result' => 'success', 'message' => $message, 'load' => true, 'closeModal' => true));
- /* 判断是否当前一级菜单不是 QA,并且 caseList session 存在,并且 caseList 不是动态页面。 */
- /* Use this session link, when the tab is not QA, a session of the case list exists, and the session is not from the Dynamic page. */
- $useSession = ($this->app->tab != 'qa' and $this->session->caseList and strpos($this->session->caseList, 'dynamic') === false);
- if($this->app->tab == 'project')
- {
- $locateLink = $this->createLink('project', 'testcase', "projectID={$this->session->project}");
- }
- else
- {
- $params = "productID={$this->post->product}&branch={$this->post->branch}";
- if($moduleID) $params .= "&browseType=byModule¶m=$moduleID";
- $locateLink = $this->createLink('testcase', 'browse', $params);
- }
- return $this->send(array('result' => 'success', 'message' => $message, 'load' => $useSession ? $this->session->caseList : $locateLink));
- }
- /**
- * 返回批量创建 testcase 的结果。
- * Respond after batch creating testcase.
- *
- * @param int $productID
- * @param string|int $branch
- * @access protected
- * @return void
- */
- protected function responseAfterBatchCreate($productID, $branch)
- {
- if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
- if(helper::isAjaxRequest('modal')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'load' => true));
- if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $caseIdList));
- helper::setcookie('caseModule', '0');
- $currentModule = $this->app->tab == 'qa' ? 'testcase' : $this->app->tab;
- $currentMethod = $this->app->tab == 'qa' ? 'browse' : 'testcase';
- $projectParam = $this->app->tab == 'qa' ? '' : "{$this->app->tab}ID=" . zget($_SESSION, $this->app->tab, 0) . '&';
- return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $this->createLink($currentModule, $currentMethod, "{$projectParam}productID={$productID}&branch={$branch}")));
- }
- /**
- * 返回展示导入 testcase 的结果。
- * Respond after showing imported testcase.
- *
- * @param int $productID
- * @param string $branch
- * @param int $maxImport
- * @param string $tmpFile
- * @param string $message
- * @access protected
- * @return void
- */
- protected function responseAfterShowImport($productID, $branch = '0', $maxImport = 0, $tmpFile = '', $message = '')
- {
- if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
- if($this->post->isEndPage)
- {
- if(!empty($_SESSION['fileImport']) && file_exists($_SESSION['fileImport'])) unlink($tmpFile);
- if(!empty($_SESSION['fileImport'])) unset($_SESSION['fileImport']);
- $locateLink = $this->app->tab == 'project' ? $this->createLink('project', 'testcase', "projectID={$this->session->project}&productID={$productID}") : inlink('browse', "productID={$productID}");
- }
- else
- {
- $locateLink = inlink('showImport', "productID={$productID}&branch={$branch}&pagerID=" . ((int)$this->post->pagerID + 1) . "&maxImport={$maxImport}&insert=" . zget($_POST, 'insert', ''));
- }
- return $this->send(array('result' => 'success', 'message' => $message ? $message : $this->lang->saveSuccess, 'load' => $locateLink));
- }
- /**
- * 处理评审数据。
- * Prepare review data.
- *
- * @param int $caseID
- * @param object $oldCase
- * @access protected
- * @return bool|object
- */
- protected function prepareReviewData($caseID, $oldCase)
- {
- $now = helper::now();
- $status = $this->getStatusForReview($oldCase);
- $case = form::data($this->config->testcase->form->review, $caseID)->add('id', $caseID)
- ->setForce('status', $status)
- ->setDefault('reviewedDate', substr($now, 0, 10))
- ->setDefault('lastEditedBy', $this->app->user->account)
- ->setDefault('lastEditedDate', $now)
- ->join('reviewedBy', ',')
- ->stripTags($this->config->testcase->editor->review['id'], $this->config->allowedTags)
- ->get();
- if(!$case->result)
- {
- dao::$errors['result'] = $this->lang->testcase->mustChooseResult;
- return false;
- }
- return $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->review['id'], $this->post->uid);
- }
- /**
- * 构建关联用例页面的搜索表单。
- * Build search form for link cases.
- *
- * @param object $case
- * @param int $queryID
- * @access protected
- * @return void
- */
- protected function buildLinkCasesSearchForm($case, $queryID)
- {
- $actionURL = $this->createLink('testcase', 'linkCases', "caseID={$case->id}&browseType=bySearch&queryID=myQueryID", '', true);
- $objectID = 0;
- if($this->app->tab == 'project') $objectID = $case->project;
- if($this->app->tab == 'execution') $objectID = $case->execution;
- unset($this->config->testcase->search['fields']['product']);
- $this->testcase->buildSearchForm($case->product, $this->products, $queryID, $actionURL, $objectID);
- }
- /**
- * 构建关联 bug 页面的搜索表单。
- * Build search form for link bugs.
- *
- * @param object $case
- * @param int $queryID
- * @access protected
- * @return void
- */
- protected function buildLinkBugsSearchForm($case, $queryID)
- {
- $actionURL = $this->createLink('testcase', 'linkBugs', "caseID={$case->id}&browseType=bySearch&queryID=myQueryID", '', true);
- $objectID = 0;
- if($this->app->tab == 'project') $objectID = $case->project;
- if($this->app->tab == 'execution') $objectID = $case->execution;
- /* 删除单一项目的计划字段。*/
- /* Unset search field 'plan' in single project. */
- unset($this->config->bug->search['fields']['product']);
- if($case->project && ($this->app->tab == 'project' || $this->app->tab == 'execution'))
- {
- $project = $this->loadModel('project')->getByID($case->project);
- if(!$project->hasProduct && $project->model == 'waterfall') unset($this->config->bug->search['fields']['plan']);
- }
- $this->loadModel('bug')->buildSearchForm($case->product, $this->products, $queryID, $actionURL, (string)$objectID);
- }
- /**
- * 获取导出的字段列表。
- * Get the export fields.
- *
- * @param string $productType
- * @access protected
- * @return array
- */
- protected function getExportFields($productType)
- {
- $fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $this->config->testcase->exportFields);
- foreach($fields as $key => $fieldName)
- {
- $fieldName = trim($fieldName);
- if($productType != 'normal' || $fieldName != 'branch') $fields[$fieldName] = zget($this->lang->testcase, $fieldName);
- unset($fields[$key]);
- }
- return $fields;
- }
- /**
- * 获取 mind 导出的数据。
- * Get export data.
- *
- * @param int $productID
- * @param int $moduleID
- * @param string $branch
- * @access protected
- * @return array
- * @param string $type
- */
- protected function getMindExport($type, $productID, $moduleID, $branch)
- {
- $caseList = $this->testcase->getCaseListForXmindExport($productID, $moduleID, $branch);
- $stepList = $this->testcase->getStepByProductAndModule($productID, $moduleID);
- $moduleList = $this->getModuleListForXmindExport($productID, $moduleID, $branch);
- $sceneInfo = $this->testcase->getSceneByProductAndModule($productID, $moduleID);
- $config = $this->testcase->getMindConfig($type);
- return array('caseList' => $caseList, 'stepList' => $stepList, 'sceneMaps' => $sceneInfo['sceneMaps'], 'topScenes' => $sceneInfo['topScenes'], 'moduleList' => $moduleList, 'config' => $config);
- }
- /**
- * 导出xmind格式用例时获取模块列表。
- * Get module list for xmind export.
- *
- * @param int $productID
- * @param int $moduleID
- * @param string $branch
- * @access public
- * @return array
- */
- private function getModuleListForXmindExport($productID, $moduleID, $branch)
- {
- if($moduleID)
- {
- $module = $this->loadModel('tree')->getByID($moduleID);
- if(!$module) return array();
- return array($module->id => $module->name);
- }
- $moduleList = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, ($branch === 'all' || !isset($branches[$branch])) ? 'all' : $branch);
- unset($moduleList['0']);
- return $moduleList;
- }
- /**
- * 获取导入的数据。
- * Get imported data.
- *
- * @param int $productID
- * @param string $file
- * @access protected
- * @return void
- */
- protected function getImportedData($productID, $file)
- {
- $rows = $this->loadModel('file')->parseCSV($file);
- $header = array();
- foreach($rows[0] as $i => $rowValue)
- {
- if(empty($rowValue)) break;
- $header[$i] = $rowValue;
- }
- unset($rows[0]);
- $fields = $this->testcase->getImportFields($productID);
- $fields = array_flip($fields);
- $caseData = array();
- $stepVars = 0;
- foreach($rows as $row => $data)
- {
- $case = new stdclass();
- foreach($header as $key => $title)
- {
- if(!isset($fields[$title]) || !isset($data[$key])) continue;
- $field = $fields[$title];
- $cellValue = $data[$key];
- $case = $this->getImportField($field, $cellValue, $case);
- }
- if(empty($case->title)) continue;
- $caseData[$row] = $case;
- unset($case);
- }
- return array(array('caseData' => $caseData), $stepVars);
- }
- /**
- * 获取导入的用例字段。
- * Get imported field.
- *
- * @param string $field
- * @param string $cellValue
- * @param object $case
- * @access protected
- * @return object
- */
- protected function getImportField($field, $cellValue, $case)
- {
- if($field == 'story' || $field == 'module' || $field == 'branch')
- {
- $case->{$field} = 0;
- if(strrpos($cellValue, '(#') !== false)
- {
- $id = trim(substr($cellValue, strrpos($cellValue,'(#') + 2), ')');
- $case->{$field} = $id;
- }
- }
- elseif($field == 'stepDesc')
- {
- $case->steps = $cellValue;
- }
- elseif($field == 'stepExpect')
- {
- $case->expects = $cellValue;
- }
- elseif(in_array($field, $this->config->testcase->export->listFields))
- {
- if($field == 'stage')
- {
- $stages = explode("\n", $cellValue);
- foreach($stages as $stage) $case->stage[] = array_search($stage, $this->lang->testcase->{$field . 'List'});
- $case->stage = join(',', $case->stage);
- }
- else
- {
- $case->{$field} = array_search($cellValue, $this->lang->testcase->{$field . 'List'});
- }
- }
- else
- {
- $case->{$field} = $cellValue;
- }
- return $case;
- }
- /**
- * 获取导入的用例步骤。
- * Get imported steps.
- *
- * @param string $field
- * @param array $steps
- * @param array $stepData
- * @param int $row
- * @access protected
- * @return array
- */
- protected function getImportSteps($field, $steps, $stepData, $row)
- {
- $caseSteps = array();
- foreach($steps as $step)
- {
- $step = trim($step);
- if(empty($step)) continue;
- preg_match('/^((([0-9]+)[.]([0-9]+))[.]([0-9]+))[.、](.*)$/Uu', $step, $out);
- if(!$out) preg_match('/^(([0-9]+)[.]([0-9]+))[.、](.*)$/Uu', $step, $out);
- if(!$out) preg_match('/^([0-9]+)[.、](.*)$/Uu', $step, $out);
- if($out)
- {
- $count = count($out);
- $num = $out[1];
- $parent = $count > 4 ? $out[2] : '0';
- $grand = $count > 6 ? $out[3] : '0';
- $step = trim($out[2]);
- if($count > 4) $step = $count > 6 ? trim($out[6]) : trim($out[4]);
- $caseSteps[$num]['content'] = $step;
- $caseSteps[$num]['number'] = $num;
- $caseSteps[$num]['type'] = $count > 4 ? 'item' : 'step';
- if(!empty($parent)) $caseSteps[$parent]['type'] = 'group';
- if(!empty($grand)) $caseSteps[$grand]['type'] = 'group';
- }
- elseif(isset($num))
- {
- $caseSteps[$num]['content'] = isset($caseSteps[$num]['content']) ? "{$caseSteps[$num]['content']}\n{$step}" : "\n{$step}";
- }
- elseif($field == 'stepDesc')
- {
- $num = 1;
- $caseSteps[$num]['content'] = $step;
- $caseSteps[$num]['type'] = 'step';
- $caseSteps[$num]['number'] = $num;
- }
- elseif($field == 'stepExpect' && isset($stepData[$row]['desc']))
- {
- end($stepData[$row]['desc']);
- $num = key($stepData[$row]['desc']);
- $caseSteps[$num]['content'] = $step;
- $caseSteps[$num]['number'] = $num;
- }
- }
- return $caseSteps;
- }
- /**
- * 处理导出的用例数据。
- * Process export cases.
- *
- * @param array $cases
- * @param int $productID
- * @param int $taskID
- * @access protected
- * @return array
- */
- protected function processCasesForExport($cases, $productID, $taskID)
- {
- $products = $this->product->getPairs('', 0, '', 'all');
- $branches = $this->loadModel('branch')->getPairs($productID);
- $users = $this->loadModel('user')->getPairs('noletter');
- $results = $this->testcase->getCaseResultsForExport(array_keys($cases), $taskID);
- $relatedModules = $this->loadModel('tree')->getAllModulePairs('case');
- $relatedStories = $this->testcase->getRelatedStories($cases);
- $relatedCases = $this->testcase->getRelatedCases($cases);
- $relatedSteps = $this->testcase->getRelatedSteps(array_keys($cases));
- $relatedFiles = $this->testcase->getRelatedFiles(array_keys($cases));
- $relatedScenes = $this->testcase->getSceneMenu($productID, 0);
- if($taskID) $this->app->loadLang('testtask');
- $cases = $this->testcase->appendData($cases);
- foreach($cases as $case) $this->processCaseForExport($case, $products, $branches, $users, $results, $relatedModules, $relatedStories, $relatedCases, $relatedSteps, $relatedFiles, $relatedScenes);
- return $cases;
- }
- /**
- * 处理导出的某个用例。
- * Process export case.
- *
- * @param object $case
- * @param array $products
- * @param array $branches
- * @param array $users
- * @param array $results
- * @param array $relatedModules
- * @param array $relatedStories
- * @param array $relatedCases
- * @param array $relatedSteps
- * @param array $relatedFiles
- * @param array $relatedScenes
- * @access protected
- * @return void
- */
- protected function processCaseForExport($case, $products, $branches, $users, $results, $relatedModules, $relatedStories, $relatedCases, $relatedSteps, $relatedFiles, $relatedScenes)
- {
- $case->stepDesc = '';
- $case->stepExpect = '';
- $case->real = '';
- $case->openedDate = !helper::isZeroDate($case->openedDate) ? substr($case->openedDate, 0, 10) : '';
- $case->lastEditedDate = !helper::isZeroDate($case->lastEditedDate) ? substr($case->lastEditedDate, 0, 10) : '';
- $case->lastRunDate = !helper::isZeroDate($case->lastRunDate) ? $case->lastRunDate : '';
- $case->product = isset($products[$case->product]) ? $products[$case->product] . "(#$case->product)" : '';
- $case->branch = isset($branches[$case->branch]) ? $branches[$case->branch] . "(#$case->branch)" : '';
- $case->module = isset($relatedModules[$case->module])? $relatedModules[$case->module] . "(#$case->module)" : '';
- $case->story = isset($relatedStories[$case->story]) ? $relatedStories[$case->story] . "(#$case->story)" : '';
- $case->scene = isset($relatedScenes[$case->scene]) ? $relatedScenes[$case->scene] . "(#$case->scene)" : '';
- $case->pri = zget($this->lang->testcase->priList, $case->pri);
- $case->type = zget($this->lang->testcase->typeList, $case->type);
- $case->status = $this->processStatus('testcase', $case);
- $case->openedBy = zget($users, $case->openedBy);
- $case->lastEditedBy = zget($users, $case->lastEditedBy);
- $case->lastRunner = zget($users, $case->lastRunner);
- $case->lastRunResult = zget($this->lang->testcase->resultList, $case->lastRunResult);
- $case->bugsAB = $case->bugs;
- $case->resultsAB = $case->results;
- $case->stepNumberAB = $case->stepNumber;
- unset($case->bugs);
- unset($case->results);
- unset($case->stepNumber);
- unset($case->caseFails);
- $this->processStepForExport($case, zget($results, $case->id, array()), $relatedSteps);
- $this->processStageForExport($case);
- $this->processFileForExport($case, $relatedFiles);
- if($case->linkCase) $this->processLinkCaseForExport($case);
- }
- /**
- * 处理导出的用例的步骤。
- * Process step of case for export.
- *
- * @param object $case
- * @param array $result
- * @param array $relatedSteps
- * @access protected
- * @return void
- */
- protected function processStepForExport($case, $result, $relatedSteps)
- {
- $case->real = '';
- if(!empty($result) && !isset($relatedSteps[$case->id]))
- {
- $firstStep = reset($result);
- $case->real = $firstStep['real'];
- }
- if(!isset($case->stepDesc)) $case->stepDesc = '';
- if(!isset($case->stepExpect)) $case->stepExpect = '';
- if(!empty($case->id) && !empty($relatedSteps[$case->id]))
- {
- $preGrade = 1;
- $parentSteps = array();
- $key = array(0, 0, 0);
- foreach($relatedSteps[$case->id] as $step)
- {
- $grade = 1;
- $parentSteps[$step->id] = $step->parent;
- if(isset($parentSteps[$step->parent])) $grade = isset($parentSteps[$parentSteps[$step->parent]]) ? 3 : 2;
- if($grade > $preGrade)
- {
- $key[$grade - 1] = 1;
- }
- else
- {
- if($grade < $preGrade)
- {
- if($grade < 2) $key[1] = 0;
- if($grade < 3) $key[2] = 0;
- }
- $key[$grade - 1] ++;
- }
- $stepID = implode('.', $key);
- $stepID = str_replace('.0', '', $stepID);
- $stepID = str_replace('.0', '', $stepID);
- $sign = (in_array($this->post->fileType, array('html', 'xml'))) ? '<br />' : "\n";
- $case->stepDesc .= $stepID . ". " . htmlspecialchars_decode($step->desc) . $sign;
- $case->stepExpect .= $stepID . ". " . htmlspecialchars_decode($step->expect) . $sign;
- $case->real .= $stepID . ". " . (isset($result[$step->id]) ? $result[$step->id]['real'] : '') . $sign;
- $preGrade = $grade;
- }
- }
- $case->stepDesc = !empty($case->stepDesc) ? trim($case->stepDesc) : '';
- $case->stepExpect = !empty($case->stepExpect) ? trim($case->stepExpect) : '';
- $case->real = !empty($case->real) ? trim($case->real) : '';
- if($this->post->fileType == 'csv')
- {
- $case->stepDesc = str_replace('"', '""', $case->stepDesc);
- $case->stepExpect = str_replace('"', '""', $case->stepExpect);
- }
- }
- /**
- * 处理导出的用例的适用阶段。
- * Process stage of case for export.
- *
- * @param object $case
- * @access protected
- * @return void
- */
- protected function processStageForExport($case)
- {
- $case->stage = explode(',', $case->stage);
- foreach($case->stage as $key => $stage) $case->stage[$key] = isset($this->lang->testcase->stageList[$stage]) ? $this->lang->testcase->stageList[$stage] : $stage;
- $case->stage = join("\n", $case->stage);
- }
- /**
- * 处理导出用例的相关用例。
- * Process link case of the case for export.
- *
- * @param object $case
- * @access protected
- * @return void
- */
- protected function processLinkCaseForExport($case)
- {
- $tmpLinkCases = array();
- $linkCaseIdList = explode(',', $case->linkCase);
- foreach($linkCaseIdList as $linkCaseID)
- {
- $linkCaseID = trim($linkCaseID);
- $tmpLinkCases[] = isset($relatedCases[$linkCaseID]) ? $relatedCases[$linkCaseID] . "(#$linkCaseID)" : $linkCaseID;
- }
- $case->linkCase = join("; \n", $tmpLinkCases);
- }
- /**
- * 处理导出用例的附件。
- * Process file of case for export.
- *
- * @param object $case
- * @param array $relatedFiles
- * @access protected
- * @return void
- */
- protected function processFileForExport($case, $relatedFiles)
- {
- $case->files = '';
- if(isset($relatedFiles[$case->id]))
- {
- foreach($relatedFiles[$case->id] as $file)
- {
- $fileURL = common::getSysURL() . $this->createLink('file', 'download', "fileID={$file->id}");
- $case->files .= html::a($fileURL, $file->title, '_blank') . '<br />';
- }
- }
- }
- /**
- * 处理批量编辑用例的步骤和预期。
- * Process steps and expects for batch edit.
- *
- * @param array $cases
- * @access protected
- * @return array
- */
- protected function processStepsAndExpectsForBatchEdit($cases)
- {
- $relatedSteps = $this->testcase->getRelatedSteps(array_column($cases, 'id'));
- foreach($cases as $case)
- {
- $this->processStepForExport($case, array(), $relatedSteps);
- $case->steps = $case->stepDesc;
- $case->expects = $case->stepExpect;
- }
- return $cases;
- }
- /**
- * 获取导出模板的字段。
- * Get fields for export template.
- *
- * @param string $productType
- * @access protected
- * @return array
- */
- protected function getFieldsForExportTemplate($productType)
- {
- $fields = array();
- $fields['branch'] = $this->lang->product->branchName[$productType];
- $fields['module'] = $this->lang->testcase->module;
- $fields['title'] = $this->lang->testcase->title;
- $fields['precondition'] = $this->lang->testcase->precondition;
- $fields['stepDesc'] = $this->lang->testcase->stepDesc;
- $fields['stepExpect'] = $this->lang->testcase->stepExpect;
- $fields['keywords'] = $this->lang->testcase->keywords;
- $fields['pri'] = $this->lang->testcase->pri;
- $fields['type'] = $this->lang->testcase->type;
- $fields['stage'] = $this->lang->testcase->stage;
- $fields[''] = '';
- $fields['typeValue'] = $this->lang->testcase->lblTypeValue;
- $fields['stageValue'] = $this->lang->testcase->lblStageValue;
- $fields['branchValue'] = $this->lang->product->branchName[$productType];
- if($productType == 'normal')
- {
- unset($fields['branch']);
- unset($fields['branchValue']);
- }
- return $fields;
- }
- /**
- * 获取导出模板的行。
- * Get rows for export template.
- *
- * @param object $product
- * @param int $num
- * @access protected
- * @return array
- */
- protected function getRowsForExportTemplate($product, $num)
- {
- $this->loadModel('tree');
- $projectID = $this->app->tab == 'project' ? $this->session->project : 0;
- $branches = $this->loadModel('branch')->getPairs($product->id, '' , $projectID);
- $modules = $product->type == 'normal' ? $this->tree->getOptionMenu($product->id, 'case', 0, 'all') : array();
- foreach($branches as $branchID => $branchName)
- {
- $branches[$branchID] = $branchName . "(#$branchID)";
- $modules += $this->tree->getOptionMenu($product->id, 'case', 0, (string)$branchID);
- }
- $rows = array();
- for($i = 0; $i < $num; $i++)
- {
- foreach($modules as $moduleID => $module)
- {
- $row = new stdclass();
- $row->module = $module . "(#$moduleID)";
- $row->stepDesc = "1. \n2. \n3.";
- $row->stepExpect = "1. \n2. \n3.";
- if(empty($rows))
- {
- unset($this->lang->testcase->typeList['unit']);
- $row->typeValue = join("\n", $this->lang->testcase->typeList);
- $row->stageValue = join("\n", $this->lang->testcase->stageList);
- if($product->type != 'normal') $row->branchValue = join("\n", $branches);
- }
- $rows[] = $row;
- }
- }
- return $rows;
- }
- /**
- * 获取创建用例时的状态值。
- * Get status for create.
- *
- * @access public
- * @return string
- */
- public function getStatusForCreate()
- {
- if($this->testcase->forceNotReview() || !$this->post->needReview) return 'normal';
- return 'wait';
- }
- /**
- * 获取评审用例时的状态值。
- * Get status for review.
- *
- * @param object $case
- * @access private
- * @return string
- */
- private function getStatusForReview($case)
- {
- if($this->post->result == 'pass') return 'normal';
- return zget($case, 'status', '');
- }
- /**
- * 获取更新的状态。
- * Get status for update.
- *
- * @param object $case
- * @access public
- * @return bool|array
- */
- public function getStatusForUpdate($case)
- {
- if($this->post->lastEditedDate && $case->lastEditedDate != $this->post->lastEditedDate)
- {
- dao::$errors['message'][] = $this->lang->error->editedByOther;
- return false;
- }
- /* 判断步骤是否变更。*/
- /* Judge steps changed or not. */
- $stepChanged = false;
- if($this->post->steps)
- {
- $steps = array();
- foreach($this->post->steps as $key => $desc)
- {
- if(!$desc) continue;
- $steps[] = array('desc' => trim($desc), 'type' => trim(zget($this->post->stepType, $key, 'step')), 'expect' => trim(zget($this->post->expects, $key, '')));
- }
- /* 如果步骤数量发生变化,步骤变更。*/
- /* If step count changed, case changed. */
- if(count($case->steps) != count($steps))
- {
- $stepChanged = true;
- }
- else
- {
- /* 对比步骤的每一步。*/
- /* Compare every step. */
- $i = 0;
- foreach($case->steps as $key => $oldStep)
- {
- if(trim($oldStep->desc) != trim($steps[$i]['desc']) || trim($oldStep->expect) != $steps[$i]['expect'] || trim($oldStep->type) != $steps[$i]['type'])
- {
- $stepChanged = true;
- break;
- }
- $i++;
- }
- }
- }
- $status = $this->post->status ? $this->post->status : $case->status;
- if(!$this->testcase->forceNotReview() && $stepChanged) $status = 'wait';
- if($this->post->title && $case->title != $this->post->title) $stepChanged = true;
- if(isset($_POST['precondition']) && $case->precondition != $this->post->precondition) $stepChanged = true;
- if(!empty($_FILES['files']['name'][0])) $stepChanged = true;
- if(!empty($_POST['deleteFiles'])) $stepChanged = true;
- return array($stepChanged, $status);
- }
- /**
- * 创建 freemind 的 xml 文档。
- * Create freemind's xml doc.
- *
- * @param int $productID
- * @param string $productName
- * @param array $context
- * @access protected
- * @return object
- */
- protected function createFreeMindXmlDoc($productID, $productName, $context)
- {
- $this->classFreeMind = $this->app->loadClass('freemind');
- $xmlDoc = new DOMDocument('1.0', 'UTF-8');
- $xmlDoc->formatOutput = true;
- $versionAttr = $xmlDoc->createAttribute('version');
- $versionAttr->value = '1.0.1';
- $textAttr = $xmlDoc->createAttribute('TEXT');
- $textAttr->value = $this->classFreeMind->toText("$productName", $productID);
- $mapNode = $xmlDoc->createElement('map');
- $mapNode->appendChild($versionAttr);
- $productNode = $xmlDoc->createElement('node');
- $productNode->appendChild($textAttr);
- $mapNode->appendChild($productNode);
- $xmlDoc->appendChild($mapNode);
- $sceneNodes = array();
- $moduleNodes = array();
- $this->classFreeMind->createModuleNode($xmlDoc, $context, $productNode, $moduleNodes);
- $this->classFreeMind->createSceneNode($xmlDoc, $context, $productNode, $moduleNodes, $sceneNodes);
- $this->classFreeMind->createTestcaseNode($xmlDoc, $context, $productNode, $moduleNodes, $sceneNodes);
- return $xmlDoc;
- }
- /**
- * 获取 xmind 导出的数据。
- * Get export data of xmind.
- *
- * @param int $productID
- * @param string $productName
- * @param array $context
- * @access protected
- * @return string
- */
- protected function getXmindExportData($productID, $productName, $context)
- {
- $this->classXmind = $this->app->loadClass('xmind');
- $xmlDoc = new DOMDocument('1.0', 'UTF-8');
- $xmlDoc->formatOutput = true;
- $titleAttr = $xmlDoc->createElement('title', $this->classXmind->toText("$productName", $productID));
- $idAttr = $xmlDoc->createElement('id', $this->classXmind->toText(uniqid(), ''));
- $productChildren = $xmlDoc->createElement('children');
- $productTopics = $this->classXmind->createTopics($xmlDoc);
- $productChildren->appendChild($productTopics);
- $class = $xmlDoc->createAttribute('structure-class');
- $classValue = $xmlDoc->createTextNode('org.xmind.ui.map.clockwise');
- $class->appendChild($classValue);
- $productTopic = $xmlDoc->createElement('topic');
- $productTopic->appendChild($titleAttr);
- $productTopic->appendChild($idAttr);
- $productTopic->appendChild($class);
- $productTopic->appendChild($productChildren);
- $titleAttr = $xmlDoc->createElement('title', 'sheet');
- $sheet = $xmlDoc->createElement('sheet');
- $theme = $xmlDoc->createAttribute('theme');
- $themeValue = $xmlDoc->createTextNode('65q18ujpt3vgdbk1ifknidq03m');
- $theme->appendChild($themeValue);
- $sheet->appendChild($titleAttr);
- $sheet->appendChild($theme);
- $sheet->appendChild($productTopic);
- $xmapContent = $this->classXmind->initXmapContent($xmlDoc);
- $xmapContent->appendChild($sheet);
- $xmlDoc->appendChild($xmapContent);
- $sceneTopics = array();
- $moduleTopics = array();
- $this->classXmind->createModuleTopic($xmlDoc, $context, $productTopics, $moduleTopics);
- $this->classXmind->createSceneTopic($xmlDoc, $context, $productTopics, $moduleTopics, $sceneTopics);
- $this->classXmind->createTestcaseTopic($xmlDoc, $context, $productTopics, $moduleTopics, $sceneTopics);
- $this->app->loadClass('pclzip', true);
- $zfile = $this->app->loadClass('zfile');
- /* Init xmind file. */
- $exportPath = $this->app->getCacheRoot() . $this->app->user->account . uniqid() . '/';
- if(is_dir($exportPath)) $zfile->removeDir($exportPath);
- $zfile->mkdir($exportPath);
- file_put_contents($exportPath . 'content.xml', $xmlDoc->saveXML());
- /* create style.xml. */
- $styleXmlContent = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><xmap-styles xmlns="urn:xmind:xmap:xmlns:style:2.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" version="2.0"><master-styles><style id="65q18ujpt3vgdbk1ifknidq03m" type="theme"/></master-styles></xmap-styles><?xml version="1.0" encoding="UTF-8" standalone="no"?><xmap-styles xmlns="urn:xmind:xmap:xmlns:style:2.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" version="2.0"><master-styles><style id="65q18ujpt3vgdbk1ifknidq03m" type="theme"/></master-styles></xmap-styles>';
- file_put_contents($exportPath . 'style.xml', $styleXmlContent);
- /* create mate.xml. */
- $metaXmlContent = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><meta xmlns="urn:xmind:xmap:xmlns:meta:2.0" version="2.0"></meta>';
- file_put_contents($exportPath . 'meta.xml', $metaXmlContent);
- /* create META_INF/manifest.xml. */
- $zfile->mkdir($exportPath . 'META-INF');
- $manifestXmlContent = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><manifest xmlns="urn:xmind:xmap:xmlns:manifest:2.0" version="2.0"></manifest>';
- file_put_contents($exportPath . 'META-INF' . DS . 'manifest.xml', $manifestXmlContent);
- /* Zip to xmind. */
- $fileName = uniqid() . '.xmind';
- helper::cd($exportPath);
- $files = array('style.xml', 'meta.xml', 'content.xml', 'META-INF/manifest.xml');
- $zip = new pclzip($fileName);
- $zip->create($files);
- $fileData = file_get_contents($exportPath . $fileName);
- $zfile->removeDir($exportPath);
- return $fileData;
- }
- /**
- * 解析上传的 xmind 文件。
- * Parse the upload xmind file.
- *
- * @param int $productID
- * @param int|string $branch
- * @access protected
- * @return void
- */
- protected function parseUploadFile($productID, $branch)
- {
- /* 创建导入目录。*/
- /* Create import Directory. */
- $importDir = $this->app->getTmpRoot() . 'import';
- if(!is_dir($importDir)) mkdir($importDir, 0755, true);
- /* 将上传的临时文件移动到指定的临时位置。*/
- /* Move the uploaded temporary file to the specified temporary location. */
- $fileName = $this->app->user->id . '-xmind';
- $filePath = $importDir . '/' . $fileName;
- $tmpFile = $filePath . 'tmp';
- if(!move_uploaded_file($_FILES['file']['tmp_name'][0], $tmpFile)) return array('result' => 'fail', 'message' => $this->lang->testcase->errorXmindUpload);
- /* 删掉已经存在的当前用户的导入目录。*/
- /* Remove the file path. */
- $this->classFile = $this->app->loadClass('zfile');
- if(is_dir($filePath)) $this->classFile->removeDir($filePath);
- /* 压缩临时文件。*/
- /* Zip the temporary file. */
- $this->app->loadClass('pclzip', true);
- $zip = new pclzip($tmpFile);
- /* 获取 ZIP 文件中的内容列表。*/
- /* Get the content list from the zip file. */
- $files = $zip->listContent();
- $removePath = $files[0]['filename'];
- /* 限制解压的文件内容以阻止 ZIP 解压缩的目录穿越漏洞。*/
- /* Limit the file content to prevent the directory traversal vulnerability of ZIP decompression. */
- $extractFiles = array('content.json', 'content.xml');
- if(in_array($removePath, $extractFiles)) $removePath = '';
- if($zip->extract(PCLZIP_OPT_PATH, $filePath, PCLZIP_OPT_BY_NAME, $extractFiles, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0) return array('result' => 'fail', 'message' => $this->lang->testcase->errorXmindUpload);
- $this->classFile->removeFile($tmpFile);
- $this->classXmind = $this->app->loadClass('xmind');
- if(file_exists($filePath . '/content.json'))
- {
- $fetchResult = $this->fetchByJSON($filePath, $productID, $branch);
- }
- else
- {
- $fetchResult = $this->fetchByXML($filePath, $productID);
- }
- if($fetchResult['result'] == 'fail') return $fetchResult;
- $this->session->set('xmindImport', $filePath);
- $this->session->set('xmindImportType', $fetchResult['type']);
- return (int)$fetchResult['pID'];
- }
- /**
- * 获取 content.xml 的内容。
- * Fetch content.xml.
- *
- * @param string $filePath
- * @param int $productID
- * @access public
- * @return array
- */
- private function fetchByXML($filePath, $productID)
- {
- $file = $filePath . '/content.xml';
- $xmlNode = simplexml_load_file($file);
- $title = (string)$xmlNode->sheet->topic->title;
- if(!is_string($title) || strlen($title) == 0) return array('result' => 'fail', 'message' => $this->lang->testcase->errorXmindUpload);
- $pID = $productID;
- if($this->classXmind->endsWith($title, ']'))
- {
- $tmpID = $this->classXmind->getBetween($title, '[', ']');
- if(!empty($tmpID))
- {
- $product = $this->loadModel('product')->getByID((int)$tmpID);
- if(!$product || $product->deleted) return array('result' => 'fail', 'message' => $this->lang->testcase->errorImportBadProduct);
- $pID = $tmpID;
- }
- }
- return array('result' => 'success', 'pID' => $pID, 'type' => 'xml');
- }
- /**
- * 获取 content.json 的内容。
- * Fetch by json.
- *
- * @param string $filePath
- * @param int $productID
- * @param int|string $branch
- * @access public
- * @return array
- */
- function fetchByJSON($filePath, $productID, $branch)
- {
- $file = $filePath . '/content.json';
- $jsonStr = file_get_contents($file);
- $jsonDatas = json_decode($jsonStr, true);
- $title = $jsonDatas[0]['rootTopic']['title'];
- if(strlen($title) == 0) return array('result' => 'fail', 'message' => $this->lang->testcase->errorXmindUpload);
- $pID = $productID;
- if($this->classXmind->endsWith($title, ']'))
- {
- $tmpID = $this->classXmind->getBetween($title, '[', ']');
- if(!empty($tmpID))
- {
- $product = $this->loadModel('product')->getByID((int)$tmpID);
- if(!$product || $product->deleted) return array('result' => 'fail', 'message' => $this->lang->testcase->errorImportBadProduct);
- $pID = $tmpID;
- }
- }
- return array('result' => 'success', 'pID' => $pID, 'type' => 'json');
- }
- }
|