|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00030 defined('MOODLE_INTERNAL') || die(); 00031 00038 if (!defined('SHORTANSWER')) { 00039 define("SHORTANSWER", "shortanswer"); 00040 define("TRUEFALSE", "truefalse"); 00041 define("MULTICHOICE", "multichoice"); 00042 define("RANDOM", "random"); 00043 define("MATCH", "match"); 00044 define("RANDOMSAMATCH", "randomsamatch"); 00045 define("DESCRIPTION", "description"); 00046 define("NUMERICAL", "numerical"); 00047 define("MULTIANSWER", "multianswer"); 00048 define("CALCULATED", "calculated"); 00049 define("ESSAY", "essay"); 00050 } 00070 function lesson_save_question_options($question, $lesson) { 00071 global $DB; 00072 00073 // These lines are required to ensure that all page types have 00074 // been loaded for the following switch 00075 if (!($lesson instanceof lesson)) { 00076 $lesson = new lesson($lesson); 00077 } 00078 $manager = lesson_page_type_manager::get($lesson); 00079 00080 $timenow = time(); 00081 $result = new stdClass(); 00082 switch ($question->qtype) { 00083 case LESSON_PAGE_SHORTANSWER: 00084 00085 $answers = array(); 00086 $maxfraction = -1; 00087 00088 // Insert all the new answers 00089 foreach ($question->answer as $key => $dataanswer) { 00090 if ($dataanswer != "") { 00091 $answer = new stdClass; 00092 $answer->lessonid = $question->lessonid; 00093 $answer->pageid = $question->id; 00094 if ($question->fraction[$key] >=0.5) { 00095 $answer->jumpto = LESSON_NEXTPAGE; 00096 } 00097 $answer->timecreated = $timenow; 00098 $answer->grade = $question->fraction[$key] * 100; 00099 $answer->answer = $dataanswer; 00100 $answer->response = $question->feedback[$key]['text']; 00101 $answer->responseformat = $question->feedback[$key]['format']; 00102 $answer->id = $DB->insert_record("lesson_answers", $answer); 00103 $answers[] = $answer->id; 00104 if ($question->fraction[$key] > $maxfraction) { 00105 $maxfraction = $question->fraction[$key]; 00106 } 00107 } 00108 } 00109 00110 00112 if ($maxfraction != 1) { 00113 $maxfraction = $maxfraction * 100; 00114 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); 00115 return $result; 00116 } 00117 break; 00118 00119 case LESSON_PAGE_NUMERICAL: // Note similarities to SHORTANSWER 00120 00121 $answers = array(); 00122 $maxfraction = -1; 00123 00124 00125 // for each answer store the pair of min and max values even if they are the same 00126 foreach ($question->answer as $key => $dataanswer) { 00127 if ($dataanswer != "") { 00128 $answer = new stdClass; 00129 $answer->lessonid = $question->lessonid; 00130 $answer->pageid = $question->id; 00131 $answer->jumpto = LESSON_NEXTPAGE; 00132 $answer->timecreated = $timenow; 00133 $answer->grade = $question->fraction[$key] * 100; 00134 $min = $question->answer[$key] - $question->tolerance[$key]; 00135 $max = $question->answer[$key] + $question->tolerance[$key]; 00136 $answer->answer = $min.":".$max; 00137 // $answer->answer = $question->min[$key].":".$question->max[$key]; original line for min/max 00138 $answer->response = $question->feedback[$key]['text']; 00139 $answer->responseformat = $question->feedback[$key]['format']; 00140 $answer->id = $DB->insert_record("lesson_answers", $answer); 00141 00142 $answers[] = $answer->id; 00143 if ($question->fraction[$key] > $maxfraction) { 00144 $maxfraction = $question->fraction[$key]; 00145 } 00146 } 00147 } 00148 00150 if ($maxfraction != 1) { 00151 $maxfraction = $maxfraction * 100; 00152 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); 00153 return $result; 00154 } 00155 break; 00156 00157 00158 case LESSON_PAGE_TRUEFALSE: 00159 00160 // the truth 00161 $answer = new stdClass(); 00162 $answer->lessonid = $question->lessonid; 00163 $answer->pageid = $question->id; 00164 $answer->timecreated = $timenow; 00165 $answer->answer = get_string("true", "quiz"); 00166 $answer->grade = $question->correctanswer * 100; 00167 if ($answer->grade > 50 ) { 00168 $answer->jumpto = LESSON_NEXTPAGE; 00169 } 00170 if (isset($question->feedbacktrue)) { 00171 $answer->response = $question->feedbacktrue['text']; 00172 $answer->responseformat = $question->feedbacktrue['format']; 00173 } 00174 $DB->insert_record("lesson_answers", $answer); 00175 00176 // the lie 00177 $answer = new stdClass; 00178 $answer->lessonid = $question->lessonid; 00179 $answer->pageid = $question->id; 00180 $answer->timecreated = $timenow; 00181 $answer->answer = get_string("false", "quiz"); 00182 $answer->grade = (1 - (int)$question->correctanswer) * 100; 00183 if ($answer->grade > 50 ) { 00184 $answer->jumpto = LESSON_NEXTPAGE; 00185 } 00186 if (isset($question->feedbackfalse)) { 00187 $answer->response = $question->feedbackfalse['text']; 00188 $answer->responseformat = $question->feedbackfalse['format']; 00189 } 00190 $DB->insert_record("lesson_answers", $answer); 00191 00192 break; 00193 00194 case LESSON_PAGE_MULTICHOICE: 00195 00196 $totalfraction = 0; 00197 $maxfraction = -1; 00198 00199 $answers = array(); 00200 00201 // Insert all the new answers 00202 foreach ($question->answer as $key => $dataanswer) { 00203 if ($dataanswer != "") { 00204 $answer = new stdClass; 00205 $answer->lessonid = $question->lessonid; 00206 $answer->pageid = $question->id; 00207 $answer->timecreated = $timenow; 00208 $answer->grade = $question->fraction[$key] * 100; 00209 // changed some defaults 00210 /* Original Code 00211 if ($answer->grade > 50 ) { 00212 $answer->jumpto = LESSON_NEXTPAGE; 00213 } 00214 Replaced with: */ 00215 if ($answer->grade > 50 ) { 00216 $answer->jumpto = LESSON_NEXTPAGE; 00217 $answer->score = 1; 00218 } 00219 // end Replace 00220 $answer->answer = $dataanswer['text']; 00221 $answer->answerformat = $dataanswer['format']; 00222 $answer->response = $question->feedback[$key]['text']; 00223 $answer->responseformat = $question->feedback[$key]['format']; 00224 $answer->id = $DB->insert_record("lesson_answers", $answer); 00225 // for Sanity checks 00226 if ($question->fraction[$key] > 0) { 00227 $totalfraction += $question->fraction[$key]; 00228 } 00229 if ($question->fraction[$key] > $maxfraction) { 00230 $maxfraction = $question->fraction[$key]; 00231 } 00232 } 00233 } 00234 00236 if ($question->single) { 00237 if ($maxfraction != 1) { 00238 $maxfraction = $maxfraction * 100; 00239 $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); 00240 return $result; 00241 } 00242 } else { 00243 $totalfraction = round($totalfraction,2); 00244 if ($totalfraction != 1) { 00245 $totalfraction = $totalfraction * 100; 00246 $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction); 00247 return $result; 00248 } 00249 } 00250 break; 00251 00252 case LESSON_PAGE_MATCHING: 00253 00254 $subquestions = array(); 00255 00256 $defaultanswer = new stdClass; 00257 $defaultanswer->lessonid = $question->lessonid; 00258 $defaultanswer->pageid = $question->id; 00259 $defaultanswer->timecreated = $timenow; 00260 $defaultanswer->grade = 0; 00261 00262 // The first answer should always be the correct answer 00263 $correctanswer = clone($defaultanswer); 00264 $correctanswer->answer = get_string('thatsthecorrectanswer', 'lesson'); 00265 $DB->insert_record("lesson_answers", $correctanswer); 00266 00267 // The second answer should always be the wrong answer 00268 $wronganswer = clone($defaultanswer); 00269 $wronganswer->answer = get_string('thatsthewronganswer', 'lesson'); 00270 $DB->insert_record("lesson_answers", $wronganswer); 00271 00272 $i = 0; 00273 // Insert all the new question+answer pairs 00274 foreach ($question->subquestions as $key => $questiontext) { 00275 $answertext = $question->subanswers[$key]; 00276 if (!empty($questiontext) and !empty($answertext)) { 00277 $answer = clone($defaultanswer); 00278 $answer->answer = $questiontext['text']; 00279 $answer->answerformat = $questiontext['format']; 00280 $answer->response = $answertext; 00281 if ($i == 0) { 00282 // first answer contains the correct answer jump 00283 $answer->jumpto = LESSON_NEXTPAGE; 00284 } 00285 $subquestions[] = $DB->insert_record("lesson_answers", $answer); 00286 $i++; 00287 } 00288 } 00289 00290 if (count($subquestions) < 3) { 00291 $result->notice = get_string("notenoughsubquestions", "quiz"); 00292 return $result; 00293 } 00294 break; 00295 default: 00296 $result->error = "Unsupported question type ($question->qtype)!"; 00297 return $result; 00298 } 00299 return true; 00300 } 00301 00302 00303 class qformat_default { 00304 00305 var $displayerrors = true; 00306 var $category = NULL; 00307 var $questionids = array(); 00308 var $qtypeconvert = array(NUMERICAL => LESSON_PAGE_NUMERICAL, 00309 MULTICHOICE => LESSON_PAGE_MULTICHOICE, 00310 TRUEFALSE => LESSON_PAGE_TRUEFALSE, 00311 SHORTANSWER => LESSON_PAGE_SHORTANSWER, 00312 MATCH => LESSON_PAGE_MATCHING 00313 ); 00314 00315 // Importing functions 00316 function provide_import() { 00317 return false; 00318 } 00319 00320 function importpreprocess() { 00321 // Does any pre-processing that may be desired 00322 return true; 00323 } 00324 00325 function importprocess($filename, $lesson, $pageid) { 00326 global $DB, $OUTPUT; 00327 00329 $timenow = time(); 00330 00331 if (! $lines = $this->readdata($filename)) { 00332 echo $OUTPUT->notification("File could not be read, or was empty"); 00333 return false; 00334 } 00335 00336 if (! $questions = $this->readquestions($lines)) { // Extract all the questions 00337 echo $OUTPUT->notification("There are no questions in this file!"); 00338 return false; 00339 } 00340 00341 //Avoid category as question type 00342 echo $OUTPUT->notification(get_string('importcount', 'lesson', 00343 $this->count_questions($questions)), 'notifysuccess'); 00344 00345 $count = 0; 00346 00347 $unsupportedquestions = 0; 00348 00349 foreach ($questions as $question) { // Process and store each question 00350 switch ($question->qtype) { 00351 //TODO: Bad way to bypass category in data... Quickfix for MDL-27964 00352 case 'category': 00353 break; 00354 // the good ones 00355 case SHORTANSWER : 00356 case NUMERICAL : 00357 case TRUEFALSE : 00358 case MULTICHOICE : 00359 case MATCH : 00360 $count++; 00361 00362 //Show nice formated question in one line. 00363 echo "<hr><p><b>$count</b>. ".$this->format_question_text($question)."</p>"; 00364 00365 $newpage = new stdClass; 00366 $newpage->lessonid = $lesson->id; 00367 $newpage->qtype = $this->qtypeconvert[$question->qtype]; 00368 switch ($question->qtype) { 00369 case SHORTANSWER : 00370 if (isset($question->usecase)) { 00371 $newpage->qoption = $question->usecase; 00372 } 00373 break; 00374 case MULTICHOICE : 00375 if (isset($question->single)) { 00376 $newpage->qoption = !$question->single; 00377 } 00378 break; 00379 } 00380 $newpage->timecreated = $timenow; 00381 if ($question->name != $question->questiontext) { 00382 $newpage->title = $question->name; 00383 } else { 00384 $newpage->title = "Page $count"; 00385 } 00386 $newpage->contents = $question->questiontext; 00387 00388 // set up page links 00389 if ($pageid) { 00390 // the new page follows on from this page 00391 if (!$page = $DB->get_record("lesson_pages", array("id" => $pageid))) { 00392 print_error('invalidpageid', 'lesson'); 00393 } 00394 $newpage->prevpageid = $pageid; 00395 $newpage->nextpageid = $page->nextpageid; 00396 // insert the page and reset $pageid 00397 $newpageid = $DB->insert_record("lesson_pages", $newpage); 00398 // update the linked list 00399 $DB->set_field("lesson_pages", "nextpageid", $newpageid, array("id" => $pageid)); 00400 00401 } else { 00402 // new page is the first page 00403 // get the existing (first) page (if any) 00404 $params = array ("lessonid" => $lesson->id, "prevpageid" => 0); 00405 if (!$page = $DB->get_record_select("lesson_pages", "lessonid = :lessonid AND prevpageid = :prevpageid", $params)) { 00406 // there are no existing pages 00407 $newpage->prevpageid = 0; // this is a first page 00408 $newpage->nextpageid = 0; // this is the only page 00409 $newpageid = $DB->insert_record("lesson_pages", $newpage); 00410 } else { 00411 // there are existing pages put this at the start 00412 $newpage->prevpageid = 0; // this is a first page 00413 $newpage->nextpageid = $page->id; 00414 $newpageid = $DB->insert_record("lesson_pages", $newpage); 00415 // update the linked list 00416 $DB->set_field("lesson_pages", "prevpageid", $newpageid, array("id" => $page->id)); 00417 } 00418 } 00419 // reset $pageid and put the page ID in $question, used in save_question_option() 00420 $pageid = $newpageid; 00421 $question->id = $newpageid; 00422 00423 $this->questionids[] = $question->id; 00424 00425 // Now to save all the answers and type-specific options 00426 00427 $question->lessonid = $lesson->id; // needed for foreign key 00428 $question->qtype = $this->qtypeconvert[$question->qtype]; 00429 $result = lesson_save_question_options($question, $lesson); 00430 00431 if (!empty($result->error)) { 00432 echo $OUTPUT->notification($result->error); 00433 return false; 00434 } 00435 00436 if (!empty($result->notice)) { 00437 echo $OUTPUT->notification($result->notice); 00438 return true; 00439 } 00440 break; 00441 // the Bad ones 00442 default : 00443 $unsupportedquestions++; 00444 break; 00445 } 00446 00447 } 00448 if ($unsupportedquestions) { 00449 echo $OUTPUT->notification(get_string('unknownqtypesnotimported', 'lesson', $unsupportedquestions)); 00450 } 00451 return true; 00452 } 00453 00461 protected function count_questions($questions) { 00462 $count = 0; 00463 if (!is_array($questions)) { 00464 return $count; 00465 } 00466 foreach ($questions as $question) { 00467 if (!is_object($question) || !isset($question->qtype) || 00468 ($question->qtype == 'category')) { 00469 continue; 00470 } 00471 $count++; 00472 } 00473 return $count; 00474 } 00475 00476 function readdata($filename) { 00478 00479 if (is_readable($filename)) { 00480 $filearray = file($filename); 00481 00483 if (preg_match("/\r/", $filearray[0]) AND !preg_match("/\n/", $filearray[0])) { 00484 return explode("\r", $filearray[0]); 00485 } else { 00486 return $filearray; 00487 } 00488 } 00489 return false; 00490 } 00491 00492 protected function readquestions($lines) { 00497 00498 $questions = array(); 00499 $currentquestion = array(); 00500 00501 foreach ($lines as $line) { 00502 $line = trim($line); 00503 if (empty($line)) { 00504 if (!empty($currentquestion)) { 00505 if ($question = $this->readquestion($currentquestion)) { 00506 $questions[] = $question; 00507 } 00508 $currentquestion = array(); 00509 } 00510 } else { 00511 $currentquestion[] = $line; 00512 } 00513 } 00514 00515 if (!empty($currentquestion)) { // There may be a final question 00516 if ($question = $this->readquestion($currentquestion)) { 00517 $questions[] = $question; 00518 } 00519 } 00520 00521 return $questions; 00522 } 00523 00524 00525 function readquestion($lines) { 00529 00530 echo "<p>This flash question format has not yet been completed!</p>"; 00531 00532 return NULL; 00533 } 00534 00535 function defaultquestion() { 00536 // returns an "empty" question 00537 // Somewhere to specify question parameters that are not handled 00538 // by import but are required db fields. 00539 // This should not be overridden. 00540 global $CFG; 00541 00542 $question = new stdClass(); 00543 $question->shuffleanswers = get_config('quiz', 'shuffleanswers'); 00544 $question->defaultmark = 1; 00545 $question->image = ""; 00546 $question->usecase = 0; 00547 $question->multiplier = array(); 00548 $question->generalfeedback = ''; 00549 $question->correctfeedback = ''; 00550 $question->partiallycorrectfeedback = ''; 00551 $question->incorrectfeedback = ''; 00552 $question->answernumbering = 'abc'; 00553 $question->penalty = 0.1; 00554 $question->length = 1; 00555 $question->qoption = 0; 00556 $question->layout = 1; 00557 00558 // this option in case the questiontypes class wants 00559 // to know where the data came from 00560 $question->export_process = true; 00561 $question->import_process = true; 00562 00563 return $question; 00564 } 00565 00566 function importpostprocess() { 00570 return true; 00571 } 00572 00577 protected function format_question_text($question) { 00578 $formatoptions = new stdClass(); 00579 $formatoptions->noclean = true; 00580 return html_to_text(format_text($question->questiontext, 00581 $question->questiontextformat, $formatoptions), 0, false); 00582 } 00583 } 00584 00585