PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/core/types/ItemBlock.php

https://bitbucket.org/audax/testmaker-mod
PHP | 926 lines | 658 code | 114 blank | 154 comment | 144 complexity | ab86677649394e8f5fa2b8ae62719eb6 MD5 | raw file
Possible License(s): BSD-2-Clause, AGPL-1.0, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /* This file is part of testMaker.
  3. testMaker is free software; you can redistribute it and/or modify
  4. it under the terms of version 2 of the GNU General Public License as
  5. published by the Free Software Foundation.
  6. testMaker is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  12. /**
  13. * @package Core
  14. */
  15. /**
  16. * Include the Block class
  17. */
  18. require_once(dirname(__FILE__).'/ParentTreeBlock.php');
  19. /**
  20. * Include the Item class
  21. */
  22. require_once(dirname(__FILE__).'/Item.php');
  23. require_once(dirname(__FILE__).'/ItemBlockAnswer.php');
  24. /**
  25. * ItemBlock class
  26. *
  27. * @package Core
  28. */
  29. class ItemBlock extends ParentTreeBlock
  30. {
  31. function ItemBlock($id)
  32. {
  33. $this->db = &$GLOBALS['dao']->getConnection();
  34. $this->table = DB_PREFIX.'item_blocks';
  35. $this->sequence = DB_PREFIX.'item_blocks';
  36. $this->childrenTable = DB_PREFIX.'items';
  37. $this->ParentTreeBlock($id);
  38. }
  39. function _returnTreeChild($id, $type = NULL) {
  40. if (!$type) {
  41. $query = 'SELECT type FROM '.$this->childrenTable.' WHERE id = ?';
  42. $type = $this->db->getOne($query, array($id));
  43. if ($this->db->isError($type)) {
  44. return false;
  45. }
  46. }
  47. $type ? $type : $type = 'McsaItem';
  48. if (!file_exists(ROOT.'upload/items/'.$type.'.php')) {
  49. trigger_error('Unknown item type.');
  50. }
  51. require_once(ROOT.'upload/items/'.$type.'.php');
  52. return new $type($id);
  53. }
  54. function &getTreeChildren() {
  55. $query = 'SELECT id, type FROM '.$this->childrenTable.' WHERE '.$this->childrenConnector.' = ? ORDER BY pos ASC';
  56. $res = $this->db->getAll($query, array($this->id));
  57. if ($this->db->isError($res)) {
  58. return false;
  59. }
  60. $children = array();
  61. for ($i = 0; $i < count($res); $i ++) {
  62. $children[] = $this->_returnTreeChild($res[$i]['id'], $res[$i]['type']);
  63. }
  64. return $children;
  65. }
  66. function _createTreeChild($avalues)
  67. {
  68. if(array_key_exists('pos', $avalues) && !preg_match('/^[0-9]+$/', $avalues['pos']))
  69. {
  70. trigger_error('<b>ParentTreeBlock:createTreeChild</b>: '.$position.' is no valid position');
  71. return false;
  72. }
  73. if(!array_key_exists('pos', $avalues))
  74. {
  75. $avalues['pos'] = $this->getNextFreeTreePosition();
  76. }
  77. $id = $this->db->nextId($this->childrenTable);
  78. if($this->db->isError($id)) {
  79. return false;
  80. }
  81. $avalues['id'] = $id;
  82. if (!array_key_exists('type', $avalues) || !$avalues['type']) {
  83. $avalues['type'] = $this->getDefaultItemType();
  84. }
  85. $avalues[$this->childrenConnector] = $this->id;
  86. $avalues['t_created'] = time();
  87. $avalues['u_created'] = $GLOBALS['PORTAL']->getUserId();
  88. $avalues['t_modified'] = time();
  89. $avalues['u_modified'] = $GLOBALS['PORTAL']->getUserId();
  90. $values = '';
  91. $columns = '';
  92. $quote = array();
  93. for(reset($avalues); list($column, $value) = each($avalues); ) {
  94. if(strlen($columns) > 0)
  95. {
  96. $columns .= ', ';
  97. }
  98. if(strlen($values) > 0)
  99. {
  100. $values .= ', ';
  101. }
  102. $columns .= $column;
  103. $values .= '?';
  104. $quote[] = $value;
  105. }
  106. $query = 'INSERT INTO '.$this->childrenTable.' ('.$columns.') VALUES ('.$values.')';
  107. $result = $this->db->query($query, $quote);
  108. if($this->db->isError($result)) {
  109. return false;
  110. }
  111. return $this->_returnTreeChild($id);
  112. }
  113. /**
  114. * Returns if this an adaptive item block
  115. * @return bool
  116. */
  117. function isAdaptiveItemBlock()
  118. {
  119. $type = $this->_getField('type');
  120. if($type == 1) {
  121. return true;
  122. } else {
  123. return false;
  124. }
  125. }
  126. /**
  127. * Returns if the items of this block should be IRT rated
  128. * @return bool
  129. */
  130. function isIRTBlock()
  131. {
  132. $irt = $this->_getField('irt');
  133. if($irt == 1) {
  134. return true;
  135. } else {
  136. return false;
  137. }
  138. }
  139. /**
  140. * Returns if the items of this block should force an answer
  141. * @return bool
  142. */
  143. function isDefaultItemForced()
  144. {
  145. $force = $this->_getField('default_item_force');
  146. if($force == 1) {
  147. return true;
  148. } else {
  149. return false;
  150. }
  151. }
  152. /**
  153. * modify the given informations in the current block
  154. * @param mixed[] $modification values to be modified
  155. * @return bool
  156. */
  157. function modify($modifications)
  158. {
  159. $avalues = array();
  160. if(array_key_exists('type', $modifications)) {
  161. if(($modifications['type'] != 0) && ($modifications['type'] != 1)) {
  162. trigger_error('<b>ItemBlock:modify</b>: $modifications[\'type\'] is no valid type');
  163. return false;
  164. }
  165. $avalues['type'] = $modifications['type'];
  166. }
  167. if(array_key_exists('title', $modifications)) {
  168. $avalues['title'] = $modifications['title'];
  169. }
  170. if(array_key_exists('description', $modifications)) {
  171. $avalues['description'] = $modifications['description'];
  172. }
  173. if(array_key_exists('introduction', $modifications)) {
  174. $avalues['introduction'] = $modifications['introduction'];
  175. }
  176. if(array_key_exists('hidden_intro', $modifications)) {
  177. $avalues['hidden_intro'] = $modifications['hidden_intro'];
  178. }
  179. if(array_key_exists('intro_pos', $modifications)) {
  180. $avalues['intro_pos'] = $modifications['intro_pos'];
  181. }
  182. if(array_key_exists('permissions_recursive', $modifications)) {
  183. $avalues['permissions_recursive'] = $modifications['permissions_recursive'];
  184. }
  185. if(array_key_exists('default_item_type', $modifications)) {
  186. $avalues['default_item_type'] = $modifications['default_item_type'];
  187. }
  188. if(array_key_exists('default_template_align', $modifications)) {
  189. $avalues['default_template_align'] = $modifications['default_template_align'];
  190. }
  191. if(array_key_exists('default_template_cols', $modifications)) {
  192. $avalues['default_template_cols'] = $modifications['default_template_cols'];
  193. }
  194. if(array_key_exists('default_item_force', $modifications)) {
  195. $avalues['default_item_force'] = $modifications['default_item_force'];
  196. }
  197. if(array_key_exists('max_items', $modifications)) {
  198. $avalues['max_items'] = $modifications['max_items'];
  199. }
  200. if(array_key_exists('max_sem', $modifications)) {
  201. $avalues['max_sem'] = $modifications['max_sem'];
  202. }
  203. if(array_key_exists('max_time', $modifications)) {
  204. $avalues['max_time'] = $modifications['max_time'];
  205. }
  206. if(array_key_exists('irt', $modifications)) {
  207. $avalues['irt'] = $modifications['irt'];
  208. }
  209. if(array_key_exists('default_min_item_time', $modifications)) {
  210. $avalues['default_min_item_time'] = $modifications['default_min_item_time'];
  211. }
  212. if(array_key_exists('default_max_item_time', $modifications)) {
  213. $avalues['default_max_item_time'] = $modifications['default_max_item_time'];
  214. }
  215. if(array_key_exists('items_per_page', $modifications)) {
  216. $avalues['items_per_page'] = $modifications['items_per_page'];
  217. }
  218. if(array_key_exists('media_connect_id', $modifications)) {
  219. $avalues['media_connect_id'] = $modifications['media_connect_id'];
  220. }
  221. if(array_key_exists('intro_label', $modifications)) {
  222. $avalues['intro_label'] = $modifications['intro_label'];
  223. }
  224. if(array_key_exists('random_order', $modifications)) {
  225. $avalues['random_order'] = (int)$modifications['random_order'];
  226. }
  227. if(array_key_exists('disabled', $modifications)) {
  228. $avalues['disabled'] = $modifications['disabled'] ? 1 : 0;
  229. }
  230. return $this->_modify($avalues);
  231. }
  232. /**
  233. * prepare given array with data for database insertion
  234. * @param array associative array with database fields and content
  235. * @return array associative array with database fields and content
  236. */
  237. function prepareDBData($data) {
  238. if(!is_array($data)) {
  239. trigger_error('<b>ItemBlock:prepareDBData</b>: $data is no valid array');
  240. }
  241. $data2 = array();
  242. if(!isset($data['type'])) {
  243. $data['type'] = 0;
  244. } elseif(($data['type'] != 1) && ($data['type'] != 0)) {
  245. trigger_error('<b>ItemBlock:prepareDBData</b>: $data[\'type\'] is no correct item block type');
  246. return NULL;
  247. }
  248. $data2['type'] = $data['type'];
  249. if(!isset($data['irt']) || $data['irt'] == false) {
  250. $data2['irt'] = 0;
  251. } else {
  252. $data2['irt'] = 1;
  253. }
  254. if (!isset($data['original'])) {
  255. $data['original'] = 0;
  256. }
  257. if(!isset($data['intro_pos'])) {
  258. $data['intro_pos'] = 0;
  259. }
  260. $data2['original'] = $data['original'];
  261. if (!isset($data['default_item_type'])) {
  262. $data['default_item_type'] = '';
  263. }
  264. $data2['default_item_type'] = $data['default_item_type'];
  265. if (!isset($data['default_template_align'])) {
  266. $data['default_template_align'] = 'h';
  267. }
  268. $data2['default_template_align'] = $data['default_template_align'];
  269. if (!isset($data['default_template_cols'])) {
  270. $data['default_template_cols'] = 2;
  271. }
  272. $data2['default_template_cols'] = $data['default_template_cols'];
  273. if (!isset($data['default_item_force'])) {
  274. $data['default_item_force'] = 0;
  275. }
  276. $data2['default_item_force'] = $data['default_item_force'];
  277. if(!isset($data['max_items'])) {
  278. $data['max_items'] = 0;
  279. }
  280. $data2['max_items'] = $data['max_items'];
  281. if(!isset($data['max_sem'])) {
  282. $data['max_sem'] = 0;
  283. }
  284. $data2['max_sem'] = $data['max_sem'];
  285. if(!isset($data['max_time'])) {
  286. $data['max_time'] = 0;
  287. }
  288. $data2['max_time'] = $data['max_time'];
  289. if(!isset($data['default_max_item_time'])) {
  290. $data['default_max_item_time'] = 0;
  291. }
  292. $data2['default_max_item_time'] = $data['default_max_item_time'];
  293. if(!isset($data['default_min_item_time'])) {
  294. $data['default_min_item_time'] = 0;
  295. }
  296. $data2['default_min_item_time'] = $data['default_min_item_time'];
  297. if(!isset($data['items_per_page'])) {
  298. $data['items_per_page'] = 0;
  299. }
  300. $data2['items_per_page'] = $data['items_per_page'];
  301. return $data2;
  302. }
  303. /**
  304. * creates and returns a new item
  305. * @param mixed[] associative array of informations
  306. * @param boolean Whether to insert default item answers
  307. * @return Item
  308. */
  309. function createTreeChild($infos = array(), $useDefaults = true)
  310. {
  311. $avalues = Item::PrepareDBData($infos);
  312. if(!($child = $this->_createTreeChild($avalues))) {
  313. return false;
  314. }
  315. if (!$useDefaults) return $child;
  316. $defaultAnswers = $this->getDefaultAnswers();
  317. $infos = array();
  318. for($i = 0; $i < count($defaultAnswers); $i++) {
  319. $infos["answer"] = $defaultAnswers[$i]->getAnswer();
  320. if(!$child->createChild($infos)) {
  321. return false;
  322. }
  323. }
  324. return $child;
  325. }
  326. /**
  327. * Returns a copy of the current item block
  328. * @param parent id to copy item block into
  329. * @param 2 dimensional array where to store changed ids from item blocks and item answers for feedback blocks and dimensions format: array('blocks' => array(id1, id2, ...), 'item_answers' => array(id1, id2, ...))
  330. * @param array where to store problems if the block would be copied
  331. * @return ItemBlock
  332. */
  333. function copyNode($parentId, &$changedIds, &$problems)
  334. {
  335. $newNode = parent::copyNode($parentId, $changedIds, NULL, $problems);
  336. $fileHandling = new FileHandling();
  337. $mediaPath = str_replace(ROOT, '', $fileHandling->getFileDirectory()).'media/';
  338. if($newNode) {
  339. $value = preg_replace('/'.preg_quote($mediaPath, '/').'[0-9]+_/', $mediaPath.$newNode->getMediaConnectId().'_', $newNode->getIntroduction());
  340. $newNode->modify(array('introduction' => $value));
  341. }
  342. if(count($problems) == 0)
  343. {
  344. //copy default answers
  345. $query = 'SELECT * FROM '.DB_PREFIX.'item_block_answers WHERE item_block_id = ?';
  346. $results = $this->db->getAll($query, array($this->id));
  347. if($this->db->isError($results))
  348. {
  349. return false;
  350. }
  351. //$fileHandling = new FileHandling();
  352. foreach($results as $result) {
  353. $rows = array();
  354. $values = array();
  355. for(reset($result); list($key, $value) = each($result);)
  356. {
  357. switch($key)
  358. {
  359. case 'id':
  360. $value = $this->db->nextId(DB_PREFIX.'item_block_answers');
  361. break;
  362. case 'item_block_id':
  363. $value = $newNode->getId();
  364. break;
  365. case 't_created':
  366. $value = time();
  367. break;
  368. case 't_modified':
  369. $value = time();
  370. break;
  371. case 'answer':
  372. $mediaPath = str_replace(ROOT, '', $fileHandling->getFileDirectory()).'media/';
  373. $value = preg_replace('/'.preg_quote($mediaPath, '/').'[0-9]+_/', $mediaPath.$newNode->getMediaConnectId().'_', $value);
  374. }
  375. $rows[] = $key;
  376. $values[] = $value;
  377. }
  378. $query = 'INSERT INTO '.DB_PREFIX.'item_block_answers ('.implode(', ', $rows).') VALUES ('.ltrim(str_repeat(', ?', count($values)), ', ').')';
  379. $this->db->query($query, $values);
  380. }
  381. }
  382. return $newNode;
  383. }
  384. /**
  385. * Returns the number of maximal items for the current block
  386. * @return bool
  387. */
  388. function getMaxItems()
  389. {
  390. return $this->_getField('max_items');
  391. }
  392. /**
  393. * Returns the maximal SEM of the current block
  394. * @return bool
  395. */
  396. function getMaxSem()
  397. {
  398. return $this->_getField('max_sem');
  399. }
  400. /**
  401. * Returns the maximal time for the current block
  402. * @return bool
  403. */
  404. function getMaxTime()
  405. {
  406. return $this->_getField('max_time');
  407. }
  408. /**
  409. * Returns the default maximal time for items in current block
  410. * @return bool
  411. */
  412. function getDefaultMaxItemTime()
  413. {
  414. return $this->_getField('default_max_item_time');
  415. }
  416. /**
  417. * Returns the default minimal time for items in current block
  418. * @return bool
  419. */
  420. function getDefaultMinItemTime()
  421. {
  422. return $this->_getField('default_min_item_time');
  423. }
  424. function getIntroduction()
  425. {
  426. return $this->_getField('introduction');
  427. }
  428. function isHiddenIntro()
  429. {
  430. if ($this->_getField('hidden_intro') != 1)
  431. {
  432. return FALSE;
  433. }
  434. else
  435. {
  436. return TRUE;
  437. }
  438. }
  439. function getIntroPos()
  440. {
  441. return ! $this->_getField('intro_pos');
  442. }
  443. function getIntroLabel()
  444. {
  445. return $this->_getField('intro_label');
  446. }
  447. function hasRandomItemOrder()
  448. {
  449. return $this->_getField('random_order') == 1 ? true : false;
  450. }
  451. /**
  452. * get all default answers of the current itemblock
  453. * @return ItemBlockAnswer[]
  454. */
  455. function getDefaultAnswers()
  456. {
  457. $query = 'SELECT id FROM '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? ORDER BY pos ASC';
  458. $ids = $this->db->getAll($query, array($this->id));
  459. if($this->db->isError($ids))
  460. {
  461. return false;
  462. }
  463. $answers = array();
  464. for($i = 0; $i < count($ids); $i++) {
  465. $answers[] = new ItemBlockAnswer($ids[$i]['id']);
  466. }
  467. return $answers;
  468. }
  469. /**
  470. * delete default answer by given id
  471. * @param integer id of itemblock
  472. * @return boolean
  473. */
  474. function deleteDefaultAnswer($id) {
  475. if(!$this->existsDefaultAnswer($id)) {
  476. trigger_error('<b>ItemBlock:deleteDefaultAnswer</b>: $id is no valid default answer id in current itemblock');
  477. return false;
  478. }
  479. $query = 'DELETE FROM '.DB_PREFIX.'item_block_answers WHERE id = ?';
  480. $result = $this->db->query($query, array($id));
  481. if($this->db->isError($result))
  482. {
  483. return false;
  484. }
  485. return true;
  486. }
  487. /**
  488. * return default answer by given id
  489. * @return ItemAnswer
  490. */
  491. function getDefaultAnswerById($id)
  492. {
  493. $query = 'SELECT count(id) FROM '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? AND id = ?';
  494. $num = $this->db->getAll($query, array($this->id, $id));
  495. if($this->db->isError($num))
  496. {
  497. return false;
  498. }
  499. if($num == 0) {
  500. trigger_error('<b>ItemBlock::getDefaultAnswerById</b>: $id is no valid default answer id in this itemblock');
  501. return false;
  502. }
  503. return new ItemBlockAnswer($id);
  504. }
  505. /**
  506. * creates and returns a new default answer
  507. * @param $position position of default answer in itemblock
  508. * @param $optionalInfos associative array of optional informations (answer)
  509. * @return ItemAnswer
  510. */
  511. function createDefaultAnswer($position = NULL, $optionalInfos = array())
  512. {
  513. if($position != NULL && !preg_match('/ [0-9]+$/', $position)) {
  514. trigger_error('<b>ItemBlock::createDefaultAnswer</b>: $position is no valid position');
  515. return false;
  516. }
  517. if($position == NULL) {
  518. $position = $this->getNextFreeDefaultAnswerPosition();
  519. }
  520. $id = $this->db->nextId(DB_PREFIX.'item_block_answers');
  521. if($this->db->isError($id))
  522. {
  523. return false;
  524. }
  525. $avalues['id'] = $id;
  526. $avalues['item_block_id'] = $this->id;
  527. $avalues['pos'] = $position;
  528. $avalues['t_created'] = time();
  529. $avalues['t_modified'] = time();
  530. if(isset($optionalInfos['answer'])) {
  531. $avalues['answer'] = $optionalInfos['answer'];
  532. }
  533. $values = '';
  534. $columns = '';
  535. $quote = array();
  536. for(reset($avalues); list($column, $value) = each($avalues); ) {
  537. if(strlen($columns) > 0) {
  538. $columns .= ', ';
  539. }
  540. if(strlen($values) > 0) {
  541. $values .= ', ';
  542. }
  543. $columns .= $column;
  544. $values .= '?';
  545. $quote[] = $value;
  546. }
  547. $query = 'INSERT INTO '.DB_PREFIX.'item_block_answers ('.$columns.') VALUES ('.$values.')';
  548. $result = $this->db->query($query, $quote);
  549. if($this->db->isError($result))
  550. {
  551. return false;
  552. }
  553. return new ItemBlockAnswer($id);
  554. }
  555. /**
  556. * returns the next free position for a default answer
  557. * @return Item
  558. */
  559. function getNextFreeDefaultAnswerPosition()
  560. {
  561. $query = 'SELECT pos FROM '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? ORDER BY pos DESC LIMIT 1';
  562. if(!($position = $this->db->getOne($query, array($this->id))))
  563. {
  564. return 1;
  565. }
  566. else {
  567. if($this->db->isError($position))
  568. {
  569. return false;
  570. }
  571. return (((int) $position) + 1);
  572. }
  573. }
  574. /**
  575. * Returns a list of feedback blocks this block acts as a source for.
  576. */
  577. function getFeedbackDestinations()
  578. {
  579. $ids = $this->db->getAll('SELECT * FROM '.DB_PREFIX.'feedback_blocks_connect WHERE item_block_id = ?', array($this->id));
  580. if ($this->db->isError($ids)) {
  581. return array();
  582. }
  583. $res = array();
  584. foreach ($ids as $id) {
  585. $res[] = $GLOBALS["BLOCK_LIST"]->getBlockById($id['feedback_block_id'], BLOCK_TYPE_FEEDBACK);
  586. }
  587. return $res;
  588. }
  589. /**
  590. * returns if a default answer exists in current itemblock
  591. * @param integer id of item
  592. * @return boolean
  593. */
  594. function existsDefaultAnswer($id) {
  595. if(!preg_match('/^[0-9]+$/', $id)) {
  596. trigger_error('<b>ItemBlock:existsDefaultAnswer</b>: $id is no valid id');
  597. return false;
  598. }
  599. $query = 'SELECT count(id) from '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? AND id = ?';
  600. $result = $this->db->getOne($query, array($this->id, $id));
  601. if($this->db->isError($result))
  602. {
  603. return false;
  604. }
  605. if($result == 0) {
  606. return false;
  607. } else {
  608. return true;
  609. }
  610. }
  611. /**
  612. * returns if any default answer exists in current itemblock
  613. * @return boolean
  614. */
  615. function existsAnyDefaultAnswer() {
  616. $query = 'SELECT count(id) from '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? ';
  617. $result = $this->db->getOne($query, array($this->id));
  618. if($this->db->isError($result))
  619. {
  620. return false;
  621. }
  622. if($result == 0) {
  623. return false;
  624. } else {
  625. return true;
  626. }
  627. }
  628. /**
  629. * Checks if any default answer exists at the given position
  630. * @param integer Position of answer in item
  631. * @return boolean
  632. */
  633. function existsAnyDefaultAnswerAtPosition($position) {
  634. if(!preg_match('/^[0-9]+$/', $position)) {
  635. trigger_error('<b>ItemBlock:isAnyDefaultAnswerAtPosition</b>: $position is no valid position');
  636. return false;
  637. }
  638. $query = 'SELECT count(pos) from '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? AND pos = ?';
  639. $result = $this->db->getOne($query, array($this->id, $position));
  640. if($this->db->isError($result))
  641. {
  642. return false;
  643. }
  644. if($result > 0 ) {
  645. return true;
  646. } else {
  647. return false;
  648. }
  649. }
  650. /**
  651. * returns default answer at given Position
  652. * @param integer Position of item in itemblock
  653. * @return Answer
  654. */
  655. function getDefaultAnswerByPosition($position) {
  656. if(!preg_match('/^[0-9]+$/', $position)) {
  657. trigger_error('<b>ItemBlock:getDefaultAnswerByPosition</b>: $position is no valid position');
  658. return false;
  659. }
  660. $query = 'SELECT count(pos) from '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? AND pos = ?';
  661. $result = $this->db->getOne($query, array($this->id, $position));
  662. if($this->db->isError($result))
  663. {
  664. return false;
  665. }
  666. if($result == 0 ) {
  667. trigger_error('<b>ItemBlock:getDefaultAnswerByPosition</b>: no default answer found at $position');
  668. return false;
  669. }
  670. $query = 'SELECT id from '.DB_PREFIX.'item_block_answers WHERE item_block_id = ? AND pos = ?';
  671. $id = $this->db->getOne($query, array($this->id, $position));
  672. if($this->db->isError($id))
  673. {
  674. return false;
  675. }
  676. return new ItemBlockAnswer($id);
  677. }
  678. /**
  679. * returns the current item type
  680. * @return string
  681. */
  682. function getDefaultItemType()
  683. {
  684. $val = $this->_getField('default_item_type');
  685. if (!$val) return 'McsaItem';
  686. return $val;
  687. }
  688. /**
  689. * returns the current default item number of answer rows for the template
  690. * @return int
  691. */
  692. function getDefaultTemplateCols()
  693. {
  694. $val = $this->_getField('default_template_cols');
  695. if (!$val) return 2;
  696. return $val;
  697. }
  698. /**
  699. * returns the current default template align for the template
  700. * @return char
  701. */
  702. function getDefaultTemplateAlign()
  703. {
  704. $val = $this->_getField('default_template_align');
  705. if (!$val) return 'h';
  706. return $val;
  707. }
  708. /**
  709. * returns how many item are displayed at once
  710. * @return integer
  711. */
  712. function getItemsPerPage()
  713. {
  714. $val = $this->_getField('items_per_page');
  715. if (!$val) return 1;
  716. return $val;
  717. }
  718. /**
  719. * overwrite all item answers and item types with the default ones of the item block
  720. */
  721. function overwriteItems($overwrite) {
  722. $items = $this->getTreeChildren();
  723. $defaultAnswers = $this->getDefaultAnswers();
  724. $modifications = array();
  725. if(isset($overwrite['min_item_time']) && $overwrite['min_item_time']) {
  726. $modifications['min_time'] = $this->getDefaultMinItemTime();
  727. }
  728. if(isset($overwrite['max_item_time']) && $overwrite['max_item_time']) {
  729. $modifications['max_time'] = $this->getDefaultMaxItemTime();
  730. }
  731. if(isset($overwrite['item_force']) && $overwrite['item_force']) {
  732. $modifications['answer_force'] = $this->isDefaultItemForced();
  733. }
  734. $infos = array();
  735. for($i = 0; $i < count($items); $i++) {
  736. if(isset($overwrite['default_answers']) && $overwrite['default_answers']) {
  737. $answers = $items[$i]->getChildren();
  738. for($j = 0; $j < count($answers); $j++) {
  739. if(!$items[$i]->deleteChild($answers[$j]->getId())) {
  740. return false;
  741. }
  742. }
  743. for($j = 0; $j < count($defaultAnswers); $j++) {
  744. $infos["answer"] = $defaultAnswers[$j]->getAnswer();
  745. if(!$items[$i]->createChild($infos)) {
  746. return false;
  747. }
  748. }
  749. }
  750. if(sizeof($modifications) > 0) {
  751. if(!$items[$i]->modify($modifications)) {
  752. return false;
  753. }
  754. }
  755. }
  756. return true;
  757. }
  758. function getItemDisplayConditions($completeOnly = FALSE)
  759. {
  760. $conditions = array();
  761. foreach ($this->getTreeChildren() as $child)
  762. {
  763. foreach ($child->getConditions($completeOnly) as $condition) {
  764. $condition["owner_block_id"] = $this->getId();
  765. $condition["owner_item_id"] = $child->getId();
  766. $conditions[] = $condition;
  767. }
  768. }
  769. return $conditions;
  770. }
  771. function getItemIds()
  772. {
  773. $itemIds = array();
  774. foreach ($this->getTreeChildren() as $child) {
  775. $itemIds[] = $child->getId();
  776. }
  777. return $itemIds;
  778. }
  779. function orderChilds($newOrder)
  780. {
  781. // Item IDs
  782. $handledIds = array();
  783. foreach ($newOrder as $childId)
  784. {
  785. $child = $this->getTreeChildById($childId);
  786. $conditions = $child->getConditionsOnSiblings();
  787. foreach ($conditions as $condition) {
  788. if (! in_array($condition["item_id"], $handledIds) && $target = @$this->getTreeChildById($condition["item_id"])) {
  789. $GLOBALS["MSG_HANDLER"]->addMsg("types.item_block.order_conflict.condition", MSG_RESULT_NEG, array("referrer_title" => $child->getTitle(), "target_title" => $target->getTitle()));
  790. return FALSE;
  791. }
  792. }
  793. $handledIds[] = $child->getId();
  794. }
  795. return parent::orderChilds($newOrder);
  796. }
  797. /**
  798. *Return the number of shown Items of the block
  799. *@param int Id of the Block.
  800. *@return int
  801. */
  802. function getShownItems($testRun) {
  803. $answers = array();
  804. $answers = $testRun->getGivenAnswerSetsByBlockId($this->id);
  805. $num = count($answers);
  806. return $num;
  807. }
  808. }
  809. ?>