exercise.class.php 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  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 21662 2009-06-29 14:55:09Z iflorespaz $
  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. // fck editor
  778. global $fck_attribute;
  779. $fck_attribute = array();
  780. $fck_attribute['Width'] = '100%';
  781. $fck_attribute['Height'] = '200px';
  782. $fck_attribute['ToolbarSet'] = 'TestDescription';
  783. $form -> addElement('html','<div class="row">
  784. <div class="label"></div>
  785. <div class="formw" style="height:50px">
  786. <a href="javascript://" onclick=" return show_media()"> <span id="media_icon"> <img src="../img/looknfeel.png" alt="" />&nbsp;'.get_lang('ExerciseDescription').'</span></a>
  787. </div>
  788. </div>');
  789. $form -> addElement ('html','<div id="media" style="display:none;">');
  790. $form -> addElement ('html_editor', 'exerciseDescription');
  791. $form -> addElement ('html','</div>');
  792. $form -> addElement('html','<div class="row">
  793. <div class="label">&nbsp;</div>
  794. <div class="formw">
  795. <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>
  796. </div>
  797. </div>');
  798. // Random questions
  799. $form -> addElement('html','<div id="options" style="display:none">');
  800. if($type=='full') {
  801. // feedback type
  802. $radios_feedback = array();
  803. $radios_feedback[] = FormValidator :: createElement ('radio', 'exerciseFeedbackType', null, get_lang('ExerciseAtTheEndOfTheTest'),'0');
  804. $radios_feedback[] = FormValidator :: createElement ('radio', 'exerciseFeedbackType', null, get_lang('NoFeedback'),'2');
  805. $form -> addGroup($radios_feedback, null, get_lang('FeedbackType'));
  806. $feedback_option[0]=get_lang('ExerciseAtTheEndOfTheTest');
  807. $feedback_option[1]=get_lang('DirectFeedback');
  808. $feedback_option[2]=get_lang('NoFeedback');
  809. //Can't modify a DirectFeedback question
  810. if ($this->selectFeedbackType() != 1 ) {
  811. // $form -> addElement('select', 'exerciseFeedbackType',get_lang('FeedbackType'),$feedback_option,'onchange="javascript:feedbackselection()"');
  812. // test type
  813. $radios = array();
  814. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('QuestionsPerPageOne'),'2');
  815. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('QuestionsPerPageAll'),'1');
  816. $form -> addGroup($radios, null, get_lang('QuestionsPerPage'));
  817. } else {
  818. // if is Directfeedback but has not questions we can allow to modify the question type
  819. if ($this->selectNbrQuestions()== 0) {
  820. $form -> addElement('select', 'exerciseFeedbackType',get_lang('FeedbackType'),$feedback_option,'onchange="javascript:feedbackselection()"');
  821. // test type
  822. $radios = array();
  823. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('SimpleExercise'),'1');
  824. $radios[] = FormValidator :: createElement ('radio', 'exerciseType', null, get_lang('SequentialExercise'),'2');
  825. $form -> addGroup($radios, null, get_lang('ExerciseType'));
  826. } else {
  827. //we force the options to the DirectFeedback exercisetype
  828. $form -> addElement('hidden', 'exerciseFeedbackType','1');
  829. $form -> addElement('hidden', 'exerciseType','2');
  830. }
  831. }
  832. $radios_results_disabled = array();
  833. $radios_results_disabled[] = FormValidator :: createElement ('radio', 'results_disabled', null, get_lang('Yes'),'0');
  834. $radios_results_disabled[] = FormValidator :: createElement ('radio', 'results_disabled', null, get_lang('No'),'1');
  835. $form -> addGroup($radios_results_disabled, null, get_lang('ShowResultsToStudents'));
  836. $random = array();
  837. $option=array();
  838. $max = ($this->id > 0) ? $this->selectNbrQuestions() : 10 ;
  839. $option = range(0,$max);
  840. $option[0]=get_lang('No');
  841. $random[] = FormValidator :: createElement ('select', 'randomQuestions',null,$option);
  842. $random[] = FormValidator :: createElement ('static', 'help','help','<span style="font-style: italic;">'.get_lang('RandomQuestionsHelp').'</span>');
  843. //$random[] = FormValidator :: createElement ('text', 'randomQuestions', null,null,'0');
  844. $form -> addGroup($random,null,get_lang('RandomQuestions'),'<br />');
  845. $attempt_option=range(0,10);
  846. $attempt_option[0]=get_lang('Infinite');
  847. $form -> addElement('select', 'exerciseAttempts',get_lang('ExerciseAttempts'),$attempt_option);
  848. $form -> addElement('checkbox', 'enabletimelimit',get_lang('EnableTimeLimits'),null,'onclick = " return timelimit() "');
  849. $var= Exercise::selectTimeLimit();
  850. $form -> addElement('html','</div>');
  851. if(($this -> start_time!='0000-00-00 00:00:00')||($this -> end_time!='0000-00-00 00:00:00'))
  852. $form -> addElement('html','<div id="options2" style="display:block;">');
  853. else
  854. $form -> addElement('html','<div id="options2" style="display:none;">');
  855. //$form -> addElement('date', 'start_time', get_lang('ExeStartTime'), array('language'=>'es','format' => 'dMYHi'));
  856. //$form -> addElement('date', 'end_time', get_lang('ExeEndTime'), array('language'=>'es','format' => 'dMYHi'));
  857. $form->addElement('datepicker', 'start_time', get_lang('ExeStartTime'), array('form_name'=>'exercise_admin'));
  858. $form->addElement('datepicker', 'end_time', get_lang('ExeEndTime'), array('form_name'=>'exercise_admin'));
  859. //$form -> addElement('text', 'exerciseAttempts', get_lang('ExerciseAttempts').' : ',array('size'=>'2'));
  860. $form -> addElement('html','</div>');
  861. $defaults = array();
  862. if (api_get_setting('search_enabled') === 'true') {
  863. require_once(api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php');
  864. $form -> addElement ('checkbox', 'index_document','', get_lang('SearchFeatureDoIndexDocument'));
  865. $form -> addElement ('html','<br /><div class="row">');
  866. $form -> addElement ('html', '<div class="label">'. get_lang('SearchFeatureDocumentLanguage') .'</div>');
  867. $form -> addElement ('html', '<div class="formw">'. api_get_languages_combo() .'</div>');
  868. $form -> addElement ('html','</div><div class="sub-form">');
  869. $specific_fields = get_specific_field_list();
  870. foreach ($specific_fields as $specific_field) {
  871. $form -> addElement ('text', $specific_field['code'], $specific_field['name']);
  872. $filter = array('course_code'=> "'". api_get_course_id() ."'", 'field_id' => $specific_field['id'], 'ref_id' => $this->id, 'tool_id' => '\''. TOOL_QUIZ .'\'');
  873. $values = get_specific_field_values_list($filter, array('value'));
  874. if ( !empty($values) ) {
  875. $arr_str_values = array();
  876. foreach ($values as $value) {
  877. $arr_str_values[] = $value['value'];
  878. }
  879. $defaults[$specific_field['code']] = implode(', ', $arr_str_values);
  880. }
  881. }
  882. $form -> addElement ('html','</div>');
  883. }
  884. }
  885. // submit
  886. isset($_GET['exerciseId'])?$text=get_lang('ModifyExercise'):$text=get_lang('ProcedToQuestions');
  887. $form -> addElement('html', '<br /><br />');
  888. $form -> addElement('style_submit_button', 'submitExercise', $text, 'class="save"');
  889. $form -> addRule ('exerciseTitle', get_lang('GiveExerciseName'), 'required');
  890. if($type=='full') {
  891. // rules
  892. $form -> addRule ('exerciseAttempts', get_lang('Numeric'), 'numeric');
  893. $form -> addRule ('start_time', get_lang('InvalidDate'), 'date');
  894. $form -> addRule ('end_time', get_lang('InvalidDate'), 'date');
  895. $form -> addRule(array ('start_time', 'end_time'), get_lang('StartDateShouldBeBeforeEndDate'), 'date_compare', 'lte');
  896. }
  897. // defaults
  898. if($type=='full') {
  899. if($this -> id > 0) {
  900. if ($this -> random > $this->selectNbrQuestions()) {
  901. $defaults['randomQuestions'] = $this->selectNbrQuestions();
  902. } else {
  903. $defaults['randomQuestions'] = $this -> random;
  904. }
  905. $defaults['exerciseType'] = $this -> selectType();
  906. $defaults['exerciseTitle'] = $this -> selectTitle();
  907. $defaults['exerciseDescription'] = $this -> selectDescription();
  908. $defaults['exerciseAttempts'] = $this->selectAttempts();
  909. $defaults['exerciseFeedbackType'] = $this->selectFeedbackType();
  910. $defaults['results_disabled'] = $this->selectResultsDisabled();
  911. if(($this -> start_time!='0000-00-00 00:00:00')||($this -> end_time!='0000-00-00 00:00:00'))
  912. $defaults['enabletimelimit'] = 1;
  913. $defaults['start_time'] = ($this->start_time!='0000-00-00 00:00:00')? $this -> start_time : date('Y-m-d 12:00:00');
  914. $defaults['end_time'] = ($this->end_time!='0000-00-00 00:00:00')?$this -> end_time : date('Y-m-d 12:00:00',time()+84600);
  915. } else {
  916. $defaults['exerciseType'] = 2;
  917. $defaults['exerciseAttempts'] = 0;
  918. $defaults['randomQuestions'] = 0;
  919. $defaults['exerciseDescription'] = '';
  920. $defaults['exerciseFeedbackType'] = 0;
  921. $defaults['results_disabled'] = 0;
  922. $defaults['start_time'] = date('Y-m-d 12:00:00');
  923. $defaults['end_time'] = date('Y-m-d 12:00:00',time()+84600);
  924. }
  925. } else {
  926. $defaults['exerciseTitle'] = $this -> selectTitle();
  927. $defaults['exerciseDescription'] = $this -> selectDescription();
  928. }
  929. if (api_get_setting('search_enabled') === 'true') {
  930. $defaults['index_document'] = 'checked="checked"';
  931. }
  932. $form -> setDefaults($defaults);
  933. }
  934. /**
  935. * function which process the creation of exercises
  936. * @param FormValidator $form the formvalidator instance
  937. */
  938. function processCreation($form,$type='')
  939. {
  940. $this -> updateTitle($form -> getSubmitValue('exerciseTitle'));
  941. $this -> updateDescription($form -> getSubmitValue('exerciseDescription'));
  942. $this -> updateAttempts($form -> getSubmitValue('exerciseAttempts'));
  943. $this -> updateFeedbackType($form -> getSubmitValue('exerciseFeedbackType'));
  944. $this -> updateType($form -> getSubmitValue('exerciseType'));
  945. $this -> setRandom($form -> getSubmitValue('randomQuestions'));
  946. $this -> updateResultsDisabled($form -> getSubmitValue('results_disabled'));
  947. if($form -> getSubmitValue('enabletimelimit')==1)
  948. {
  949. $start_time = $form -> getSubmitValue('start_time');
  950. $this->start_time = $start_time['Y'].'-'.$start_time['F'].'-'.$start_time['d'].' '.$start_time['H'].':'.$start_time['i'].':00';
  951. $end_time = $form -> getSubmitValue('end_time');
  952. $this->end_time = $end_time['Y'].'-'.$end_time['F'].'-'.$end_time['d'].' '.$end_time['H'].':'.$end_time['i'].':00';
  953. }
  954. else
  955. {
  956. $this->start_time = '0000-00-00 00:00:00';
  957. $this->end_time = '0000-00-00 00:00:00';
  958. }
  959. //echo $end_time;exit;
  960. $this -> save($type);
  961. }
  962. function search_engine_save() {
  963. if ($_POST['index_document'] != 1) {
  964. return;
  965. }
  966. $course_id = api_get_course_id();
  967. require_once(api_get_path(LIBRARY_PATH) . 'search/DokeosIndexer.class.php');
  968. require_once(api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php');
  969. require_once(api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php');
  970. $specific_fields = get_specific_field_list();
  971. $ic_slide = new IndexableChunk();
  972. $all_specific_terms = '';
  973. foreach ($specific_fields as $specific_field) {
  974. if (isset($_REQUEST[$specific_field['code']])) {
  975. $sterms = trim($_REQUEST[$specific_field['code']]);
  976. if (!empty($sterms)) {
  977. $all_specific_terms .= ' '. $sterms;
  978. $sterms = explode(',', $sterms);
  979. foreach ($sterms as $sterm) {
  980. $ic_slide->addTerm(trim($sterm), $specific_field['code']);
  981. add_specific_field_value($specific_field['id'], $course_id, TOOL_QUIZ, $this->id, $sterm);
  982. }
  983. }
  984. }
  985. }
  986. // build the chunk to index
  987. $ic_slide->addValue("title", $this->exercise);
  988. $ic_slide->addCourseId($course_id);
  989. $ic_slide->addToolId(TOOL_QUIZ);
  990. $xapian_data = array(
  991. SE_COURSE_ID => $course_id,
  992. SE_TOOL_ID => TOOL_QUIZ,
  993. SE_DATA => array('type' => SE_DOCTYPE_EXERCISE_EXERCISE, 'exercise_id' => (int)$this->id),
  994. SE_USER => (int)api_get_user_id(),
  995. );
  996. $ic_slide->xapian_data = serialize($xapian_data);
  997. $exercise_description = $all_specific_terms .' '. $this->description;
  998. $ic_slide->addValue("content", $exercise_description);
  999. $di = new DokeosIndexer();
  1000. isset($_POST['language'])? $lang=Database::escape_string($_POST['language']): $lang = 'english';
  1001. $di->connectDb(NULL, NULL, $lang);
  1002. $di->addChunk($ic_slide);
  1003. //index and return search engine document id
  1004. $did = $di->index();
  1005. if ($did) {
  1006. // save it to db
  1007. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1008. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  1009. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  1010. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id, $did);
  1011. api_sql_query($sql,__FILE__,__LINE__);
  1012. }
  1013. }
  1014. function search_engine_edit() {
  1015. // update search enchine and its values table if enabled
  1016. if (api_get_setting('search_enabled')=='true' && extension_loaded('xapian')) {
  1017. $course_id = api_get_course_id();
  1018. // actually, it consists on delete terms from db, insert new ones, create a new search engine document, and remove the old one
  1019. // get search_did
  1020. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1021. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  1022. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1023. $res = api_sql_query($sql, __FILE__, __LINE__);
  1024. if (Database::num_rows($res) > 0) {
  1025. require_once(api_get_path(LIBRARY_PATH) . 'search/DokeosIndexer.class.php');
  1026. require_once(api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php');
  1027. require_once(api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php');
  1028. $se_ref = Database::fetch_array($res);
  1029. $specific_fields = get_specific_field_list();
  1030. $ic_slide = new IndexableChunk();
  1031. $all_specific_terms = '';
  1032. foreach ($specific_fields as $specific_field) {
  1033. delete_all_specific_field_value($course_id, $specific_field['id'], TOOL_QUIZ, $this->id);
  1034. if (isset($_REQUEST[$specific_field['code']])) {
  1035. $sterms = trim($_REQUEST[$specific_field['code']]);
  1036. $all_specific_terms .= ' '. $sterms;
  1037. $sterms = explode(',', $sterms);
  1038. foreach ($sterms as $sterm) {
  1039. $ic_slide->addTerm(trim($sterm), $specific_field['code']);
  1040. add_specific_field_value($specific_field['id'], $course_id, TOOL_QUIZ, $this->id, $sterm);
  1041. }
  1042. }
  1043. }
  1044. // build the chunk to index
  1045. $ic_slide->addValue("title", $this->exercise);
  1046. $ic_slide->addCourseId($course_id);
  1047. $ic_slide->addToolId(TOOL_QUIZ);
  1048. $xapian_data = array(
  1049. SE_COURSE_ID => $course_id,
  1050. SE_TOOL_ID => TOOL_QUIZ,
  1051. SE_DATA => array('type' => SE_DOCTYPE_EXERCISE_EXERCISE, 'exercise_id' => (int)$this->id),
  1052. SE_USER => (int)api_get_user_id(),
  1053. );
  1054. $ic_slide->xapian_data = serialize($xapian_data);
  1055. $exercise_description = $all_specific_terms .' '. $this->description;
  1056. $ic_slide->addValue("content", $exercise_description);
  1057. $di = new DokeosIndexer();
  1058. isset($_POST['language'])? $lang=Database::escape_string($_POST['language']): $lang = 'english';
  1059. $di->connectDb(NULL, NULL, $lang);
  1060. $di->remove_document((int)$se_ref['search_did']);
  1061. $di->addChunk($ic_slide);
  1062. //index and return search engine document id
  1063. $did = $di->index();
  1064. if ($did) {
  1065. // save it to db
  1066. $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=\'%s\'';
  1067. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1068. api_sql_query($sql,__FILE__,__LINE__);
  1069. //var_dump($sql);
  1070. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  1071. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  1072. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id, $did);
  1073. api_sql_query($sql,__FILE__,__LINE__);
  1074. }
  1075. }
  1076. }
  1077. }
  1078. function search_engine_delete() {
  1079. // remove from search engine if enabled
  1080. if (api_get_setting('search_enabled') == 'true' && extension_loaded('xapian') ) {
  1081. $course_id = api_get_course_id();
  1082. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1083. $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';
  1084. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1085. $res = api_sql_query($sql, __FILE__, __LINE__);
  1086. if (Database::num_rows($res) > 0) {
  1087. $row = Database::fetch_array($res);
  1088. require_once(api_get_path(LIBRARY_PATH) .'search/DokeosIndexer.class.php');
  1089. $di = new DokeosIndexer();
  1090. $di->remove_document((int)$row['search_did']);
  1091. unset($di);
  1092. $tbl_quiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
  1093. foreach ( $this->questionList as $question_i) {
  1094. $sql = 'SELECT type FROM %s WHERE id=%s';
  1095. $sql = sprintf($sql, $tbl_quiz_question, $question_i);
  1096. $qres = api_sql_query($sql, __FILE__, __LINE__);
  1097. if (Database::num_rows($qres) > 0) {
  1098. $qrow = Database::fetch_array($qres);
  1099. $objQuestion = Question::getInstance($qrow['type']);
  1100. $objQuestion = Question::read((int)$question_i);
  1101. $objQuestion->search_engine_edit($this->id, FALSE, TRUE);
  1102. unset($objQuestion);
  1103. }
  1104. }
  1105. }
  1106. $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';
  1107. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_QUIZ, $this->id);
  1108. api_sql_query($sql, __FILE__, __LINE__);
  1109. // remove terms from db
  1110. require_once(api_get_path(LIBRARY_PATH) .'specific_fields_manager.lib.php');
  1111. delete_all_values_for_item($course_id, TOOL_QUIZ, $this->id);
  1112. }
  1113. }
  1114. }
  1115. endif;
  1116. ?>