PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/functions/testcase.class.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 4679 lines | 2534 code | 517 blank | 1628 comment | 280 complexity | 85cec307c4494274c6a143574811ca1f MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * TestLink Open Source Project - http://testlink.sourceforge.net/
  4. * This script is distributed under the GNU General Public License 2 or later.
  5. *
  6. * @package TestLink
  7. * @author Francisco Mancardi (francisco.mancardi@gmail.com)
  8. * @copyright 2005-2009, TestLink community
  9. * @version CVS: $Id: testcase.class.php,v 1.295 2010/08/31 20:07:11 franciscom Exp $
  10. * @link http://www.teamst.org/index.php
  11. *
  12. * @internal Revisions:
  13. *
  14. * 20100831 - franciscom - BUGID 3729 - get_by_name()
  15. * 20100825 - franciscom - BUGID 3702 - _blind_delete() issue
  16. * 20100821 - franciscom - BUGID 3695 - Test Case Steps - Export/Import - missing attribute execution type
  17. * create_step() - fixed issue when execution_type was NULL.
  18. * new method - update_tcversion_steps() needed for BUGID 3634
  19. *
  20. * 20100814 - franciscom - getInternalID() - removed unused code and minor code rearrangement
  21. * changes in returned value when internal ID can not be found.
  22. * 20100813 - asimon - deactivated last slash on full path in get_assigned_to_user()
  23. * to remove it from test suite name in "tc assigned to user" tables
  24. * 20100802 - asimon - BUGID 3647 - filtering by build id in get_assigned_to_user()
  25. * 20100731 - asimon - more modifications to get_assigned_to_user()
  26. * 20100722 - asimon - BUGID 3406 - modified statement to get build name in get_assigned_to_user()
  27. * 20100714 - Julian - BUGID 3575 - get_assigned_to_user() added priority in output set
  28. * 20100712 - asimon - inserted missing semicolon after break in get_assigned_to_user()
  29. * 20100711 - franciscom - BUGID 3575 - get_assigned_to_user() added $filters as optional arg
  30. * 20100708 - franciscom - BUGID 3575 - get_assigned_to_user() add plaftorm in output set
  31. * 20100706 - franciscom - BUGID 3573 - _blind_delete() with alias has problems with MySQL
  32. * 20100521 - franciscom - BUGID 3481 - copy_tcversion() - preconditions are not copied
  33. * 20100516 - franciscom - BUGID 3465: Delete Test Project - User Execution Assignment is not deleted
  34. * 20100514 - franciscom - get_by_id() interface changes and improvements
  35. * 20100503 - franciscom - create_tcase_only() - BUGID 3374
  36. * 20100502 - franciscom - show() fixed error due to non existent variable $info
  37. * 20100417 - franciscom - new method - filter_tcversions()
  38. * get_last_active_version() - changes on output data
  39. * 20100411 - franciscom - BUGID 3387 - changes in show()
  40. * 20100411 - franciscom - new methods: get_last_active_version(),filter_tcversions_by_exec_type()
  41. * 20100409 - franciscom - BUGID 3367: Error after trying to copy a test case that the name is in the size limit.
  42. * 20100330 - eloff - BUGID 3329 - fixes test plan usage with platforms
  43. * 20100323 - asimon - fixed BUGID 3316 in show()
  44. * 20100317 - franciscom - new method get_by_external()
  45. * 20100315 - amitkhullar - Added options for Requirements and CFields for Export.
  46. * 20100309 - franciscom - get_by_id() - improvements on control to apply when LATEST_VERSION is requested.
  47. * 20100309 - franciscom - get_exec_status() - interface changes
  48. * get_linked_versions() - interface changes
  49. * BUGID 0003253
  50. *
  51. * 20100301 - franciscom - changes on show() to solve
  52. * BUGID 3181: From test case specification, after adding the test case
  53. * to test a plan with platforms, platforms are not displayed
  54. *
  55. * 20100210 - franciscom - keywords XML export refactored
  56. * 20100204 - franciscom - copyKeywordsTo(),copyReqAssignmentTo() - interface changes
  57. * 20100201 - franciscom - getExternalID(), refactored to improve performance when used on loops
  58. * 20100124 - franciscom - BUGID 3090 - problems when trying to delete a test case that has 0 steps.
  59. * 20100111 - franciscom - get_version_exec_assignment() - refactoring due to platforms feature.
  60. * get_linked_versions() - refactoring due to platforms feature.
  61. * 20100107 - franciscom - Multiple Test Case Steps Feature
  62. * Affected methods: delete(), _blind_delete()
  63. *
  64. * 20100106 - franciscom - Multiple Test Case Steps Feature
  65. * Affected methods: get_by_id(), create(), update()
  66. * get_last_version_info(), get_linked_versions(), copy_to()
  67. * copy_tcversion(),exportTestCaseDataToXML()
  68. *
  69. * 20100105 - franciscom - fixed missing copy of preconditions on copy_tcversion()
  70. * exportTestCaseDataToXML() - added execution_type, importance
  71. *
  72. * 20100104 - franciscom - create_new_version() - interface changes
  73. * new method get_basic_info()
  74. * fixed bug in show() regarding $gui->can_do->add2tplan
  75. * get_last_version_info() - interface changes
  76. * 20100103 - franciscom - getPrefix() - interface changes & refactoring
  77. * new methods - buildDirectWebLink(), getExternalID()
  78. * 20091229 - eloff - BUGID 3021 - getInternalID() - fixed error when tc prefix contains glue character
  79. * 20091220 - franciscom - copy_attachments() refactoring
  80. * 20091217 - franciscom - getDuplicatesByName() - new argument added
  81. * 20091215 - franciscom - getPrefix() - changed in return type, to avoid in some situations
  82. * a double call.
  83. * 20091207 - franciscom - get_last_execution() - internal bug
  84. * 20091127 - franciscom - getByPathName() new method
  85. * 20091118 - franciscom - get_last_execution() - still working ond fixing bug when using self::ALL_VERSIONS
  86. * 20091113 - franciscom - get_last_execution() - fixed bug when using self::ALL_VERSIONS
  87. * 20091003 - franciscom - show() changes in template get logic
  88. * 20090927 - franciscom - new methods: getPathLayered(),getPathTopSuite()
  89. * 20090922 - franciscom - get_last_execution() - used COALESCE() to return code
  90. * also code for NOT RUN status.
  91. * 20090831 - franciscom - added management of new field: preconditions
  92. * create(),update(),exportTestCaseDataToXML()
  93. *
  94. * 20090815 - franciscom - get_executions() - added platform related info
  95. * interface changes.
  96. * get_last_execution() - added platform related info
  97. *
  98. * 20090720 - franciscom - found bug in get_linked_cfields_at_execution()
  99. * when calling cfield_mgr class method
  100. *
  101. * 20090718 - franciscom - new method buildCFLocationMap();
  102. * 20090716 - franciscom - get_last_execution() - BUGID 2692 - interface changes.
  103. * 20090713 - franciscom - solved bug on get_executions() (bad SQL statement).
  104. * 20090530 - franciscom - html_table_of_custom_field_inputs() changes in interface
  105. * 20090526 - franciscom - html_table_of_custom_field_values() - added scope 'testplan_design'
  106. * 20090521 - franciscom - get_by_id() added version_number argument
  107. * 20090419 - franciscom - BUGID 2364 - show() changes on edit enabled logic
  108. * 20090414 - franciscom - BUGID 2378
  109. * 20090401 - franciscom - BUGID 2316 - changes to copy_to()
  110. * 20090308 - franciscom - BUGID 2204 - create() fixed return of new version number
  111. * 20090220 - franciscom - BUGID 2129
  112. * 20090106 - franciscom - BUGID - exportTestCaseDataToXML() - added export of custom fields values
  113. * 20081103 - franciscom - new method setKeywords() - added by schlundus
  114. * removed useless code from getTestProjectFromTestCase()
  115. * 20081015 - franciscom - delete() - improve controls to avoid bug if no children
  116. * 20080812 - franciscom - BUGID 1650 (REQ)
  117. * html_table_of_custom_field_inputs() interface changes
  118. * to manage custom fields with scope='testplan_design'
  119. *
  120. * 20080602 - franciscom - get_linked_versions() - internal changes due to BUG1504
  121. * get_exec_status() - interface and internal changes due to BUG1504
  122. *
  123. * 20080126 - franciscom - BUGID 1313
  124. */
  125. /** related functionality */
  126. require_once( dirname(__FILE__) . '/requirement_mgr.class.php' );
  127. require_once( dirname(__FILE__) . '/assignment_mgr.class.php' );
  128. require_once( dirname(__FILE__) . '/attachments.inc.php' );
  129. require_once( dirname(__FILE__) . '/users.inc.php' );
  130. /** list of supported format for Test case import/export */
  131. $g_tcFormatStrings = array ("XML" => lang_get('the_format_tc_xml_import'));
  132. /**
  133. * class for Test case CRUD
  134. * @package TestLink
  135. */
  136. class testcase extends tlObjectWithAttachments
  137. {
  138. const AUTOMATIC_ID=0;
  139. const DEFAULT_ORDER=0;
  140. const ALL_VERSIONS=0;
  141. const LATEST_VERSION=-1;
  142. const AUDIT_OFF=0;
  143. const AUDIT_ON=1;
  144. const CHECK_DUPLICATE_NAME=1;
  145. const DONT_CHECK_DUPLICATE_NAME=0;
  146. const ENABLED=1;
  147. const ALL_TESTPLANS=null;
  148. const ANY_BUILD=null;
  149. const GET_NO_EXEC=1;
  150. const ANY_PLATFORM=null;
  151. /** @var database handler */
  152. var $db;
  153. var $tree_manager;
  154. var $tproject_mgr;
  155. var $node_types_descr_id;
  156. var $node_types_id_descr;
  157. var $my_node_type;
  158. var $assignment_mgr;
  159. var $assignment_types;
  160. var $assignment_status;
  161. var $cfield_mgr;
  162. var $import_file_types = array("XML" => "XML", "XLS" => "XLS" );
  163. var $export_file_types = array("XML" => "XML");
  164. var $execution_types = array();
  165. /**
  166. * testplan class constructor
  167. *
  168. * @param resource &$db reference to database handler
  169. */
  170. function __construct(&$db)
  171. {
  172. $this->db = &$db;
  173. $this->tproject_mgr = new testproject($this->db);
  174. $this->tree_manager = &$this->tproject_mgr->tree_manager;
  175. $this->node_types_descr_id=$this->tree_manager->get_available_node_types();
  176. $this->node_types_id_descr=array_flip($this->node_types_descr_id);
  177. $this->my_node_type=$this->node_types_descr_id['testcase'];
  178. $this->assignment_mgr=New assignment_mgr($this->db);
  179. $this->assignment_types=$this->assignment_mgr->get_available_types();
  180. $this->assignment_status=$this->assignment_mgr->get_available_status();
  181. $this->cfield_mgr = new cfield_mgr($this->db);
  182. $this->execution_types = array(TESTCASE_EXECUTION_TYPE_MANUAL => lang_get('manual'),
  183. TESTCASE_EXECUTION_TYPE_AUTO => lang_get('automated'));
  184. // ATTENTION:
  185. // second argument is used to set $this->attachmentTableName,property that this calls
  186. // get from his parent
  187. parent::__construct($this->db,"nodes_hierarchy");
  188. }
  189. /*
  190. function: get_export_file_types
  191. getter
  192. args: -
  193. returns: map
  194. key: export file type code
  195. value: export file type verbose description
  196. */
  197. function get_export_file_types()
  198. {
  199. return $this->export_file_types;
  200. }
  201. /*
  202. function: get_impor_file_types
  203. getter
  204. args: -
  205. returns: map
  206. key: import file type code
  207. value: import file type verbose description
  208. */
  209. function get_import_file_types()
  210. {
  211. return $this->import_file_types;
  212. }
  213. /*
  214. function: get_execution_types
  215. getter
  216. args: -
  217. returns: map
  218. key: execution type code
  219. value: execution type verbose description
  220. */
  221. function get_execution_types()
  222. {
  223. return $this->execution_types;
  224. }
  225. /**
  226. * create a test case
  227. */
  228. function create($parent_id,$name,$summary,$preconditions,$steps,$author_id,
  229. $keywords_id='',$tc_order=self::DEFAULT_ORDER,$id=self::AUTOMATIC_ID,
  230. $execution_type=TESTCASE_EXECUTION_TYPE_MANUAL,
  231. $importance=2,$options=null)
  232. {
  233. $status_ok = 1;
  234. $my['options'] = array( 'check_duplicate_name' => self::DONT_CHECK_DUPLICATE_NAME,
  235. 'action_on_duplicate_name' => 'generate_new');
  236. $my['options'] = array_merge($my['options'], (array)$options);
  237. $ret = $this->create_tcase_only($parent_id,$name,$tc_order,$id,$my['options']);
  238. if($ret["status_ok"])
  239. {
  240. if(trim($keywords_id) != "")
  241. {
  242. $a_keywords = explode(",",$keywords_id);
  243. $this->addKeywords($ret['id'],$a_keywords);
  244. }
  245. $version_number = 1;
  246. if(isset($ret['version_number']) && $ret['version_number'] < 0)
  247. {
  248. // We are in the special situation we are only creating a new version,
  249. // useful when importing test cases. Need to get last version number.
  250. // I do not use create_new_version() because it does a copy ot last version
  251. // and do not allow to set new values in different fields while doing this operation.
  252. $last_version_info = $this->get_last_version_info($ret['id'],array('output' => 'minimun'));
  253. $version_number = $last_version_info['version']+1;
  254. $ret['msg'] = sprintf($ret['msg'],$version_number);
  255. // BUGID 2204
  256. $ret['version_number']=$version_number;
  257. }
  258. // Multiple Test Case Steps Feature
  259. $op = $this->create_tcversion($ret['id'],$ret['external_id'],$version_number,$summary,
  260. $preconditions,$steps,$author_id,$execution_type,$importance);
  261. $ret['msg'] = $op['status_ok'] ? $ret['msg'] : $op['msg'];
  262. }
  263. return $ret;
  264. }
  265. /*
  266. 20061008 - franciscom
  267. added [$check_duplicate_name]
  268. [$action_on_duplicate_name]
  269. 20060725 - franciscom - interface changes
  270. [$order]
  271. [$id]
  272. 0 -> the id will be assigned by dbms
  273. x -> this will be the id
  274. Warning: no check is done before insert => can got error.
  275. return:
  276. $ret['id']
  277. $ret['external_id']
  278. $ret['status_ok']
  279. $ret['msg'] = 'ok';
  280. $ret['new_name']
  281. rev:
  282. 20100503 - franciscom - BUGID 3374
  283. 20100409 - franciscom - improved check on name len.
  284. BUGID 3367: Error after trying to copy a test case that
  285. the name is in the size limit.
  286. 20090120 - franciscom - added new action_on_duplicate_name
  287. */
  288. function create_tcase_only($parent_id,$name,$order=self::DEFAULT_ORDER,$id=self::AUTOMATIC_ID,
  289. $options=null)
  290. {
  291. $dummy = config_get('field_size');
  292. $name_max_len = $dummy->testcase_name;
  293. $name = trim($name);
  294. $originalNameLen = tlStringLen($name);
  295. $getOptions = array();
  296. $ret = array('id' => -1,'external_id' => 0, 'status_ok' => 1,'msg' => 'ok',
  297. 'new_name' => '', 'version_number' => 1, 'has_duplicate' => false);
  298. $my['options'] = array( 'check_duplicate_name' => self::DONT_CHECK_DUPLICATE_NAME,
  299. 'action_on_duplicate_name' => 'generate_new');
  300. $my['options'] = array_merge($my['options'], (array)$options);
  301. $doCreate=true;
  302. if ($my['options']['check_duplicate_name'])
  303. {
  304. $algo_cfg = config_get('testcase_cfg')->duplicated_name_algorithm;
  305. $getOptions['check_criteria'] = ($algo_cfg->type == 'counterSuffix') ? 'like' : '=';
  306. $getOptions['access_key'] = ($algo_cfg->type == 'counterSuffix') ? 'name' : 'id';
  307. $itemSet = $this->getDuplicatesByName($name,$parent_id,$getOptions);
  308. if( !is_null($itemSet) && ($siblingQty=count($itemSet)) > 0 )
  309. {
  310. $ret['has_duplicate'] = true;
  311. switch($my['options']['action_on_duplicate_name'])
  312. {
  313. case 'block':
  314. $doCreate=false;
  315. $ret['status_ok'] = 0;
  316. $ret['msg'] = sprintf(lang_get('testcase_name_already_exists'),$name);
  317. break;
  318. case 'generate_new':
  319. $doCreate=true;
  320. switch($algo_cfg->type)
  321. {
  322. case 'stringPrefix':
  323. $name = $algo_cfg->text . " " . $name ;
  324. $final_len = strlen($name);
  325. if( $final_len > $name_max_len)
  326. {
  327. $name = substr($name,0,$name_max_len);
  328. }
  329. break;
  330. case 'counterSuffix':
  331. $mask = !is_null($algo_cfg->text) ? $algo_cfg->text : '#%s';
  332. $nameSet = array_flip(array_keys($itemSet));
  333. $target = $name . ($suffix = sprintf($mask,++$siblingQty));
  334. // BUGID 3367
  335. $final_len = strlen($target);
  336. if( $final_len > $name_max_len)
  337. {
  338. $target = substr($target,strlen($suffix),$name_max_len);
  339. }
  340. // Need to recheck if new generated name does not crash with existent name
  341. // why? Suppose you have created:
  342. // TC [1]
  343. // TC [2]
  344. // TC [3]
  345. // Then you delete TC [2].
  346. // When I got siblings il will got 2 siblings, if I create new progressive using next,
  347. // it will be 3 => I will get duplicated name.
  348. while( isset($nameSet[$target]) )
  349. {
  350. $target = $name . ($suffix = sprintf($mask,++$siblingQty));
  351. // BUGID 3367
  352. $final_len = strlen($target);
  353. if( $final_len > $name_max_len)
  354. {
  355. $target = substr($target,strlen($suffix),$name_max_len);
  356. }
  357. }
  358. $name = $target;
  359. break;
  360. }
  361. $ret['status_ok'] = 1;
  362. $ret['new_name'] = $name;
  363. $ret['msg'] = sprintf(lang_get('created_with_title'),$name);
  364. break;
  365. case 'create_new_version':
  366. $doCreate=false;
  367. // If we found more that one with same name and same parent,
  368. // will take the first one.
  369. // BUGID 3374
  370. $xx = current($itemSet);
  371. $ret['id'] = $xx['id'];
  372. $ret['external_id']=$xx['tc_external_id'];
  373. $ret['status_ok'] = 1;
  374. $ret['new_name'] = $name;
  375. $ret['version_number'] = -1;
  376. $ret['msg'] = lang_get('create_new_version');
  377. break;
  378. default:
  379. break;
  380. }
  381. }
  382. }
  383. if( $ret['status_ok'] && $doCreate)
  384. {
  385. $safeLenName = tlSubStr($name, 0, $name_max_len);
  386. // Get tproject id
  387. $path2root=$this->tree_manager->get_path($parent_id);
  388. $tproject_id=$path2root[0]['parent_id'];
  389. $tcaseNumber=$this->tproject_mgr->generateTestCaseNumber($tproject_id);
  390. $tcase_id = $this->tree_manager->new_node($parent_id,$this->my_node_type,$safeLenName,$order,$id);
  391. $ret['id'] = $tcase_id;
  392. $ret['external_id'] = $tcaseNumber;
  393. if( !$ret['has_duplicate'] )
  394. {
  395. $ret['new_name'] = $safeLenName;
  396. $ret['msg'] = sprintf(lang_get('testcase_name_length_exceeded'),$originalNameLen,$name_max_len);
  397. }
  398. }
  399. return $ret;
  400. }
  401. /*
  402. function: create_tcversion
  403. args:
  404. returns:
  405. rev:
  406. 20100821 - franciscom - BUGID 3696 - test case step execution type ignored
  407. 20100106 - franciscom - Multiple Test Case Steps Feature
  408. 20080113 - franciscom - interface changes added tc_ext_id
  409. */
  410. function create_tcversion($id,$tc_ext_id,$version,$summary,$preconditions,$steps,
  411. $author_id,$execution_type=TESTCASE_EXECUTION_TYPE_MANUAL,$importance=2)
  412. {
  413. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  414. $tcase_version_id = $this->tree_manager->new_node($id,$this->node_types_descr_id['testcase_version']);
  415. $sql = "/* $debugMsg */ INSERT INTO {$this->tables['tcversions']} " .
  416. " (id,tc_external_id,version,summary,preconditions," .
  417. "author_id,creation_ts,execution_type,importance) " .
  418. " VALUES({$tcase_version_id},{$tc_ext_id},{$version},'" .
  419. $this->db->prepare_string($summary) . "','" . $this->db->prepare_string($preconditions) . "'," .
  420. $this->db->prepare_int($author_id) . "," . $this->db->db_now() .
  421. ", {$execution_type},{$importance} )";
  422. $result = $this->db->exec_query($sql);
  423. $ret['msg']='ok';
  424. $ret['id']=$tcase_version_id;
  425. $ret['status_ok']=1;
  426. if ($result && ( !is_null($steps) && is_array($steps) ) )
  427. {
  428. $steps2create = count($steps);
  429. $op['status_ok'] = 1;
  430. for($jdx=0 ; ($jdx < $steps2create && $op['status_ok']); $jdx++)
  431. {
  432. $op = $this->create_step($tcase_version_id,$steps[$jdx]['step_number'],$steps[$jdx]['actions'],
  433. $steps[$jdx]['expected_results'],$steps[$jdx]['execution_type']);
  434. }
  435. }
  436. if (!$result)
  437. {
  438. $ret['msg'] = $this->db->error_msg();
  439. $ret['status_ok']=0;
  440. $ret['id']=-1;
  441. }
  442. return $ret;
  443. }
  444. /*
  445. function: getDuplicatesByname
  446. args: $name
  447. $parent_id
  448. returns: hash
  449. */
  450. function getDuplicatesByName($name, $parent_id, $options=null)
  451. {
  452. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  453. $my['options'] = array( 'check_criteria' => '=', 'access_key' => 'id');
  454. $my['options'] = array_merge($my['options'], (array)$options);
  455. $target = $this->db->prepare_string($name);
  456. switch($my['options']['check_criteria'])
  457. {
  458. case '=':
  459. default:
  460. $check_criteria = " AND NHA.name = '{$target}' ";
  461. break;
  462. case 'like':
  463. $check_criteria = " AND NHA.name LIKE '{$target}%' ";
  464. break;
  465. }
  466. $sql = " SELECT DISTINCT NHA.id,NHA.name,TCV.tc_external_id" .
  467. " FROM {$this->tables['nodes_hierarchy']} NHA, " .
  468. " {$this->tables['nodes_hierarchy']} NHB, {$this->tables['tcversions']} TCV " .
  469. " WHERE NHA.node_type_id = {$this->my_node_type} " .
  470. " AND NHB.parent_id=NHA.id " .
  471. " AND TCV.id=NHB.id " .
  472. " AND NHB.node_type_id = {$this->node_types_descr_id['testcase_version']} " .
  473. " AND NHA.parent_id={$parent_id} {$check_criteria}";
  474. $rs = $this->db->fetchRowsIntoMap($sql,$my['options']['access_key']);
  475. if( is_null($rs) || count($rs) == 0 )
  476. {
  477. $rs=null;
  478. }
  479. return $rs;
  480. }
  481. /*
  482. function: get_by_name
  483. args: $name
  484. [$tsuite_name]: name of parent test suite
  485. [$tproject_name]
  486. returns: hash
  487. @internal revisions
  488. 20100831 - franciscom - BUGID 3729
  489. */
  490. function get_by_name($name, $tsuite_name = '', $tproject_name = '')
  491. {
  492. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  493. $recordset = null;
  494. $filters_on = array('tsuite_name' => false, 'tproject_name' => false);
  495. // BUGID 3729 - limit all names
  496. $field_size = config_get('field_size');
  497. $tsuite_name = tlSubStr(trim($tsuite_name),0, $field_size->testsuite_name);
  498. $tproject_name = tlSubStr(trim($tproject_name),0,$field_size->testproject_name);
  499. $name = tlSubStr(trim($name), 0, $field_size->testcase_name);
  500. $sql = "/* $debugMsg */ " .
  501. " SELECT DISTINCT NH_TCASE.id,NH_TCASE.name,NH_TCASE_PARENT.id AS parent_id," .
  502. " NH_TCASE_PARENT.name AS tsuite_name, TCV.tc_external_id " .
  503. " FROM {$this->tables['nodes_hierarchy']} NH_TCASE, " .
  504. " {$this->tables['nodes_hierarchy']} NH_TCASE_PARENT, " .
  505. " {$this->tables['nodes_hierarchy']} NH_TCVERSIONS," .
  506. " {$this->tables['tcversions']} TCV " .
  507. " WHERE NH_TCASE.node_type_id = {$this->my_node_type} " .
  508. " AND NH_TCASE.name = '{$this->db->prepare_string($name)}' " .
  509. " AND TCV.id=NH_TCVERSIONS.id " .
  510. " AND NH_TCVERSIONS.parent_id=NH_TCASE.id " .
  511. " AND NH_TCASE_PARENT.id=NH_TCASE.parent_id ";
  512. if($tsuite_name != "")
  513. {
  514. $sql .= " AND NH_TCASE_PARENT.name = '{$this->db->prepare_string($tsuite_name)}' " .
  515. " AND NH_TCASE_PARENT.node_type_id = {$this->node_types_descr_id['testsuite']} ";
  516. }
  517. $recordset = $this->db->get_recordset($sql);
  518. if(count($recordset) && $tproject_name != "")
  519. {
  520. list($tproject_info)=$this->tproject_mgr->get_by_name($tproject_name);
  521. foreach($recordset as $idx => $tcase_info)
  522. {
  523. if( $this->get_testproject($tcase_info['id']) != $tproject_info['id'] )
  524. {
  525. unset($recordset[$idx]);
  526. }
  527. }
  528. }
  529. return $recordset;
  530. }
  531. /*
  532. get array of info for every test case
  533. without any kind of filter.
  534. Every array element contains an assoc array with testcase info
  535. */
  536. function get_all()
  537. {
  538. $sql = " SELECT nodes_hierarchy.name, nodes_hierarchy.id
  539. FROM {$this->tables['nodes_hierarchy']} nodes_hierarchy
  540. WHERE nodes_hierarchy.node_type_id={$my_node_type}";
  541. $recordset = $this->db->get_recordset($sql);
  542. return $recordset;
  543. }
  544. /**
  545. * Show Test Case logic
  546. *
  547. * @param object $smarty reference to smarty object (controls viewer).
  548. * @param integer $id Test case unique identifier
  549. * @param integer $version_id (optional) you can work on ONE test case version,
  550. * or on ALL; default: ALL
  551. *
  552. * @internal
  553. [viewer_args]: map with keys
  554. action
  555. msg_result
  556. refresh_tree: controls if tree view is refreshed after every operation.
  557. default: yes
  558. user_feedback
  559. disable_edit: used to overwrite user rights
  560. default: 0 -> no
  561. returns:
  562. rev :
  563. 20090215 - franciscom - added info about links to test plans
  564. 20081114 - franciscom -
  565. added arguments and options that are useful when this method is
  566. used to display test case search results.
  567. path_info: map: key: testcase id
  568. value: array with path to test case, where:
  569. element 0 -> test project name
  570. other elements test suites name
  571. new options on viewer_args: hilite_testcase_name,show_match_count
  572. 20070930 - franciscom - REQ - BUGID 1078
  573. added disable_edit argument
  574. */
  575. function show(&$smarty,$guiObj,$template_dir,$id,$version_id = self::ALL_VERSIONS,
  576. $viewer_args = null,$path_info=null,$mode=null)
  577. {
  578. $status_ok = 1;
  579. $gui = is_null($guiObj) ? new stdClass() : $guiObj;
  580. $gui->parentTestSuiteName='';
  581. $gui->path_info=$path_info;
  582. $gui->tprojectName='';
  583. $gui->linked_versions=null;
  584. $gui->tc_current_version = array();
  585. $gui->bodyOnLoad="";
  586. $gui->bodyOnUnload="";
  587. $gui->submitCode="";
  588. $gui->dialogName = '';
  589. $gui->platforms = null;
  590. $gui->tableColspan = 5; // sorry magic related to table to display steps
  591. $gui->opt_requirements = false;
  592. $gui_cfg = config_get('gui');
  593. $the_tpl = config_get('tpl');
  594. $my_template = isset($the_tpl['tcView']) ? $the_tpl['tcView'] : 'tcView.tpl';
  595. $tcase_cfg = config_get('testcase_cfg');
  596. $req_mgr = new requirement_mgr($this->db);
  597. $tc_other_versions = array();
  598. $status_quo_map = array();
  599. $keywords_map = array();
  600. $arrReqs = array();
  601. $userid_array = array();
  602. // 20090718 - franciscom
  603. $cf_smarty = null;
  604. $formatOptions=null;
  605. $cfx=0;
  606. $filters=$this->buildCFLocationMap();
  607. if( !is_null($mode) && $mode=='editOnExec' )
  608. {
  609. // refers to two javascript functions present in testlink_library.js
  610. // and logic used to refresh both frames when user call this
  611. // method to edit a test case while executing it.
  612. $gui->dialogName='tcview_dialog';
  613. $gui->bodyOnLoad="dialog_onLoad($gui->dialogName)";
  614. $gui->bodyOnUnload="dialog_onUnload($gui->dialogName)";
  615. $gui->submitCode="return dialog_onSubmit($gui->dialogName)";
  616. }
  617. $viewer_defaults=array('title' => lang_get('title_test_case'),'show_title' => 'no',
  618. 'action' => '', 'msg_result' => '','user_feedback' => '',
  619. 'refreshTree' => 1, 'disable_edit' => 0,
  620. 'display_testproject' => 0,'display_parent_testsuite' => 0,
  621. 'hilite_testcase_name' => 0,'show_match_count' => 0);
  622. if( !is_null($viewer_args) && is_array($viewer_args) )
  623. {
  624. foreach($viewer_defaults as $key => $value)
  625. {
  626. if(isset($viewer_args[$key]) )
  627. {
  628. $viewer_defaults[$key]=$viewer_args[$key];
  629. }
  630. }
  631. }
  632. $gui->show_title=$viewer_defaults['show_title'];
  633. $gui->display_testcase_path=!is_null($path_info);
  634. $gui->hilite_testcase_name=$viewer_defaults['hilite_testcase_name'];
  635. $gui->pageTitle=$viewer_defaults['title'];
  636. $gui->show_match_count=$viewer_defaults['show_match_count'];
  637. if($gui->show_match_count && $gui->display_testcase_path )
  638. {
  639. $gui->match_count=count($path_info);
  640. }
  641. // fine grain control of operations
  642. // if( $viewer_defaults['disable_edit'] == 1 || has_rights($this->db,"mgt_modify_tc") == 'no' )
  643. // BUGID 3387
  644. if( $viewer_defaults['disable_edit'] == 1 || has_rights($this->db,"mgt_modify_tc") == false)
  645. {
  646. $mode = 'editDisabled';
  647. }
  648. $gui->show_mode = $mode;
  649. $gui->can_do = $this->getShowViewerActions($mode);
  650. if(is_array($id))
  651. {
  652. $a_id = $id;
  653. }
  654. else
  655. {
  656. $status_ok = $id > 0 ? 1 : 0;
  657. $a_id = array($id);
  658. }
  659. if($status_ok)
  660. {
  661. $path2root = $this->tree_manager->get_path($a_id[0]);
  662. $tproject_id = $path2root[0]['parent_id'];
  663. $info = $this->tproject_mgr->get_by_id($tproject_id);
  664. $gui->opt_requirements = $info['opt']->requirementsEnabled;
  665. $platformMgr = new tlPlatform($this->db,$tproject_id);
  666. $gui->platforms = $platformMgr->getAllAsMap();
  667. // BUGID 2378
  668. $testplans = $this->tproject_mgr->get_all_testplans($tproject_id,array('plan_status' =>1) );
  669. $gui->has_testplans = !is_null($testplans) && count($testplans) > 0 ? 1 : 0;
  670. if( $viewer_defaults['display_testproject'] )
  671. {
  672. $gui->tprojectName=$info['name'];
  673. }
  674. if( $viewer_defaults['display_parent_testsuite'] )
  675. {
  676. $parent_idx = count($path2root)-2;
  677. $gui->parentTestSuiteName = $path2root[$parent_idx]['name'];
  678. }
  679. $tcasePrefix = $this->tproject_mgr->getTestCasePrefix($tproject_id);
  680. if(trim($tcasePrefix) != "")
  681. {
  682. // Add To Testplan button will be disabled if the testcase doesn't belong to the current selected testproject
  683. // $gui->can_do->add2tplan = 'no';
  684. if ($_SESSION['testprojectPrefix'] == $tcasePrefix)
  685. {
  686. $gui->can_do->add2tplan = $gui->can_do->add2tplan == 'yes' ? has_rights($this->db,"testplan_planning") : 'no';
  687. }
  688. else
  689. {
  690. $gui->can_do->add2tplan = 'no';
  691. }
  692. $tcasePrefix .= $tcase_cfg->glue_character;
  693. }
  694. }
  695. if($status_ok && sizeof($a_id))
  696. {
  697. $allTCKeywords = $this->getKeywords($a_id,null,'testcase_id',' ORDER BY keyword ASC ');
  698. $allReqs = $req_mgr->get_all_for_tcase($a_id);
  699. foreach($a_id as $key => $tc_id)
  700. {
  701. $tc_array = $this->get_by_id($tc_id,$version_id);
  702. if (!$tc_array)
  703. {
  704. continue;
  705. }
  706. $tc_array[0]['tc_external_id'] = $tcasePrefix . $tc_array[0]['tc_external_id'];
  707. // get the status quo of execution and links of tc versions
  708. $status_quo_map[] = $this->get_versions_status_quo($tc_id);
  709. $gui->linked_versions[] = $this->get_linked_versions($tc_id);
  710. $keywords_map[] = isset($allTCKeywords[$tc_id]) ? $allTCKeywords[$tc_id] : null;
  711. $tc_current = $tc_array[0];
  712. $gui->tc_current_version[] = array($tc_current);
  713. //Get UserID and Updater ID for current Version
  714. $userid_array[$tc_current['author_id']] = null;
  715. $userid_array[$tc_current['updater_id']] = null;
  716. if(count($tc_array) > 1)
  717. {
  718. $tc_other_versions[] = array_slice($tc_array,1);
  719. }
  720. else
  721. {
  722. $tc_other_versions[] = null;
  723. }
  724. //Get author and updater id for each version
  725. if ($tc_other_versions[0])
  726. {
  727. foreach($tc_other_versions[0] as $key => $version)
  728. {
  729. $userid_array[$version['author_id']] = null;
  730. $userid_array[$version['updater_id']] = null;
  731. }
  732. }
  733. $tcReqs = isset($allReqs[$tc_id]) ? $allReqs[$tc_id] : null;
  734. $arrReqs[] = $tcReqs;
  735. foreach($filters as $locationKey => $locationFilter)
  736. {
  737. $cf_smarty[$cfx][$locationKey] =
  738. $this->html_table_of_custom_field_values($tc_id,'design',$locationFilter,
  739. null,null,$tproject_id);
  740. }
  741. $cfx++;
  742. } // foreach($a_id as $key => $tc_id)
  743. } // if (sizeof($a_id))
  744. // Removing duplicate and NULL id's
  745. unset($userid_array['']);
  746. $passeduserarray = array_keys($userid_array);
  747. $gui->cf = $cf_smarty;
  748. $gui->refreshTree = $viewer_defaults['refreshTree'];
  749. $gui->sqlResult = $viewer_defaults['msg_result'];
  750. $gui->action = $viewer_defaults['action'];
  751. $gui->user_feedback = $viewer_defaults['user_feedback'];
  752. $gui->execution_types = $this->execution_types;
  753. $gui->tcase_cfg = $tcase_cfg;
  754. $gui->users = tlUser::getByIDs($this->db,$passeduserarray,'id');
  755. $gui->status_quo = $status_quo_map;
  756. $gui->testcase_other_versions = $tc_other_versions;
  757. $gui->arrReqs = $arrReqs;
  758. $gui->view_req_rights = has_rights($this->db,"mgt_view_req");
  759. $gui->keywords_map = $keywords_map;
  760. $smarty->assign('gui',$gui);
  761. $smarty->display($template_dir . $my_template);
  762. }
  763. /**
  764. * update test case specification
  765. *
  766. * @param integer $id Test case unique identifier (node_hierarchy table)
  767. * @param integer $tcversion_id Test Case Version unique ID (node_hierarchy table)
  768. * @param string $name name/title
  769. * @param string $summary
  770. * @param string $preconditions
  771. * @param array $steps steps + expected results
  772. * @param integer $user_id who is doing the update
  773. * @param string $keywords_id optional list of keyword id to be linked to test case
  774. * this list will override previous keyword links (delete + insert).
  775. *
  776. * @param integer $tc_order optional order inside parent test suite
  777. * @param integer $execution_type optional
  778. * @param integer $importance optional
  779. *
  780. *
  781. *
  782. */
  783. function update($id,$tcversion_id,$name,$summary,$preconditions,$steps,
  784. $user_id,$keywords_id='',$tc_order=self::DEFAULT_ORDER,
  785. $execution_type=TESTCASE_EXECUTION_TYPE_MANUAL,$importance=2)
  786. {
  787. $ret['status_ok'] = 1;
  788. $ret['msg'] = '';
  789. tLog("TC UPDATE ID=($id): exec_type=$execution_type importance=$importance");
  790. // Check if new name will be create a duplicate testcase under same parent
  791. $checkDuplicates = config_get('check_names_for_duplicates');
  792. if ($checkDuplicates)
  793. {
  794. $check = $this->tree_manager->nodeNameExists($name,$this->my_node_type,$id);
  795. $ret['status_ok'] = !$check['status'];
  796. $ret['msg'] = $check['msg'];
  797. }
  798. if($ret['status_ok'])
  799. {
  800. $sql=array();
  801. $sql[] = " UPDATE {$this->tables['nodes_hierarchy']} SET name='" .
  802. $this->db->prepare_string($name) . "' WHERE id= {$id}";
  803. // test case version
  804. $sql[] = " UPDATE {$this->tables['tcversions']} tcversions " .
  805. " SET summary='" . $this->db->prepare_string($summary) . "'," .
  806. " updater_id=" . $this->db->prepare_int($user_id) . ", " .
  807. " modification_ts = " . $this->db->db_now() . "," .
  808. " execution_type=" . $this->db->prepare_int($execution_type) . ", " .
  809. " importance=" . $this->db->prepare_int($importance) . "," .
  810. " preconditions='" . $this->db->prepare_string($preconditions) . "' " .
  811. " WHERE tcversions.id = " . $this->db->prepare_int($tcversion_id);
  812. foreach($sql as $stm)
  813. {
  814. $result = $this->db->exec_query($stm);
  815. if( !$result )
  816. {
  817. $ret['status_ok'] = 0;
  818. $ret['msg'] = $this->db->error_msg;
  819. break;
  820. }
  821. }
  822. // BUGID 3634 - missing update.
  823. if( $ret['status_ok'] && !is_null($steps) )
  824. {
  825. $this->update_tcversion_steps($tcversion_id,$steps);
  826. }
  827. if( $ret['status_ok'] )
  828. {
  829. $this->updateKeywordAssignment($id,$keywords_id);
  830. }
  831. }
  832. return $ret;
  833. }
  834. /*
  835. function: updateKeywordAssignment
  836. args:
  837. returns:
  838. */
  839. private function updateKeywordAssignment($id,$keywords_id)
  840. {
  841. // To avoid false loggings, check is delete is needed
  842. $items = array();
  843. $items['stored'] = $this->get_keywords_map($id);
  844. if (is_null($items['stored']))
  845. $items['stored'] = array();
  846. $items['requested'] = array();
  847. if(trim($keywords_id) != "")
  848. {
  849. $a_keywords = explode(",",trim($keywords_id));
  850. $sql = " SELECT id,keyword " .
  851. " FROM {$this->tables['keywords']} " .
  852. " WHERE id IN (" . implode(',',$a_keywords) . ")";
  853. $items['requested'] = $this->db->fetchColumnsIntoMap($sql,'id','keyword');
  854. }
  855. $items['common'] = array_intersect_assoc($items['stored'],$items['requested']);
  856. $items['new'] = array_diff_assoc($items['requested'],$items['common']);
  857. $items['todelete'] = array_diff_assoc($items['stored'],$items['common']);
  858. if(!is_null($items['todelete']) && count($items['todelete']))
  859. {
  860. $this->deleteKeywords($id,array_keys($items['todelete']),self::AUDIT_ON);
  861. }
  862. if(!is_null($items['new']) && count($items['new']))
  863. {
  864. $this->addKeywords($id,array_keys($items['new']),self::AUDIT_ON);
  865. }
  866. }
  867. /*
  868. function: logKeywordChanges
  869. args:
  870. returns:
  871. */
  872. function logKeywordChanges($old,$new)
  873. {
  874. // try to understand the really new
  875. }
  876. /*
  877. function: check_link_and_exec_status
  878. Fore every version of testcase (id), do following checks:
  879. 1. testcase is linked to one of more test plans ?
  880. 2. if anwser is yes then,check if has been executed => has records on executions table
  881. args : id: testcase id
  882. returns: string with following values:
  883. no_links: testcase is not linked to any testplan
  884. linked_but_not_executed: testcase is linked at least to a testplan
  885. but has not been executed.
  886. linked_and_executed: testcase is linked at least to a testplan and
  887. has been executed => has records on executions table.
  888. */
  889. function check_link_and_exec_status($id)
  890. {
  891. $status = 'no_links';
  892. // get linked versions
  893. // ATTENTION TO PLATFORMS
  894. $linked_tcversions = $this->get_linked_versions($id);
  895. $has_links_to_testplans = is_null($linked_tcversions) ? 0 : 1;
  896. if($has_links_to_testplans)
  897. {
  898. // check if executed
  899. $linked_not_exec = $this->get_linked_versions($id,"NOT_EXECUTED");
  900. $status='linked_and_executed';
  901. if(count($linked_tcversions) == count($linked_not_exec))
  902. {
  903. $status = 'linked_but_not_executed';
  904. }
  905. }
  906. return $status;
  907. }
  908. /*
  909. rev:
  910. 20100107 - franciscom - Multiple Test Case Step Feature
  911. 20081015 - franciscom - added check to avoid bug due to no children
  912. */
  913. function delete($id,$version_id = self::ALL_VERSIONS)
  914. {
  915. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  916. $children=null;
  917. $do_it=true;
  918. // I'm trying to speedup the next deletes
  919. $sql="/* $debugMsg */ " .
  920. " SELECT NH_TCV.id AS tcversion_id, NH_TCSTEPS.id AS step_id " .
  921. " FROM {$this->tables['nodes_hierarchy']} NH_TCV " .
  922. " LEFT OUTER JOIN {$this->tables['nodes_hierarchy']} NH_TCSTEPS " .
  923. " ON NH_TCSTEPS.parent_id = NH_TCV.id ";
  924. if($version_id == self::ALL_VERSIONS)
  925. {
  926. if( is_array($id) )
  927. {
  928. $sql .= " WHERE NH_TCV.parent_id IN (" .implode(',',$id) . ") ";
  929. }
  930. else
  931. {
  932. $sql .= " WHERE NH_TCV.parent_id={$id} ";
  933. }
  934. }
  935. else
  936. {
  937. $sql .= " WHERE NH_TCV.parent_id={$id} AND NH_TCV.id = {$version_id}";
  938. }
  939. $children_rs=$this->db->get_recordset($sql);
  940. $do_it = !is_null($children_rs);
  941. if($do_it)
  942. {
  943. foreach($children_rs as $value)
  944. {
  945. $children['tcversion'][]=$value['tcversion_id'];
  946. $children['step'][]=$value['step_id'];
  947. }
  948. $this->_execution_delete($id,$version_id,$children);
  949. $this->_blind_delete($id,$version_id,$children);
  950. }
  951. return 1;
  952. }
  953. /*
  954. function: get_linked_versions
  955. For a test case get information about versions linked to testplans.
  956. Filters can be applied on:
  957. execution status
  958. active status
  959. args : id: testcase id
  960. [exec_status]: default: ALL, range: ALL,EXECUTED,NOT_EXECUTED
  961. [active_status]: default: ALL, range: ALL,ACTIVE,INACTIVE
  962. [tplan_id]
  963. returns: map.
  964. key: version id
  965. value: map with following structure:
  966. key: testplan id
  967. value: map with following structure:
  968. testcase_id
  969. tcversion_id
  970. id -> tcversion_id (node id)
  971. version
  972. summary
  973. importance
  974. author_id
  975. creation_ts
  976. updater_id
  977. modification_ts
  978. active
  979. is_open
  980. testplan_id
  981. tplan_name
  982. */
  983. function get_linked_versions($id,$exec_status="ALL",$active_status='ALL',$tplan_id=null,$platform_id=null)
  984. {
  985. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  986. $active_filter='';
  987. $active_status=strtoupper($active_status);
  988. if($active_status !='ALL')
  989. {
  990. $active_filter=' AND tcversions.active=' . $active_status=='ACTIVE' ? 1 : 0;
  991. }
  992. switch ($exec_status)
  993. {
  994. case "ALL":
  995. $sql = "/* $debugMsg */ " .
  996. " SELECT NH.parent_id AS testcase_id, NH.id AS tcversion_id, " .
  997. " tcversions.*, TTC.testplan_id, TTC.tcversion_id, TTC.platform_id," .
  998. " NHB.name AS tplan_name " .
  999. " FROM {$this->tables['nodes_hierarchy']} NH," .
  1000. " {$this->tables['tcversions']} tcversions," .
  1001. " {$this->tables['testplan_tcversions']} TTC, " .
  1002. " {$this->tables['nodes_hierarchy']} NHB " .
  1003. " WHERE TTC.tcversion_id = tcversions.id {$active_filter} " .
  1004. " AND tcversions.id = NH.id " .
  1005. " AND NHB.id = TTC.testplan_id " .
  1006. " AND NH.parent_id = {$id}";
  1007. if(!is_null($tplan_id))
  1008. {
  1009. $sql .= " AND TTC.testplan_id = {$tplan_id} ";
  1010. }
  1011. // 20100308 - franciscom
  1012. if(!is_null($platform_id))
  1013. {
  1014. $sql .= " AND TTC.platform_id = {$platform_id} ";
  1015. }
  1016. $recordset = $this->db->fetchMapRowsIntoMap($sql,'tcversion_id','testplan_id',database::CUMULATIVE);
  1017. // 20100330 - eloff - BUGID 3329
  1018. if( !is_null($recordset) )
  1019. {
  1020. // changes third access key from sequential index to platform_id
  1021. foreach ($recordset as $accessKey => $testplan)
  1022. {
  1023. foreach ($testplan as $tplanKey => $testcases)
  1024. {
  1025. // Use a temporary array to avoid key collisions
  1026. $newArray = array();
  1027. foreach ($testcases as $elemKey => $element)
  1028. {
  1029. $platform_id = $element['platform_id'];
  1030. $newArray[$platform_id] = $element;
  1031. }
  1032. $recordset[$accessKey][$tplanKey] = $newArray;
  1033. }
  1034. }
  1035. }
  1036. break;
  1037. case "EXECUTED":
  1038. $recordset=$this->get_exec_status($id,$exec_status,$active_status,$tplan_id,$platform_id);
  1039. break;
  1040. case "NOT_EXECUTED":
  1041. $recordset=$this->get_exec_status($id,$exec_status,$active_status,$tplan_id,$platform_id);
  1042. break;
  1043. }
  1044. // Multiple Test Case Steps
  1045. if( !is_null($recordset) )
  1046. {
  1047. $version2loop = array_keys($recordset);
  1048. foreach( $version2loop as $accessKey)
  1049. {
  1050. $step_set = $this->get_steps($accessKey);
  1051. $tplan2loop = array_keys($recordset[$accessKey]);
  1052. foreach( $tplan2loop as $tplanKey)
  1053. {
  1054. $elem2loop = array_keys($recordset[$accessKey][$tplanKey]);
  1055. foreach( $elem2loop as $elemKey)
  1056. {
  1057. $recordset[$accessKey][$tplanKey][$elemKey]['steps'] = $step_set;
  1058. }
  1059. }
  1060. }
  1061. }
  1062. return $recordset;
  1063. }
  1064. /*
  1065. Delete the following info:
  1066. req_coverage
  1067. risk_assignment
  1068. custom fields
  1069. keywords
  1070. links to test plans
  1071. tcversions
  1072. nodes from hierarchy
  1073. rev:
  1074. 20100825 - BUGID 3702
  1075. 20070602 - franciscom - delete attachments
  1076. */
  1077. function _blind_delete($id,$version_id=self::ALL_VERSIONS,$children=null)
  1078. {
  1079. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  1080. $sql = array();
  1081. $destroyTC = false;
  1082. $item_id = $version_id;
  1083. $tcversion_list = $version_id;
  1084. if( $version_id == self::ALL_VERSIONS)
  1085. {
  1086. $destroyTC = true;
  1087. $item_id = $id;
  1088. $tcversion_list=implode(',',$children['tcversion']);
  1089. }
  1090. // BUGID 3465: Delete Test Project - User Execution Assignment is not deleted
  1091. // BUGID 3573: MySQL does not like ALIAS
  1092. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['user_assignments']} " .
  1093. " WHERE feature_id in (" .
  1094. " SELECT id FROM {$this->tables['testplan_tcversions']} " .
  1095. " WHERE tcversion_id IN ({$tcversion_list}))";
  1096. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['testplan_tcversions']} " .
  1097. " WHERE tcversion_id IN ({$tcversion_list})";
  1098. // Multiple Test Case Steps Feature
  1099. // BUGID 3702
  1100. if( !is_null($children['step']) )
  1101. {
  1102. // remove null elements
  1103. foreach($children['step'] as $key => $value)
  1104. {
  1105. if(is_null($value))
  1106. {
  1107. unset($children['step'][$key]);
  1108. }
  1109. }
  1110. if( count($children['step']) > 0)
  1111. {
  1112. $step_list=trim(implode(',',$children['step']));
  1113. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['tcsteps']} " .
  1114. " WHERE id IN ({$step_list})";
  1115. }
  1116. }
  1117. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['tcversions']} " .
  1118. " WHERE id IN ({$tcversion_list})";
  1119. foreach ($sql as $the_stm)
  1120. {
  1121. $result = $this->db->exec_query($the_stm);
  1122. }
  1123. if($destroyTC)
  1124. {
  1125. // Remove data that is related to Test Case => must be deleted when there is no more trace
  1126. // of test case => when all version are deleted
  1127. $sql = null;
  1128. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['testcase_keywords']} WHERE testcase_id = {$id}";
  1129. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['req_coverage']} WHERE testcase_id = {$id}";
  1130. foreach ($sql as $the_stm)
  1131. {
  1132. $result = $this->db->exec_query($the_stm);
  1133. }
  1134. $this->deleteAttachments($id);
  1135. $this->cfield_mgr->remove_all_design_values_from_node($id);
  1136. }
  1137. // Attention:
  1138. // After addition of test case steps feature, a test case version can be root of
  1139. // a subtree that contains the steps.
  1140. $this->tree_manager->delete_subtree($item_id);
  1141. }
  1142. /*
  1143. Delete the following info:
  1144. bugs
  1145. executions
  1146. cfield_execution_values
  1147. */
  1148. function _execution_delete($id,$version_id=self::ALL_VERSIONS,$children=null)
  1149. {
  1150. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  1151. $sql = array();
  1152. if( $version_id == self::ALL_VERSIONS )
  1153. {
  1154. $tcversion_list=implode(',',$children['tcversion']);
  1155. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['execution_bugs']} " .
  1156. " WHERE execution_id IN (SELECT id FROM {$this->tables['executions']} " .
  1157. " WHERE tcversion_id IN ({$tcversion_list}))";
  1158. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['cfield_execution_values']} " .
  1159. " WHERE tcversion_id IN ({$tcversion_list})";
  1160. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['executions']} " .
  1161. " WHERE tcversion_id IN ({$tcversion_list})";
  1162. }
  1163. else
  1164. {
  1165. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['execution_bugs']} " .
  1166. " WHERE execution_id IN (SELECT id FROM {$this->tables['executions']} " .
  1167. " WHERE tcversion_id = {$version_id})";
  1168. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['cfield_execution_values']} " .
  1169. " WHERE tcversion_id = {$version_id}";
  1170. $sql[]="/* $debugMsg */ DELETE FROM {$this->tables['executions']} " .
  1171. " WHERE tcversion_id = {$version_id}";
  1172. }

Large files files are truncated, but you can click here to view the full file