exercise.class.php 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. <?php
  2. /*
  3. ==============================================================================
  4. Dokeos - elearning and course management software
  5. Copyright (c) 2004-2008 Dokeos SPRL
  6. For a full list of contributors, see "credits.txt".
  7. The full license can be read in "license.txt".
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License
  10. as published by the Free Software Foundation; either version 2
  11. of the License, or (at your option) any later version.
  12. See the GNU General Public License for more details.
  13. Contact address: Dokeos, rue du Corbeau, 108, B-1030 Brussels, Belgium
  14. Mail: info@dokeos.com
  15. ==============================================================================
  16. */
  17. /**
  18. * Exercise class: This class allows to instantiate an object of type Exercise
  19. * @package dokeos.exercise
  20. * @author Olivier Brouckaert
  21. * @version $Id: exercise.class.php 22046 2009-07-14 01:45:19Z ivantcholakov $
  22. */
  23. if(!class_exists('Exercise')):
  24. class Exercise
  25. {
  26. var $id;
  27. var $exercise;
  28. var $description;
  29. var $sound;
  30. var $type;
  31. var $random;
  32. var $active;
  33. var $timeLimit;
  34. var $attempts;
  35. var $feedbacktype;
  36. var $end_time;
  37. var $start_time;
  38. var $questionList; // array with the list of this exercise's questions
  39. var $results_disabled;
  40. /**
  41. * constructor of the class
  42. *
  43. * @author - Olivier Brouckaert
  44. */
  45. function Exercise()
  46. {
  47. $this->id=0;
  48. $this->exercise='';
  49. $this->description='';
  50. $this->sound='';
  51. $this->type=1;
  52. $this->random=0;
  53. $this->active=1;
  54. $this->questionList=array();
  55. $this->timeLimit = 0;
  56. $this->end_time = '0000-00-00 00:00:00';
  57. $this->start_time = '0000-00-00 00:00:00';
  58. $this->results_disabled =1;
  59. }
  60. /**
  61. * reads exercise informations from the data base
  62. *
  63. * @author - Olivier Brouckaert
  64. * @param - integer $id - exercise ID
  65. * @return - boolean - true if exercise exists, otherwise false
  66. */
  67. function read($id)
  68. {
  69. global $_course;
  70. global $_configuration;
  71. global $questionList;
  72. $TBL_EXERCICE_QUESTION = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
  73. $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
  74. $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
  75. #$TBL_REPONSES = Database::get_course_table(TABLE_QUIZ_ANSWER);
  76. $sql="SELECT title,description,sound,type,random,active, results_disabled, max_attempt,start_time,end_time,feedback_type FROM $TBL_EXERCICES WHERE id='".Database::escape_string($id)."'";
  77. $result=api_sql_query($sql,__FILE__,__LINE__);
  78. // if the exercise has been found
  79. if($object=Database::fetch_object($result))
  80. {
  81. $this->id=$id;
  82. $this->exercise=$object->title;
  83. $this->description=$object->description;
  84. $this->sound=$object->sound;
  85. $this->type=$object->type;
  86. $this->random=$object->random;
  87. $this->active=$object->active;
  88. $this->results_disabled =$object->results_disabled;
  89. $this->attempts = $object->max_attempt;
  90. $this->feedbacktype = $object->feedback_type;
  91. $this->end_time = $object->end_time;
  92. $this->start_time = $object->start_time;
  93. $sql="SELECT question_id, question_order FROM $TBL_EXERCICE_QUESTION,$TBL_QUESTIONS WHERE question_id=id AND exercice_id='".Database::escape_string($id)."' ORDER BY question_order";
  94. $result=api_sql_query($sql,__FILE__,__LINE__);
  95. // fills the array with the question ID for this exercise
  96. // the key of the array is the question position
  97. while($object=Database::fetch_object($result))
  98. {
  99. // makes sure that the question position is unique
  100. while(isset($this->questionList[$object->question_order]))
  101. {
  102. $object->question_order++;
  103. }
  104. $this->questionList[$object->question_order]=$object->question_id;
  105. }
  106. //var_dump($this->end_time,$object->start_time);
  107. if($this->random > 0){
  108. $this->questionList = $this->selectRandomList();
  109. }
  110. //overload questions list with recorded questions list
  111. //load questions only for exercises of type 'one question per page'
  112. //this is needed only is there is no questions
  113. //
  114. if($this->type == 2 && $_configuration['live_exercise_tracking']==true && $_SERVER['REQUEST_METHOD']!='POST' && defined('QUESTION_LIST_ALREADY_LOGGED'))
  115. {
  116. //if(empty($_SESSION['questionList']))
  117. $this->questionList = $questionList;
  118. }
  119. return true;
  120. }
  121. // exercise not found
  122. return false;
  123. }
  124. /**
  125. * returns the exercise ID
  126. *
  127. * @author - Olivier Brouckaert
  128. * @return - integer - exercise ID
  129. */
  130. function selectId()
  131. {
  132. return $this->id;
  133. }
  134. /**
  135. * returns the exercise title
  136. *
  137. * @author - Olivier Brouckaert
  138. * @return - string - exercise title
  139. */
  140. function selectTitle()
  141. {
  142. return $this->exercise;
  143. }
  144. /**
  145. * returns the number of attempts setted
  146. *
  147. * @return - numeric - exercise attempts
  148. */
  149. function selectAttempts()
  150. {
  151. return $this->attempts;
  152. }
  153. /** returns the number of FeedbackType *
  154. * 0=>Feedback , 1=>DirectFeedback, 2=>NoFeedback
  155. * @return - numeric - exercise attempts
  156. */
  157. function selectFeedbackType()
  158. {
  159. return $this->feedbacktype;
  160. }
  161. /**
  162. * returns the time limit
  163. */
  164. function selectTimeLimit()
  165. {
  166. return $this->timeLimit;
  167. }
  168. /**
  169. * returns the exercise description
  170. *
  171. * @author - Olivier Brouckaert
  172. * @return - string - exercise description
  173. */
  174. function selectDescription()
  175. {
  176. return $this->description;
  177. }
  178. /**
  179. * returns the exercise sound file
  180. *
  181. * @author - Olivier Brouckaert
  182. * @return - string - exercise description
  183. */
  184. function selectSound()
  185. {
  186. return $this->sound;
  187. }
  188. /**
  189. * returns the exercise type
  190. *
  191. * @author - Olivier Brouckaert
  192. * @return - integer - exercise type
  193. */
  194. function selectType()
  195. {
  196. return $this->type;
  197. }
  198. /**
  199. * tells if questions are selected randomly, and if so returns the draws
  200. *
  201. * @author - Carlos Vargas
  202. * @return - integer - results disabled exercise
  203. */
  204. function selectResultsDisabled()
  205. {
  206. return $this->results_disabled;
  207. }
  208. /**
  209. * tells if questions are selected randomly, and if so returns the draws
  210. *
  211. * @author - Olivier Brouckaert
  212. * @return - integer - 0 if not random, otherwise the draws
  213. */
  214. function isRandom()
  215. {
  216. if($this->random > 0){
  217. return true;
  218. }
  219. else{
  220. return false;
  221. }
  222. }
  223. /**
  224. * Same as isRandom() but has a name applied to values different than 0 or 1
  225. */
  226. function getShuffle()
  227. {
  228. return $this->random;
  229. }
  230. /**
  231. * returns the exercise status (1 = enabled ; 0 = disabled)
  232. *
  233. * @author - Olivier Brouckaert
  234. * @return - boolean - true if enabled, otherwise false
  235. */
  236. function selectStatus()
  237. {
  238. return $this->active;
  239. }
  240. /**
  241. * returns the array with the question ID list
  242. *
  243. * @author - Olivier Brouckaert
  244. * @return - array - question ID list
  245. */
  246. function selectQuestionList()
  247. {
  248. return $this->questionList;
  249. }
  250. /**
  251. * returns the number of questions in this exercise
  252. *
  253. * @author - Olivier Brouckaert
  254. * @return - integer - number of questions
  255. */
  256. function selectNbrQuestions()
  257. {
  258. return sizeof($this->questionList);
  259. }
  260. /**
  261. * selects questions randomly in the question list
  262. *
  263. * @author - Olivier Brouckaert
  264. * @return - array - if the exercise is not set to take questions randomly, returns the question list
  265. * without randomizing, otherwise, returns the list with questions selected randomly
  266. */
  267. function selectRandomList()
  268. {
  269. $nbQuestions = $this->selectNbrQuestions();
  270. $temp_list = $this->questionList;
  271. //error_log(print_r($temp_list,true));
  272. //error_log(count($temp_list));
  273. if (count($temp_list)<>0) {
  274. shuffle($temp_list);
  275. return array_combine(range(1,$nbQuestions),$temp_list);
  276. }
  277. $nbQuestions = $this->selectNbrQuestions();
  278. //Not a random exercise, or if there are not at least 2 questions
  279. if($this->random == 0 || $nbQuestions < 2)
  280. {
  281. return $this->questionList;
  282. }
  283. $randQuestionList = array();
  284. $alreadyChosen = array();
  285. for($i=0; $i < $this->random; $i++)
  286. {
  287. if($i < $nbQuestions){
  288. do
  289. {
  290. $rand=rand(1,$nbQuestions);
  291. }
  292. while(in_array($rand,$alreadyChosen));
  293. $alreadyChosen[]=$rand;
  294. $randQuestionList[$rand] = $this->questionList[$rand];
  295. }
  296. }
  297. return $randQuestionList;
  298. }
  299. /**
  300. * returns 'true' if the question ID is in the question list
  301. *
  302. * @author - Olivier Brouckaert
  303. * @param - integer $questionId - question ID
  304. * @return - boolean - true if in the list, otherwise false
  305. */
  306. function isInList($questionId)
  307. {
  308. if (is_array($this->questionList))
  309. return in_array($questionId,$this->questionList);
  310. else
  311. return false;
  312. }
  313. /**
  314. * changes the exercise title
  315. *
  316. * @author - Olivier Brouckaert
  317. * @param - string $title - exercise title
  318. */
  319. function updateTitle($title)
  320. {
  321. $this->exercise=$title;
  322. }
  323. /**
  324. * changes the exercise max attempts
  325. *
  326. * @param - numeric $attempts - exercise max attempts
  327. */
  328. function updateAttempts($attempts)
  329. {
  330. $this->attempts=$attempts;
  331. }
  332. /**
  333. * changes the exercise feedback type
  334. *
  335. * @param - numeric $attempts - exercise max attempts
  336. */
  337. function updateFeedbackType($feedback_type)
  338. {
  339. $this->feedbacktype=$feedback_type;
  340. }
  341. /**
  342. * changes the exercise description
  343. *
  344. * @author - Olivier Brouckaert
  345. * @param - string $description - exercise description
  346. */
  347. function updateDescription($description)
  348. {
  349. $this->description=$description;
  350. }
  351. /**
  352. * changes the exercise sound file
  353. *
  354. * @author - Olivier Brouckaert
  355. * @param - string $sound - exercise sound file
  356. * @param - string $delete - ask to delete the file
  357. */
  358. function updateSound($sound,$delete)
  359. {
  360. global $audioPath, $documentPath,$_course, $_user;
  361. $TBL_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  362. $TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  363. if($sound['size'] && (strstr($sound['type'],'audio') || strstr($sound['type'],'video')))
  364. {
  365. $this->sound=$sound['name'];
  366. if(@move_uploaded_file($sound['tmp_name'],$audioPath.'/'.$this->sound))
  367. {
  368. $query="SELECT 1 FROM $TBL_DOCUMENT "
  369. ." WHERE path='".str_replace($documentPath,'',$audioPath).'/'.$this->sound."'";
  370. $result=api_sql_query($query,__FILE__,__LINE__);
  371. if(!mysql_num_rows($result))
  372. {
  373. /*$query="INSERT INTO $TBL_DOCUMENT(path,filetype) VALUES "
  374. ." ('".str_replace($documentPath,'',$audioPath).'/'.$this->sound."','file')";
  375. api_sql_query($query,__FILE__,__LINE__);*/
  376. $id = add_document($_course,str_replace($documentPath,'',$audioPath).'/'.$this->sound,'file',$sound['size'],$sound['name']);
  377. //$id = Database::get_last_insert_id();
  378. //$time = time();
  379. //$time = date("Y-m-d H:i:s", $time);
  380. // insert into the item_property table, using default visibility of "visible"
  381. /*$query = "INSERT INTO $TBL_ITEM_PROPERTY "
  382. ."(tool, ref, insert_user_id,to_group_id, insert_date, lastedit_date, lastedit_type) "
  383. ." VALUES "
  384. ."('".TOOL_DOCUMENT."', $id, $_user['user_id'], 0, '$time', '$time', 'DocumentAdded' )";
  385. api_sql_query($query,__FILE__,__LINE__);*/
  386. api_item_property_update($_course, TOOL_DOCUMENT, $id, 'DocumentAdded',$_user['user_id']);
  387. item_property_update_on_folder($_course,str_replace($documentPath,'',$audioPath),$_user['user_id']);
  388. }
  389. }
  390. }
  391. elseif($delete && is_file($audioPath.'/'.$this->sound))
  392. {
  393. $this->sound='';
  394. }
  395. }
  396. /**
  397. * changes the exercise type
  398. *
  399. * @author - Olivier Brouckaert
  400. * @param - integer $type - exercise type
  401. */
  402. function updateType($type)
  403. {
  404. $this->type=$type;
  405. }
  406. /**
  407. * sets to 0 if questions are not selected randomly
  408. * if questions are selected randomly, sets the draws
  409. *
  410. * @author - Olivier Brouckaert
  411. * @param - integer $random - 0 if not random, otherwise the draws
  412. */
  413. function setRandom($random)
  414. {
  415. $this->random=$random;
  416. }
  417. /**
  418. * enables the exercise
  419. *
  420. * @author - Olivier Brouckaert
  421. */
  422. function enable()
  423. {
  424. $this->active=1;
  425. }
  426. /**
  427. * disables the exercise
  428. *
  429. * @author - Olivier Brouckaert
  430. */
  431. function disable()
  432. {
  433. $this->active=0;
  434. }
  435. function disable_results()
  436. {
  437. $this->results_disabled = true;
  438. }
  439. function enable_results()
  440. {
  441. $this->results_disabled = false;
  442. }
  443. function updateResultsDisabled($results_disabled)
  444. {
  445. if ($results_disabled==1){
  446. $this->results_disabled = true;
  447. } else {
  448. $this->results_disabled = false;
  449. }
  450. }
  451. /**
  452. * updates the exercise in the data base
  453. *
  454. * @author - Olivier Brouckaert
  455. */
  456. function save($type_e='')
  457. {
  458. global $_course,$_user;
  459. $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
  460. $TBL_QUESTIONS = Database::get_course_table(TABLE_QUIZ_QUESTION);
  461. $TBL_QUIZ_QUESTION= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
  462. $id=$this->id;
  463. $exercise=$this->exercise;
  464. $description=$this->description;
  465. $sound=$this->sound;
  466. $type=$this->type;
  467. $attempts=$this->attempts;
  468. $feedbacktype=$this->feedbacktype;
  469. $random=$this->random;
  470. $active=$this->active;
  471. if ($feedbacktype==1){
  472. $results_disabled = 1;
  473. } else {
  474. $results_disabled = intval($this->results_disabled);
  475. }
  476. $start_time = Database::escape_string($this->start_time);
  477. $end_time = Database::escape_string($this->end_time);
  478. // exercise already exists
  479. if($id) {
  480. /*
  481. title='".Database::escape_string(Security::remove_XSS($exercise))."',
  482. description='".Database::escape_string(Security::remove_XSS(api_html_entity_decode($description),COURSEMANAGERLOWSECURITY))."'";
  483. */
  484. $sql="UPDATE $TBL_EXERCICES SET
  485. title='".Database::escape_string($exercise)."',
  486. description='".Database::escape_string($description)."'";
  487. if ($type_e != 'simple') {
  488. $sql .= ", sound='".Database::escape_string($sound)."',
  489. type='".Database::escape_string($type)."',
  490. random='".Database::escape_string($random)."',
  491. active='".Database::escape_string($active)."',
  492. feedback_type='".Database::escape_string($feedbacktype)."',
  493. start_time='$start_time',end_time='$end_time',
  494. max_attempt='".Database::escape_string($attempts)."', " .
  495. "results_disabled='".Database::escape_string($results_disabled)."'";
  496. }
  497. $sql .= " WHERE id='".Database::escape_string($id)."'";
  498. // echo $sql;
  499. api_sql_query($sql,__FILE__,__LINE__);
  500. // update into the item_property table
  501. api_item_property_update($_course, TOOL_QUIZ, $id,'QuizUpdated',$_user['user_id']);
  502. if (api_get_setting('search_enabled')=='true') {
  503. $this -> search_engine_edit();
  504. }
  505. } else {// creates a new exercise
  506. //add condition by anonymous user
  507. /*if (!api_is_anonymous()) {
  508. //is course manager
  509. $cond1=Database::escape_string($exercise);
  510. $cond2=Database::escape_string($description);
  511. } else {
  512. //is anonymous user
  513. $cond1=Database::escape_string(Security::remove_XSS($exercise));
  514. $cond2=Database::escape_string(Security::remove_XSS(api_html_entity_decode($description),COURSEMANAGERLOWSECURITY));
  515. }*/
  516. $sql="INSERT INTO $TBL_EXERCICES(start_time,end_time,title,description,sound,type,random,active, results_disabled, max_attempt,feedback_type)
  517. VALUES(
  518. '$start_time','$end_time',
  519. '".Database::escape_string($exercise)."',
  520. '".Database::escape_string($description)."',
  521. '".Database::escape_string($sound)."',
  522. '".Database::escape_string($type)."',
  523. '".Database::escape_string($random)."',
  524. '".Database::escape_string($active)."',
  525. '".Database::escape_string($results_disabled)."',
  526. '".Database::escape_string($attempts)."',
  527. '".Database::escape_string($feedbacktype)."'
  528. )";
  529. api_sql_query($sql,__FILE__,__LINE__);
  530. $this->id=Database::insert_id();
  531. // insert into the item_property table
  532. api_item_property_update($_course, TOOL_QUIZ, $this->id,'QuizAdded',$_user['user_id']);
  533. if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian')) {
  534. $this -> search_engine_save();
  535. }
  536. }
  537. // updates the question position
  538. $this->update_question_positions();
  539. }
  540. function update_question_positions() {
  541. // updates the question position
  542. $TBL_QUIZ_QUESTION= Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
  543. foreach($this->questionList as $position=>$questionId)
  544. {
  545. //$sql="UPDATE $TBL_QUESTIONS SET position='".Database::escape_string($position)."' WHERE id='".Database::escape_string($questionId)."'";
  546. $sql="UPDATE $TBL_QUIZ_QUESTION SET question_order='".Database::escape_string($position)."' " .
  547. "WHERE question_id='".Database::escape_string($questionId)."' and exercice_id=".Database::escape_string($this->id)."";
  548. api_sql_query($sql,__FILE__,__LINE__);
  549. }
  550. }
  551. /**
  552. * moves a question up in the list
  553. *
  554. * @author - Olivier Brouckaert
  555. * @author - Julio Montoya (rewrote the code)
  556. * @param - integer $id - question ID to move up
  557. */
  558. function moveUp($id)
  559. {
  560. // there is a bug with some version of PHP with the key and prev functions
  561. // the script commented was tested in dev.dokeos.com with no success
  562. // Instead of using prev and next this was change with arrays.
  563. /*
  564. foreach($this->questionList as $position=>$questionId)
  565. {
  566. // if question ID found
  567. if($questionId == $id)
  568. {
  569. // position of question in the array
  570. echo $pos1=$position; //1
  571. echo "<br>";
  572. prev($this->questionList);
  573. prev($this->questionList);
  574. // position of previous question in the array
  575. $pos2=key($this->questionList);
  576. //if the cursor of the array hit the end
  577. // then we must reset the array to get the previous key
  578. if($pos2===null)
  579. {
  580. end($this->questionList);
  581. prev($this->questionList);
  582. $pos2=key($this->questionList);
  583. }
  584. // error, can't move question
  585. if(!$pos2)
  586. {
  587. //echo 'cant move!';
  588. $pos2=key($this->questionList);
  589. reset($this->questionList);
  590. }
  591. $id2=$this->questionList[$pos2];
  592. // exits foreach()
  593. break;
  594. }
  595. $i++;
  596. }
  597. */
  598. $question_list =array();
  599. foreach($this->questionList as $position=>$questionId)
  600. {
  601. $question_list[]= $questionId;
  602. }
  603. $len=count($question_list);
  604. $orderlist=array_keys($this->questionList);
  605. for($i=0;$i<$len;$i++)
  606. {
  607. $questionId = $question_list[$i];
  608. if($questionId == $id)
  609. {
  610. // position of question in the array
  611. $pos1=$orderlist[$i];
  612. $pos2=$orderlist[$i-1];
  613. if($pos2===null)
  614. {
  615. $pos2 = $orderlist[$len-1];
  616. }
  617. // error, can't move question
  618. if(!$pos2)
  619. {
  620. $pos2=$orderlist[0];
  621. $i=0;
  622. }
  623. break;
  624. }
  625. }
  626. // permutes questions in the array
  627. $temp=$this->questionList[$pos2];
  628. $this->questionList[$pos2]=$this->questionList[$pos1];
  629. $this->questionList[$pos1]=$temp;
  630. }
  631. /**
  632. * moves a question down in the list
  633. *
  634. * @author - Olivier Brouckaert
  635. * @param - integer $id - question ID to move down
  636. */
  637. function moveDown($id)
  638. {
  639. // there is a bug with some version of PHP with the key and prev functions
  640. // the script commented was tested in dev.dokeos.com with no success
  641. // Instead of using prev and next this was change with arrays.
  642. /*
  643. foreach($this->questionList as $position=>$questionId)
  644. {
  645. // if question ID found
  646. if($questionId == $id)
  647. {
  648. // position of question in the array
  649. $pos1=$position;
  650. //next($this->questionList);
  651. // position of next question in the array
  652. $pos2=key($this->questionList);
  653. // error, can't move question
  654. if(!$pos2)
  655. {
  656. //echo 'cant move!';
  657. return;
  658. }
  659. $id2=$this->questionList[$pos2];
  660. // exits foreach()
  661. break;
  662. }
  663. }
  664. */
  665. $question_list =array();
  666. foreach($this->questionList as $position=>$questionId)
  667. {
  668. $question_list[]= $questionId;
  669. }
  670. $len=count($question_list);
  671. $orderlist=array_keys($this->questionList);
  672. for($i=0;$i<$len;$i++)
  673. {
  674. $questionId = $question_list[$i];
  675. if($questionId == $id)
  676. {
  677. $pos1=$orderlist[$i+1];
  678. $pos2 =$orderlist[$i];
  679. if(!$pos2)
  680. {
  681. //echo 'cant move!';
  682. }
  683. break;
  684. }
  685. }
  686. // permutes questions in the array
  687. $temp=$this->questionList[$pos2];
  688. $this->questionList[$pos2]=$this->questionList[$pos1];
  689. $this->questionList[$pos1]=$temp;
  690. }
  691. /**
  692. * adds a question into the question list
  693. *
  694. * @author - Olivier Brouckaert
  695. * @param - integer $questionId - question ID
  696. * @return - boolean - true if the question has been added, otherwise false
  697. */
  698. function addToList($questionId)
  699. {
  700. // checks if the question ID is not in the list
  701. if(!$this->isInList($questionId))
  702. {
  703. // selects the max position
  704. if(!$this->selectNbrQuestions())
  705. {
  706. $pos=1;
  707. }
  708. else
  709. {
  710. if (is_array($this->questionList))
  711. $pos=max(array_keys($this->questionList))+1;
  712. }
  713. $this->questionList[$pos]=$questionId;
  714. return true;
  715. }
  716. return false;
  717. }
  718. /**
  719. * removes a question from the question list
  720. *
  721. * @author - Olivier Brouckaert
  722. * @param - integer $questionId - question ID
  723. * @return - boolean - true if the question has been removed, otherwise false
  724. */
  725. function removeFromList($questionId)
  726. {
  727. // searches the position of the question ID in the list
  728. $pos=array_search($questionId,$this->questionList);
  729. // question not found
  730. if($pos === false)
  731. {
  732. return false;
  733. }
  734. else
  735. {
  736. // deletes the position from the array containing the wanted question ID
  737. unset($this->questionList[$pos]);
  738. return true;
  739. }
  740. }
  741. /**
  742. * deletes the exercise from the database
  743. * Notice : leaves the question in the data base
  744. *
  745. * @author - Olivier Brouckaert
  746. */
  747. function delete(){
  748. global $_course,$_user;
  749. $TBL_EXERCICES = Database::get_course_table(TABLE_QUIZ_TEST);
  750. $sql="UPDATE $TBL_EXERCICES SET active='-1' WHERE id='".Database::escape_string($this->id)."'";
  751. api_sql_query($sql);
  752. api_item_property_update($_course, TOOL_QUIZ, $this->id,'QuizDeleted',$_user['user_id']);
  753. if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian') ) {
  754. $this -> search_engine_delete();
  755. }
  756. }
  757. /**
  758. * Creates the form to create / edit an exercise
  759. * @param FormValidator $form the formvalidator instance (by reference)
  760. */
  761. function createForm ($form, $type='full')
  762. {
  763. global $id;
  764. if(empty($type)){
  765. $type='full';
  766. }
  767. // form title
  768. if (!empty($_GET['exerciseId'])) {
  769. $form_title = get_lang('ModifyExercise');
  770. } else {
  771. $form_title = get_lang('NewEx');
  772. }
  773. $form->addElement('header', '', $form_title);
  774. // title
  775. $form -> addElement('text', 'exerciseTitle', get_lang('ExerciseName'),'class="input_titles"');
  776. //$form->applyFilter('exerciseTitle','html_filter');
  777. $form -> addElement('html','<div class="row">
  778. <div class="label"></div>
  779. <div class="formw" style="height:50px">
  780. <a href="javascript://" onclick=" return show_media()"> <span id="media_icon"> <img src="../img/looknfeel.png" alt="" />&nbsp;'.get_lang('ExerciseDescription').'</span></a>
  781. </div>
  782. </div>');
  783. $form -> addElement ('html','<div id="media" style="display:none;">');
  784. $form -> addElement ('html_editor', 'exerciseDescription', null, null, array('ToolbarSet' => 'TestDescription', 'Width' => '100%', 'Height' => '200'));
  785. $form -> addElement ('html','</div>');
  786. $form -> addElement('html','<div class="row">
  787. <div class="label">&nbsp;</div>
  788. <div class="formw">
  789. <a href="javascript://" onclick=" return advanced_parameters()"><span id="img_plus_and_minus"><div style="vertical-align:top" ><img src="../img/div_show.gif" alt="" />&nbsp;'.get_lang('AdvancedParameters').'</div></span></a>
  790. </div>
  791. </div>');
  792. // Random questions
  793. $form -> addElement('html','<div id="options" style="display:none">');
  794. if($type=='full') {
  795. // feedback type
  796. $radios_feedback = array();
  797. $radios_feedback[] = FormValidator :: createElement ('radio', 'exerciseFeedbackType', null, get_lang('ExerciseAtTheEndOfTheTest'),'0');
  798. $radios_feedback[] = FormValidator :: createElement ('radio', 'exerciseFeedbackType', null, get_lang('NoFeedback'),'2');
  799. $form -> addGroup($radios_feedback, null, get_lang('FeedbackType'));
  800. $feedback_option[0]=get_lang('ExerciseAtTheEndOfTheTest');
  801. $feedback_option[1]=get_lang('DirectFeedback');
  802. $feedback_option[2]=get_lang('NoFeedback');
  803. //Can't modify a DirectFeedback question
  804. if ($this->selectFeedbackType() != 1 ) {
  805. // $form -> addElement('select', 'exerciseFeedbackType',get_lang('FeedbackType'),$feedback_option,'onchange="javascript:feedbackselection()"');
  806. // test type
  807. $radios = array();
  808. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('QuestionsPerPageOne'),'2');
  809. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('QuestionsPerPageAll'),'1');
  810. $form -> addGroup($radios, null, get_lang('QuestionsPerPage'));
  811. } else {
  812. // if is Directfeedback but has not questions we can allow to modify the question type
  813. if ($this->selectNbrQuestions()== 0) {
  814. $form -> addElement('select', 'exerciseFeedbackType',get_lang('FeedbackType'),$feedback_option,'onchange="javascript:feedbackselection()"');
  815. // test type
  816. $radios = array();
  817. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('SimpleExercise'),'1');
  818. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('SequentialExercise'),'2');
  819. $form -> addGroup($radios, null, get_lang('ExerciseType'));
  820. } else {
  821. //we force the options to the DirectFeedback exercisetype
  822. $form -> addElement('hidden', 'exerciseFeedbackType','1');
  823. $form -> addElement('hidden', 'exerciseType','2');
  824. }
  825. }
  826. $radios_results_disabled = array();
  827. $radios_results_disabled[] = FormValidator :: createElement ('radio', 'results_disabled', null, get_lang('Yes'),'0');
  828. $radios_results_disabled[] = FormValidator :: createElement ('radio', 'results_disabled', null, get_lang('No'),'1');
  829. $form -> addGroup($radios_results_disabled, null, get_lang('ShowResultsToStudents'));
  830. $random = array();
  831. $option=array();
  832. $max = ($this->id > 0) ? $this->selectNbrQuestions() : 10 ;
  833. $option = range(0,$max);
  834. $option[0]=get_lang('No');
  835. $random[] = FormValidator :: createElement ('select', 'randomQuestions',null,$option);
  836. $random[] = FormValidator :: createElement ('static', 'help','help','<span style="font-style: italic;">'.get_lang('RandomQuestionsHelp').'</span>');
  837. //$random[] = FormValidator :: createElement ('text', 'randomQuestions', null,null,'0');
  838. $form -> addGroup($random,null,get_lang('RandomQuestions'),'<br />');
  839. $attempt_option=range(0,10);
  840. $attempt_option[0]=get_lang('Infinite');
  841. $form -> addElement('select', 'exerciseAttempts',get_lang('ExerciseAttempts'),$attempt_option);
  842. $form -> addElement('checkbox', 'enabletimelimit',get_lang('EnableTimeLimits'),null,'onclick = " return timelimit() "');
  843. $var= Exercise::selectTimeLimit();
  844. $form -> addElement('html','</div>');
  845. if(($this -> start_time!='0000-00-00 00:00:00')||($this -> end_time!='0000-00-00 00:00:00'))
  846. $form -> addElement('html','<div id="options2" style="display:block;">');
  847. else
  848. $form -> addElement('html','<div id="options2" style="display:none;">');
  849. //$form -> addElement('date', 'start_time', get_lang('ExeStartTime'), array('language'=>'es','format' => 'dMYHi'));
  850. //$form -> addElement('date', 'end_time', get_lang('ExeEndTime'), array('language'=>'es','format' => 'dMYHi'));
  851. $form->addElement('datepicker', 'start_time', get_lang('ExeStartTime'), array('form_name'=>'exercise_admin'));
  852. $form->addElement('datepicker', 'end_time', get_lang('ExeEndTime'), array('form_name'=>'exercise_admin'));
  853. //$form -> addElement('text', 'exerciseAttempts', get_lang('ExerciseAttempts').' : ',array('size'=>'2'));
  854. $form -> addElement('html','</div>');
  855. $defaults = array();
  856. if (api_get_setting('search_enabled') === 'true') {
  857. require_once(api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php');
  858. $form -> addElement ('checkbox', 'index_document','', get_lang('SearchFeatureDoIndexDocument'));
  859. $form -> addElement ('html','<br /><div class="row">');
  860. $form -> addElement ('html', '<div class="label">'. get_lang('SearchFeatureDocumentLanguage') .'</div>');
  861. $form -> addElement ('html', '<div class="formw">'. api_get_languages_combo() .'</div>');
  862. $form -> addElement ('html','</div><div class="sub-form">');
  863. $specific_fields = get_specific_field_list();
  864. foreach ($specific_fields as $specific_field) {
  865. $form -> addElement ('text', $specific_field['code'], $specific_field['name']);
  866. $filter = array('course_code'=> "'". api_get_course_id() ."'", 'field_id' => $specific_field['id'], 'ref_id' => $this->id, 'tool_id' => '\''. TOOL_QUIZ .'\'');
  867. $values = get_specific_field_values_list($filter, array('value'));
  868. if ( !empty($values) ) {
  869. $arr_str_values = array();
  870. foreach ($values as $value) {
  871. $arr_str_values[] = $value['value'];
  872. }
  873. $defaults[$specific_field['code']] = implode(', ', $arr_str_values);
  874. }
  875. }
  876. $form -> addElement ('html','</div>');
  877. }
  878. }
  879. // submit
  880. isset($_GET['exerciseId'])?$text=get_lang('ModifyExercise'):$text=get_lang('ProcedToQuestions');
  881. $form -> addElement('html', '<br /><br />');
  882. $form -> addElement('style_submit_button', 'submitExercise', $text, 'class="save"');
  883. $form -> addRule ('exerciseTitle', get_lang('GiveExerciseName'), 'required');
  884. if($type=='full') {
  885. // rules
  886. $form -> addRule ('exerciseAttempts', get_lang('Numeric'), 'numeric');
  887. $form -> addRule ('start_time', get_lang('InvalidDate'), 'date');
  888. $form -> addRule ('end_time', get_lang('InvalidDate'), 'date');
  889. $form -> addRule(array ('start_time', 'end_time'), get_lang('StartDateShouldBeBeforeEndDate'), 'date_compare', 'lte');
  890. }
  891. // defaults
  892. if($type=='full') {
  893. if($this -> id > 0) {
  894. if ($this -> random > $this->selectNbrQuestions()) {
  895. $defaults['randomQuestions'] = $this->selectNbrQuestions();
  896. } else {
  897. $defaults['randomQuestions'] = $this -> random;
  898. }
  899. $defaults['exerciseType'] = $this -> selectType();
  900. $defaults['exerciseTitle'] = $this -> selectTitle();
  901. $defaults['exerciseDescription'] = $this -> selectDescription();
  902. $defaults['exerciseAttempts'] = $this->selectAttempts();
  903. $defaults['exerciseFeedbackType'] = $this->selectFeedbackType();
  904. $defaults['results_disabled'] = $this->selectResultsDisabled();
  905. if(($this -> start_time!='0000-00-00 00:00:00')||($this -> end_time!='0000-00-00 00:00:00'))
  906. $defaults['enabletimelimit'] = 1;
  907. $defaults['start_time'] = ($this->start_time!='0000-00-00 00:00:00')? $this -> start_time : date('Y-m-d 12:00:00');
  908. $defaults['end_time'] = ($this->end_time!='0000-00-00 00:00:00')?$this -> end_time : date('Y-m-d 12:00:00',time()+84600);
  909. } else {
  910. $defaults['exerciseType'] = 2;
  911. $defaults['exerciseAttempts'] = 0;
  912. $defaults['randomQuestions'] = 0;
  913. $defaults['exerciseDescription'] = '';
  914. $defaults['exerciseFeedbackType'] = 0;
  915. $defaults['results_disabled'] = 0;
  916. $defaults['start_time'] = date('Y-m-d 12:00:00');
  917. $defaults['end_time'] = date('Y-m-d 12:00:00',time()+84600);
  918. }
  919. } else {
  920. $defaults['exerciseTitle'] = $this -> selectTitle();
  921. $defaults['exerciseDescription'] = $this -> selectDescription();
  922. }
  923. if (api_get_setting('search_enabled') === 'true') {
  924. $defaults['index_document'] = 'checked="checked"';
  925. }
  926. $form -> setDefaults($defaults);
  927. }
  928. /**
  929. * function which process the creation of exercises
  930. * @param FormValidator $form the formvalidator instance
  931. */
  932. function processCreation($form,$type='')
  933. {
  934. $this -> updateTitle($form -> getSubmitValue('exerciseTitle'));
  935. $this -> updateDescription($form -> getSubmitValue('exerciseDescription'));
  936. $this -> updateAttempts($form -> getSubmitValue('exerciseAttempts'));
  937. $this -> updateFeedbackType($form -> getSubmitValue('exerciseFeedbackType'));
  938. $this -> updateType($form -> getSubmitValue('exerciseType'));
  939. $this -> setRandom($form -> getSubmitValue('randomQuestions'));
  940. $this -> updateResultsDisabled($form -> getSubmitValue('results_disabled'));
  941. if($form -> getSubmitValue('enabletimelimit')==1)
  942. {
  943. $start_time = $form -> getSubmitValue('start_time');
  944. $this->start_time = $start_time['Y'].'-'.$start_time['F'].'-'.$start_time['d'].' '.$start_time['H'].':'.$start_time['i'].':00';
  945. $end_time = $form -> getSubmitValue('end_time');
  946. $this->end_time = $end_time['Y'].'-'.$end_time['F'].'-'.$end_time['d'].' '.$end_time['H'].':'.$end_time['i'].':00';
  947. }
  948. else
  949. {
  950. $this->start_time = '0000-00-00 00:00:00';
  951. $this->end_time = '0000-00-00 00:00:00';
  952. }
  953. //echo $end_time;exit;
  954. $this -> save($type);
  955. }
  956. function search_engine_save() {
  957. if ($_POST['index_document'] != 1) {
  958. return;
  959. }
  960. $course_id = api_get_course_id();
  961. require_once(api_get_path(LIBRARY_PATH) . 'search/DokeosIndexer.class.php');
  962. require_once(api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php');
  963. require_once(api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php');
  964. $specific_fields = get_specific_field_list();
  965. $ic_slide = new IndexableChunk();
  966. $all_specific_terms = '';
  967. foreach ($specific_fields as $specific_field) {
  968. if (isset($_REQUEST[$specific_field['code']])) {
  969. $sterms = trim($_REQUEST[$specific_field['code']]);
  970. if (!empty($sterms)) {
  971. $all_specific_terms .= ' '. $sterms;
  972. $sterms = explode(',', $sterms);
  973. foreach ($sterms as $sterm) {
  974. $ic_slide->addTerm(trim($sterm), $specific_field['code']);
  975. add_specific_field_value($specific_field['id'], $course_id, TOOL_QUIZ, $this->id, $sterm);
  976. }
  977. }
  978. }
  979. }
  980. // build the chunk to index
  981. $ic_slide->addValue("title", $this->exercise);
  982. $ic_slide->addCourseId($course_id);
  983. $ic_slide->addToolId(TOOL_QUIZ);
  984. $xapian_data = array(
  985. SE_COURSE_ID => $course_id,
  986. SE_TOOL_ID => TOOL_QUIZ,
  987. SE_DATA => array('type' => SE_DOCTYPE_EXERCISE_EXERCISE, 'exercise_id' => (int)$this->id),
  988. SE_USER => (int)api_get_user_id(),
  989. );
  990. $ic_slide->xapian_data = serialize($xapian_data);
  991. $exercise_description = $all_specific_terms .' '. $this->description;
  992. $ic_slide->addValue("content", $exercise_description);
  993. $di = new DokeosIndexer();
  994. isset($_POST['language'])? $lang=Database::escape_string($_POST['language']): $lang = 'english';
  995. $di->connectDb(NULL, NULL, $lang);
  996. $di->addChunk($ic_slide);
  997. //index and return search engine document id
  998. $did = $di->index();
  999. if ($did) {
  1000. // save it to db
  1001. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1002. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  1003. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  1004. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id, $did);
  1005. api_sql_query($sql,__FILE__,__LINE__);
  1006. }
  1007. }
  1008. function search_engine_edit() {
  1009. // update search enchine and its values table if enabled
  1010. if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian')) {
  1011. $course_id = api_get_course_id();
  1012. // actually, it consists on delete terms from db, insert new ones, create a new search engine document, and remove the old one
  1013. // get search_did
  1014. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1015. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  1016. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1017. $res = api_sql_query($sql, __FILE__, __LINE__);
  1018. if (Database::num_rows($res) > 0) {
  1019. require_once(api_get_path(LIBRARY_PATH) . 'search/DokeosIndexer.class.php');
  1020. require_once(api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php');
  1021. require_once(api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php');
  1022. $se_ref = Database::fetch_array($res);
  1023. $specific_fields = get_specific_field_list();
  1024. $ic_slide = new IndexableChunk();
  1025. $all_specific_terms = '';
  1026. foreach ($specific_fields as $specific_field) {
  1027. delete_all_specific_field_value($course_id, $specific_field['id'], TOOL_QUIZ, $this->id);
  1028. if (isset($_REQUEST[$specific_field['code']])) {
  1029. $sterms = trim($_REQUEST[$specific_field['code']]);
  1030. $all_specific_terms .= ' '. $sterms;
  1031. $sterms = explode(',', $sterms);
  1032. foreach ($sterms as $sterm) {
  1033. $ic_slide->addTerm(trim($sterm), $specific_field['code']);
  1034. add_specific_field_value($specific_field['id'], $course_id, TOOL_QUIZ, $this->id, $sterm);
  1035. }
  1036. }
  1037. }
  1038. // build the chunk to index
  1039. $ic_slide->addValue("title", $this->exercise);
  1040. $ic_slide->addCourseId($course_id);
  1041. $ic_slide->addToolId(TOOL_QUIZ);
  1042. $xapian_data = array(
  1043. SE_COURSE_ID => $course_id,
  1044. SE_TOOL_ID => TOOL_QUIZ,
  1045. SE_DATA => array('type' => SE_DOCTYPE_EXERCISE_EXERCISE, 'exercise_id' => (int)$this->id),
  1046. SE_USER => (int)api_get_user_id(),
  1047. );
  1048. $ic_slide->xapian_data = serialize($xapian_data);
  1049. $exercise_description = $all_specific_terms .' '. $this->description;
  1050. $ic_slide->addValue("content", $exercise_description);
  1051. $di = new DokeosIndexer();
  1052. isset($_POST['language'])? $lang=Database::escape_string($_POST['language']): $lang = 'english';
  1053. $di->connectDb(NULL, NULL, $lang);
  1054. $di->remove_document((int)$se_ref['search_did']);
  1055. $di->addChunk($ic_slide);
  1056. //index and return search engine document id
  1057. $did = $di->index();
  1058. if ($did) {
  1059. // save it to db
  1060. $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=\'%s\'';
  1061. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1062. api_sql_query($sql,__FILE__,__LINE__);
  1063. //var_dump($sql);
  1064. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  1065. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  1066. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id, $did);
  1067. api_sql_query($sql,__FILE__,__LINE__);
  1068. }
  1069. }
  1070. }
  1071. }
  1072. function search_engine_delete() {
  1073. // remove from search engine if enabled
  1074. if (api_get_setting('search_enabled') == 'true' && extension_loaded('xapian') ) {
  1075. $course_id = api_get_course_id();
  1076. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1077. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level IS NULL LIMIT 1';
  1078. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1079. $res = api_sql_query($sql, __FILE__, __LINE__);
  1080. if (Database::num_rows($res) > 0) {
  1081. $row = Database::fetch_array($res);
  1082. require_once(api_get_path(LIBRARY_PATH) .'search/DokeosIndexer.class.php');
  1083. $di = new DokeosIndexer();
  1084. $di->remove_document((int)$row['search_did']);
  1085. unset($di);
  1086. $tbl_quiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
  1087. foreach ( $this->questionList as $question_i) {
  1088. $sql = 'SELECT type FROM %s WHERE id=%s';
  1089. $sql = sprintf($sql, $tbl_quiz_question, $question_i);
  1090. $qres = api_sql_query($sql, __FILE__, __LINE__);
  1091. if (Database::num_rows($qres) > 0) {
  1092. $qrow = Database::fetch_array($qres);
  1093. $objQuestion = Question::getInstance($qrow['type']);
  1094. $objQuestion = Question::read((int)$question_i);
  1095. $objQuestion->search_engine_edit($this->id, FALSE, TRUE);
  1096. unset($objQuestion);
  1097. }
  1098. }
  1099. }
  1100. $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level IS NULL LIMIT 1';
  1101. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1102. api_sql_query($sql, __FILE__, __LINE__);
  1103. // remove terms from db
  1104. require_once(api_get_path(LIBRARY_PATH) .'specific_fields_manager.lib.php');
  1105. delete_all_values_for_item($course_id, TOOL_QUIZ, $this->id);
  1106. }
  1107. }
  1108. }
  1109. endif;
  1110. ?>