From 69988ed452fa68a363445dcfad08a72bcaa292d6 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Fri, 12 Nov 2010 17:11:34 +0000 Subject: [PATCH] questions MDL-25104 and MDL-25088 fix question editing and import Editing of some qtypes was broken since a previous commit by me earlier in the week. Import of XML and GIFT should now work, but could use some more testing. --- question/format/xml/format.php | 8 +- question/type/essay/questiontype.php | 39 ++--- question/type/match/questiontype.php | 88 +++++------ question/type/multichoice/questiontype.php | 150 ++++++++---------- question/type/numerical/questiontype.php | 176 +++++++-------------- question/type/questiontype.php | 39 ++++- question/type/shortanswer/questiontype.php | 97 +++++------- question/type/truefalse/questiontype.php | 139 +++++++--------- 8 files changed, 309 insertions(+), 427 deletions(-) diff --git a/question/format/xml/format.php b/question/format/xml/format.php index ef3f152eb45..68fedcee8a0 100755 --- a/question/format/xml/format.php +++ b/question/format/xml/format.php @@ -448,8 +448,8 @@ class qformat_xml extends qformat_default { $answers = $question['#']['answer']; $a_count = 0; foreach ($answers as $answer) { - $ans = $this->import_answer( $answer ); - $qo->answer[$a_count] = $ans->answer; + $ans = $this->import_answer($answer); + $qo->answer[$a_count] = $ans->answer['text']; $qo->fraction[$a_count] = $ans->fraction; $qo->feedback[$a_count] = $ans->feedback; ++$a_count; @@ -494,7 +494,7 @@ class qformat_xml extends qformat_default { foreach ($answers as $answer) { // answer outside of is deprecated $obj = $this->import_answer($answer); - $qo->answer[] = $obj->answer; + $qo->answer[] = $obj->answer['text']; if (empty($qo->answer)) { $qo->answer = '*'; } @@ -520,6 +520,8 @@ class qformat_xml extends qformat_default { $qo->unitpenalty = $this->getpath( $question, array('#','unitpenalty',0,'#'), 0 ); $qo->showunits = $this->getpath( $question, array('#','showunits',0,'#'), 0 ); $qo->unitsleft = $this->getpath( $question, array('#','unitsleft',0,'#'), 0 ); + $qo->instructions['text'] = ''; + $qo->instructions['format'] = FORMAT_HTML; $instructions = $this->getpath($question, array('#', 'instructions'), array()); if (!empty($instructions)) { $qo->instructions = array(); diff --git a/question/type/essay/questiontype.php b/question/type/essay/questiontype.php index b7163ece15b..1a29b9e8a74 100644 --- a/question/type/essay/questiontype.php +++ b/question/type/essay/questiontype.php @@ -37,37 +37,28 @@ class question_essay_qtype extends default_questiontype { function save_question_options($question) { global $DB; $context = $question->context; - $result = true; - $update = true; - $answer = $DB->get_record("question_answers", array("question" => $question->id)); + + $answer = $DB->get_record('question_answers', array('question' => $question->id)); if (!$answer) { $answer = new stdClass; $answer->question = $question->id; - $update = false; + $answer->answer = ''; + $answer->feedback = ''; + $answer->id = $DB->insert_record('question_answers', $answer); } + + $answer->feedback = $question->feedback['text']; $answer->feedbackformat = $question->feedback['format']; + $answer->answer = $answer->feedback; $answer->answerformat = $question->feedback['format']; $answer->fraction = $question->fraction; - if ($update) { - $answer->feedback = file_save_draft_area_files($question->feedback['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback['text'])); - $answer->answer = $answer->feedback; - $DB->update_record("question_answers", $answer); - } else { - $answer->feedback = $question->feedback['text']; - $answer->answer = $answer->feedback; - $answer->id = $DB->insert_record('question_answers', $answer); - if (isset($question->feedback['files'])) { - // import - foreach ($question->feedback['files'] as $file) { - $this->import_file($context, 'question', 'answerfeedback', $answer->id, $file); - } - } else { - $answer->feedback = file_save_draft_area_files($question->feedback['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, trim($question->feedback['text'])); - } - $answer->answer = $answer->feedback; - $DB->update_record('question_answers', $answer); - } - return $result; + + $answer->feedback = $this->import_or_save_files($question->feedback, + $context, 'question', 'answerfeedback', $answer->id); + $answer->answer = $answer->feedback; + $DB->update_record('question_answers', $answer); + + return true; } function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { diff --git a/question/type/match/questiontype.php b/question/type/match/questiontype.php index 333db6b713d..96bb660503c 100644 --- a/question/type/match/questiontype.php +++ b/question/type/match/questiontype.php @@ -42,73 +42,63 @@ class question_match_qtype extends default_questiontype { $context = $question->context; $result = new stdClass; - if (!$oldsubquestions = $DB->get_records("question_match_sub", array("question" => $question->id), "id ASC")) { - $oldsubquestions = array(); - } + $oldsubquestions = $DB->get_records('question_match_sub', + array('question' => $question->id), 'id ASC'); // $subquestions will be an array with subquestion ids $subquestions = array(); // Insert all the new question+answer pairs foreach ($question->subquestions as $key => $questiontext) { - if (!empty($questiontext['itemid'])) { - $itemid = $questiontext['itemid']; + if ($questiontext['text'] == '' && trim($question->subanswers[$key]) == '') { + continue; } - $files = $questiontext['files']; - $format = $questiontext['format']; - $questiontext = trim($questiontext['text']); - $answertext = trim($question->subanswers[$key]); - if ($questiontext != '' || $answertext != '') { - if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it - $subquestion->answertext = $answertext; - $subquestion->questiontext = file_save_draft_area_files($itemid, $context->id, 'qtype_match', 'subquestion', $subquestion->id, self::$fileoptions, $questiontext); - $subquestion->questiontextformat = $format; - $DB->update_record("question_match_sub", $subquestion); - } else { - $subquestion = new stdClass; - // Determine a unique random code - $subquestion->code = rand(1, 999999999); - while ($DB->record_exists('question_match_sub', array('code' => $subquestion->code, 'question' => $question->id))) { - $subquestion->code = rand(); - } - $subquestion->question = $question->id; - $subquestion->questiontext = $questiontext; - $subquestion->questiontextformat = $format; - $subquestion->answertext = $answertext; - $subquestion->id = $DB->insert_record("question_match_sub", $subquestion); - if (!isset($itemid)) { - foreach ($files as $file) { - $this->import_file($context, 'qtype_match', 'subquestion', $subquestion->id, $file); - } - } else { - $questiontext = file_save_draft_area_files($itemid, $context->id, 'qtype_match', 'subquestion', $subquestion->id, self::$fileoptions, $questiontext); - } - $DB->set_field('question_match_sub', 'questiontext', $questiontext, array('id'=>$subquestion->id)); - } - $subquestions[] = $subquestion->id; - } - if ($questiontext != '' && $answertext == '') { + if ($questiontext['text'] != '' && trim($question->subanswers[$key]) == '') { $result->notice = get_string('nomatchinganswer', 'quiz', $questiontext); } - } - // delete old subquestions records - if (!empty($oldsubquestions)) { - foreach($oldsubquestions as $os) { - $DB->delete_records('question_match_sub', array('id' => $os->id)); + // Update an existing subquestion if possible. + $subquestion = array_shift($oldsubquestions); + if (!$subquestion) { + $subquestion = new stdClass; + // Determine a unique random code + $subquestion->code = rand(1, 999999999); + while ($DB->record_exists('question_match_sub', array('code' => $subquestion->code, 'question' => $question->id))) { + $subquestion->code = rand(1, 999999999); + } + $subquestion->question = $question->id; + $subquestion->questiontext = ''; + $subquestion->answertext = ''; + $subquestion->id = $DB->insert_record('question_match_sub', $subquestion); } + + $subquestion->questiontext = $this->import_or_save_files($questiontext, + $context, 'qtype_match', 'subquestion', $subquestion->id); + $subquestion->questiontextformat = $questiontext['format']; + $subquestion->answertext = trim($question->subanswers[$key]); + + $DB->update_record('question_match_sub', $subquestion); + + $subquestions[] = $subquestion->id; } - if ($options = $DB->get_record("question_match", array("question" => $question->id))) { - $options->subquestions = implode(",",$subquestions); + // Delete old subquestions records + $fs = get_file_storage(); + foreach($oldsubquestions as $oldsub) { + $fs->delete_area_files($context->id, 'qtype_match', 'subquestion', $oldsub->id); + $DB->delete_records('question_match_sub', array('id' => $oldsub->id)); + } + + if ($options = $DB->get_record('question_match', array('question' => $question->id))) { + $options->subquestions = implode(',', $subquestions); $options->shuffleanswers = $question->shuffleanswers; - $DB->update_record("question_match", $options); + $DB->update_record('question_match', $options); } else { unset($options); $options->question = $question->id; - $options->subquestions = implode(",",$subquestions); + $options->subquestions = implode(',', $subquestions); $options->shuffleanswers = $question->shuffleanswers; - $DB->insert_record("question_match", $options); + $DB->insert_record('question_match', $options); } if (!empty($result->notice)) { diff --git a/question/type/multichoice/questiontype.php b/question/type/multichoice/questiontype.php index bef67f0e65d..bb75bf58e55 100644 --- a/question/type/multichoice/questiontype.php +++ b/question/type/multichoice/questiontype.php @@ -36,135 +36,109 @@ class question_multichoice_qtype extends default_questiontype { global $DB; $context = $question->context; $result = new stdClass; - if (!$oldanswers = $DB->get_records("question_answers", array("question" => $question->id), "id ASC")) { - $oldanswers = array(); - } + + $oldanswers = $DB->get_records('question_answers', + array('question' => $question->id), 'id ASC'); // following hack to check at least two answers exist $answercount = 0; - foreach ($question->answer as $key=>$dataanswer) { - if ($dataanswer != "") { + foreach ($question->answer as $key => $answer) { + if ($answer != '') { $answercount++; } } - $answercount += count($oldanswers); if ($answercount < 2) { // check there are at lest 2 answers for multiple choice - $result->notice = get_string("notenoughanswers", "qtype_multichoice", "2"); + $result->notice = get_string('notenoughanswers', 'qtype_multichoice', '2'); return $result; } // Insert all the new answers - $totalfraction = 0; $maxfraction = -1; - $answers = array(); + foreach ($question->answer as $key => $answerdata) { + if ($answerdata == '') { + continue; + } - foreach ($question->answer as $key => $dataanswer) { - if ($dataanswer != "") { - $feedbackformat = $question->feedback[$key]['format']; - if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it - $answer->answer = $dataanswer; - $answer->fraction = $question->fraction[$key]; - $answer->feedbackformat = $feedbackformat; - $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']); - $DB->update_record("question_answers", $answer); - } else { - // import goes here too - unset($answer); - if (is_array($dataanswer)) { - $answer->answer = $dataanswer['text']; - $answer->answerformat = $dataanswer['format']; - } else { - $answer->answer = $dataanswer; - } - $answer->question = $question->id; - $answer->fraction = $question->fraction[$key]; - $answer->feedback = $question->feedback[$key]['text']; - $answer->feedbackformat = $feedbackformat; - $answer->id = $DB->insert_record("question_answers", $answer); - if (isset($question->feedback[$key]['files'])) { - foreach ($question->feedback[$key]['files'] as $file) { - $this->import_file($context, 'question', 'answerfeedback', $answer->id, $file); - } - } else { - $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']); - } + // Update an existing answer if possible. + $answer = array_shift($oldanswers); + if (!$answer) { + $answer = new stdClass(); + $answer->question = $question->id; + $answer->answer = ''; + $answer->feedback = ''; + $answer->id = $DB->insert_record('question_answers', $answer); + } - $DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id)); - } - $answers[] = $answer->id; + $answer->answer = $answerdata; + $answer->answer = FORMAT_HTML; + $answer->fraction = $question->fraction[$key]; + $answer->feedback = $this->import_or_save_files($question->feedback[$key], + $context, 'question', 'answerfeedback', $answer->id); + $answer->feedbackformat = $question->feedback[$key]['format']; - if ($question->fraction[$key] > 0) { // Sanity checks - $totalfraction += $question->fraction[$key]; - } - if ($question->fraction[$key] > $maxfraction) { - $maxfraction = $question->fraction[$key]; - } + $DB->update_record('question_answers', $answer); + $answers[] = $answer->id; + + if ($question->fraction[$key] > 0) { + $totalfraction += $question->fraction[$key]; + } + if ($question->fraction[$key] > $maxfraction) { + $maxfraction = $question->fraction[$key]; } } - $update = true; - $options = $DB->get_record("question_multichoice", array("question" => $question->id)); + // Delete any left over old answer records. + $fs = get_file_storage(); + foreach($oldanswers as $oldanswer) { + $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id); + $DB->delete_records('question_answers', array('id' => $oldanswer->id)); + } + + $options = $DB->get_record('question_multichoice', array('question' => $question->id)); if (!$options) { - $update = false; $options = new stdClass; $options->question = $question->id; - + $options->correctfeedback = ''; + $options->partiallycorrectfeedback = ''; + $options->incorrectfeedback = ''; + $options->id = $DB->insert_record('question_multichoice', $options); } - $options->answers = implode(",",$answers); + + $options->answers = implode(',', $answers); $options->single = $question->single; - if(isset($question->layout)){ + if (isset($question->layout)) { $options->layout = $question->layout; } $options->answernumbering = $question->answernumbering; $options->shuffleanswers = $question->shuffleanswers; + $options->correctfeedback = $this->import_or_save_files($question->correctfeedback, + $context, 'qtype_multichoice', 'correctfeedback', $question->id); + $options->correctfeedbackformat = $question->correctfeedback['format']; + $options->partiallycorrectfeedback = $this->import_or_save_files($question->correctfeedback, + $context, 'qtype_multichoice', 'partiallycorrectfeedback', $question->id); + $options->partiallycorrectfeedbackformat = $question->partiallycorrectfeedback['format']; + $options->incorrectfeedback = $this->import_or_save_files($question->correctfeedback, + $context, 'qtype_multichoice', 'incorrectfeedback', $question->id); + $options->incorrectfeedbackformat = $question->incorrectfeedback['format']; - foreach (array('correct', 'partiallycorrect', 'incorrect') as $feedbacktype) { - $feedbackname = $feedbacktype . 'feedback'; - $feedback = $question->$feedbackname; - $feedbackformatname = $feedbackname . 'format'; - $options->$feedbackname = trim($feedback['text']); - $options->$feedbackformatname = trim($feedback['format']); - if (isset($feedback['files'])) { - // import - foreach ($feedback['files'] as $file) { - $this->import_file($context, 'qtype_multichoice', $feedbackname, $question->id, $file); - } - } else { - $options->$feedbackname = file_save_draft_area_files( - $feedback['itemid'], $context->id, 'qtype_multichoice', $feedbackname, $question->id, self::$fileoptions, trim($feedback['text'])); - } - } - - if ($update) { - $DB->update_record('question_multichoice', $options); - } else { - $DB->insert_record('question_multichoice', $options); - } - - // delete old answer records - if (!empty($oldanswers)) { - foreach($oldanswers as $oa) { - $DB->delete_records('question_answers', array('id' => $oa->id)); - } - } + $DB->update_record('question_multichoice', $options); /// Perform sanity checks on fractional grades if ($options->single) { if ($maxfraction != 1) { - $maxfraction = $maxfraction * 100; - $result->noticeyesno = get_string("fractionsnomax", "qtype_multichoice", $maxfraction); + $result->noticeyesno = get_string('fractionsnomax', 'qtype_multichoice', $maxfraction * 100); return $result; } } else { - $totalfraction = round($totalfraction,2); + $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { - $totalfraction = $totalfraction * 100; - $result->noticeyesno = get_string("fractionsaddwrong", "qtype_multichoice", $totalfraction); + $result->noticeyesno = get_string('fractionsaddwrong', 'qtype_multichoice', $totalfraction * 100); return $result; } } + return true; } diff --git a/question/type/numerical/questiontype.php b/question/type/numerical/questiontype.php index 6f1c0fb3eef..cd49575b8d3 100644 --- a/question/type/numerical/questiontype.php +++ b/question/type/numerical/questiontype.php @@ -149,78 +149,58 @@ class question_numerical_qtype extends question_shortanswer_qtype { $context = $question->context; // Get old versions of the objects - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - - if (!$oldoptions = $DB->get_records('question_numerical', array('question' => $question->id), 'answer ASC')) { - $oldoptions = array(); - } + $oldanswers = $DB->get_records('question_answers', + array('question' => $question->id), 'id ASC'); + $oldoptions = $DB->get_records('question_numerical', + array('question' => $question->id), 'answer ASC'); // Save the units. $result = $this->save_numerical_units($question); if (isset($result->error)) { return $result; } else { - $units = &$result->units; + $units = $result->units; } // Insert all the new answers - foreach ($question->answer as $key => $dataanswer) { - if (is_array($dataanswer)) { - $dataanswer = $dataanswer['text']; - } + foreach ($question->answer as $key => $answerdata) { // Check for, and ingore, completely blank answer from the form. - if (trim($dataanswer) == '' && $question->fraction[$key] == 0 && + if (trim($answerdata) == '' && $question->fraction[$key] == 0 && html_is_blank($question->feedback[$key]['text'])) { continue; } - $answer = new stdClass; - $answer->question = $question->id; - if (trim($dataanswer) === '*') { + // Update an existing answer if possible. + $answer = array_shift($oldanswers); + if (!$answer) { + $answer = new stdClass(); + $answer->question = $question->id; + $answer->answer = ''; + $answer->feedback = ''; + $answer->id = $DB->insert_record('question_answers', $answer); + } + + if (trim($answerdata) === '*') { $answer->answer = '*'; } else { - $answer->answer = $this->apply_unit($dataanswer, $units); + $answer->answer = $this->apply_unit($answerdata, $units); if ($answer->answer === false) { $result->notice = get_string('invalidnumericanswer', 'quiz'); } } $answer->fraction = $question->fraction[$key]; - - $feedbacktext = trim($question->feedback[$key]['text']); + $answer->feedback = $this->import_or_save_files($question->feedback[$key], + $context, 'question', 'answerfeedback', $answer->id); $answer->feedbackformat = $question->feedback[$key]['format']; - if (!empty($question->feedback[$key]['itemid'])) { - $draftid = $question->feedback[$key]['itemid']; - } else { - $draftid = '' ; - } - $feedbackfiles = $question->feedback[$key]['files']; - - if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it - $feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $feedbacktext); - $answer->feedback = $feedbacktext; - $answer->id = $oldanswer->id; - $DB->update_record("question_answers", $answer); - } else { // This is a completely new answer - $answer->feedback = $feedbacktext; - $answer->id = $DB->insert_record("question_answers", $answer); - if ($draftid) { - $feedbacktext = file_save_draft_area_files($draftid, $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $feedbacktext); - } else { - foreach ($feedbackfiles as $file) { - $this->import_file($question->context, 'question', 'answerfeedback', $answer->id, $file); - } - } - $DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$answer->id)); - } + $DB->update_record('question_answers', $answer); // Set up the options object + $options = array_shift($oldoptions); if (!$options = array_shift($oldoptions)) { - $options = new stdClass; + $options = new stdClass(); } - $options->question = $question->id; - $options->answer = $answer->id; + $options->question = $question->id; + $options->answer = $answer->id; if (trim($question->tolerance[$key]) == '') { $options->tolerance = ''; } else { @@ -229,35 +209,28 @@ class question_numerical_qtype extends question_shortanswer_qtype { $result->notice = get_string('invalidnumerictolerance', 'quiz'); } } - - // Save options - if (isset($options->id)) { // reusing existing record + if (isset($options->id)) { $DB->update_record('question_numerical', $options); - } else { // new options + } else { $DB->insert_record('question_numerical', $options); } } - // delete old answer records - if (!empty($oldanswers)) { - foreach($oldanswers as $oa) { - $DB->delete_records('question_answers', array('id' => $oa->id)); - } + + // Delete any left over old answer records. + $fs = get_file_storage(); + foreach($oldanswers as $oldanswer) { + $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id); + $DB->delete_records('question_answers', array('id' => $oldanswer->id)); + } + foreach($oldoptions as $oldoption) { + $DB->delete_records('question_numerical', array('id' => $oldoption->id)); } - // delete old answer records - if (!empty($oldoptions)) { - foreach($oldoptions as $oo) { - $DB->delete_records('question_numerical', array('id' => $oo->id)); - } - } $result = $this->save_numerical_options($question); - if (isset($result->error)) { - return $result; - } - // Report any problems. - if (!empty($result->notice)) { + if (!empty($result->error) || !empty($result->notice)) { return $result; } + return true; } @@ -269,31 +242,32 @@ class question_numerical_qtype extends question_shortanswer_qtype { * as old question. * */ - function save_numerical_options(&$question) { + function save_numerical_options($question) { global $DB; - // echo"

".$question->id."question

";print_r($question) ;echo"

"; $result = new stdClass; - // numerical options + $update = true ; $options = $DB->get_record('question_numerical_options', array('question' => $question->id)); if (!$options) { - $update = false; $options = new stdClass; $options->question = $question->id; + $options->instructions = ''; + $options->id = $DB->insert_record('question_numerical_options', $options); } - if(isset($question->options->unitgradingtype)){ + + if (isset($question->options->unitgradingtype)) { $options->unitgradingtype = $question->options->unitgradingtype; - }else { + } else { $options->unitgradingtype = 0 ; } - if(isset($question->unitpenalty)){ + if (isset($question->unitpenalty)){ $options->unitpenalty = $question->unitpenalty; - }else { //so this is either an old question or a close question type + } else { //so this is either an old question or a close question type $options->unitpenalty = 1 ; } // if we came from the form then 'unitrole' exists - if(isset($question->unitrole)){ + if (isset($question->unitrole)){ switch ($question->unitrole){ case '0' : $options->showunits = NUMERICALQUESTIONUNITNODISPLAY ; break ; @@ -307,58 +281,30 @@ class question_numerical_qtype extends question_shortanswer_qtype { break ; } } else { - if(isset($question->showunits)){ + if (isset($question->showunits)){ $options->showunits = $question->showunits; - }else { + } else { if ($defaultunit = $this->get_default_numerical_unit($question)) { // so units can be used $options->showunits = NUMERICALQUESTIONUNITTEXTINPUTDISPLAY ; - }else { + } else { // only numerical will be graded $options->showunits = NUMERICALQUESTIONUNITNODISPLAY ; } } } - if(isset($question->unitsleft)){ + + if (isset($question->unitsleft)) { $options->unitsleft = $question->unitsleft; - }else { + } else { $options->unitsleft = 0 ; } - $options->instructionsformat = '1' ; - if ( isset($question->instructions) && isset($question->instructions['format']) && $question->instructions['format'] != '' ){ - $options->instructionsformat = $question->instructions['format']; - } - if(isset($question->instructions) && isset($question->instructions['text']) ){ - $options->instructions = trim($question->instructions['text']); - }else { - $options->instructions = '' ; - } - $component = 'qtype_' . $question->qtype; - if (isset($question->instructionsfiles) && is_array($question->instructionsfiles)) { - // import - foreach ($question->instructionsfiles as $file) { - $this->import_file($question->context, $component, 'instruction', $question->id, $file); - } - } else { - if(isset($question->instructions)){ - $options->instructions = file_save_draft_area_files($question->instructions['itemid'], - $question->context->id, // context - $component, // component - 'instruction', // filearea - $question->id, // itemid - self::$fileoptions, // options - $question->instructions['text'] // text - ); - }else { - $options->instructions = ""; - } - } - if ($update) { - $DB->update_record("question_numerical_options", $options); - } else { - $id = $DB->insert_record("question_numerical_options", $options); - } + $options->instructions = $this->import_or_save_files($question->instructions, + $question->context, 'qtype_' . $question->qtype, 'instructions', $options->id); + $options->instructionsformat = $question->instructions['format']; + + $DB->update_record('question_numerical_options', $options); return $result; } @@ -487,7 +433,7 @@ class question_numerical_qtype extends question_shortanswer_qtype { $nameprefix = $question->name_prefix; $component = 'qtype_' . $question->qtype; // rewrite instructions text - $question->options->instructions = quiz_rewrite_question_urls($question->options->instructions, 'pluginfile.php', $context->id, $component, 'instruction', array($state->attempt, $state->question), $question->id); + $question->options->instructions = quiz_rewrite_question_urls($question->options->instructions, 'pluginfile.php', $context->id, $component, 'instructions', array($state->attempt, $state->question), $question->id); /// Print question text and media diff --git a/question/type/questiontype.php b/question/type/questiontype.php index 4f322c2dcae..118d8e1f59f 100644 --- a/question/type/questiontype.php +++ b/question/type/questiontype.php @@ -46,7 +46,11 @@ require_once($CFG->libdir . '/questionlib.php'); * @subpackage questiontypes */ class default_questiontype { - public static $fileoptions = array('subdirs'=>false, 'maxfiles'=>-1, 'maxbytes'=>0); + protected $fileoptions = array( + 'subdirs' => false, + 'maxfiles' => -1, + 'maxbytes' => 0, + ); /** * Name of the question type @@ -361,10 +365,10 @@ class default_questiontype { $question->timemodified = time(); if (!empty($question->questiontext)) { - $question->questiontext = file_save_draft_area_files($form->questiontext['itemid'], $context->id, 'question', 'questiontext', (int)$question->id, self::$fileoptions, $question->questiontext); + $question->questiontext = file_save_draft_area_files($form->questiontext['itemid'], $context->id, 'question', 'questiontext', (int)$question->id, $this->fileoptions, $question->questiontext); } if (!empty($question->generalfeedback)) { - $question->generalfeedback = file_save_draft_area_files($form->generalfeedback['itemid'], $context->id, 'question', 'generalfeedback', (int)$question->id, self::$fileoptions, $question->generalfeedback); + $question->generalfeedback = file_save_draft_area_files($form->generalfeedback['itemid'], $context->id, 'question', 'generalfeedback', (int)$question->id, $this->fileoptions, $question->generalfeedback); } $DB->update_record('question', $question); @@ -1653,6 +1657,35 @@ class default_questiontype { return $context; } + /** + * Save the file belonging to one text field. + * + * @param array $field the data from the form (or from import). This will + * normally have come from the formslib editor element, so it will be an + * array with keys 'text', 'format' and 'itemid'. However, when we are + * importing, it will be an array with keys 'text', 'format' and 'files' + * @param object $context the context the question is in. + * @param string $component indentifies the file area. + * @param string $filearea indentifies the file area. + * @param integer $itemid identifies the file area. + * + * @return string the text for this field, after files have been processed. + */ + protected function import_or_save_files($field, $context, $component, $filearea, $itemid) { + if (!empty($field['itemid'])) { + // This is the normal case. We are safing the questions editing form. + return file_save_draft_area_files($field['itemid'], $context->id, $component, + $filearea, $itemid, $this->fileoptions, trim($field['text'])); + + } else if (!empty($field['files'])) { + // This is the case when we are doing an import. + foreach ($question->feedback['files'] as $file) { + $this->import_file($context, 'question', 'answerfeedback', $itemid, $file); + } + } + return trim($field['text']); + } + /** * Move all the files belonging to this question from one context to another. * @param integer $questionid the question being moved. diff --git a/question/type/shortanswer/questiontype.php b/question/type/shortanswer/questiontype.php index e449904dcb1..2ef7e130403 100644 --- a/question/type/shortanswer/questiontype.php +++ b/question/type/shortanswer/questiontype.php @@ -65,88 +65,63 @@ class question_shortanswer_qtype extends default_questiontype { $context = $question->context; - if (!$oldanswers = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC')) { - $oldanswers = array(); - } - - $answers = array(); - $maxfraction = -1; + $oldanswers = $DB->get_records('question_answers', + array('question' => $question->id), 'id ASC'); // Insert all the new answers - foreach ($question->answer as $key => $dataanswer) { - if (is_array($dataanswer)) { - $dataanswer = $dataanswer['text']; - } - // Check for, and ingore, completely blank answer from the form. - if (trim($dataanswer) == '' && $question->fraction[$key] == 0 && + $answers = array(); + $maxfraction = -1; + foreach ($question->answer as $key => $answerdata) { + // Check for, and ignore, completely blank answer from the form. + if (trim($answerdata) == '' && $question->fraction[$key] == 0 && html_is_blank($question->feedback[$key]['text'])) { continue; } - $feedbackformat = $question->feedback[$key]['format']; - if (isset($question->feedback[$key]['files'])) { - $feedbackfiles = $question->feedback[$key]['files']; - } - - if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it - $answer = $oldanswer; - $answer->answer = trim($dataanswer); - $answer->fraction = $question->fraction[$key]; - - // save draft file and rewrite text in feedback - $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $oldanswer->id, self::$fileoptions, $question->feedback[$key]['text']); - $answer->feedbackformat = $feedbackformat; - - $DB->update_record("question_answers", $answer); - } else { // This is a completely new answer - $answer = new stdClass; - $answer->answer = trim($dataanswer); + // Update an existing answer if possible. + $answer = array_shift($oldanswers); + if (!$answer) { + $answer = new stdClass(); $answer->question = $question->id; - $answer->fraction = $question->fraction[$key]; - // feedback content needs to be rewriten - $answer->feedback = $question->feedback[$key]['text']; - $answer->feedbackformat = $feedbackformat; - $answer->id = $DB->insert_record("question_answers", $answer); - - if (isset($feedbackfiles)) { - // import - foreach ($feedbackfiles as $file) { - $this->import_file($question->context, 'question', 'answerfeedback', $answer->id, $file); - } - } else { - // save draft file and rewrite text in feedback - $answer->feedback = file_save_draft_area_files($question->feedback[$key]['itemid'], $context->id, 'question', 'answerfeedback', $answer->id, self::$fileoptions, $question->feedback[$key]['text']); - } - // update feedback content - $DB->set_field('question_answers', 'feedback', $answer->feedback, array('id'=>$answer->id)); + $answer->answer = ''; + $answer->feedback = ''; + $answer->id = $DB->insert_record('question_answers', $answer); } + + $answer->answer = trim($answerdata); + $answer->fraction = $question->fraction[$key]; + $answer->feedback = $this->import_or_save_files($question->feedback[$key], + $context, 'question', 'answerfeedback', $answer->id); + $answer->feedbackformat = $question->feedback[$key]['format']; + $DB->update_record('question_answers', $answer); + $answers[] = $answer->id; if ($question->fraction[$key] > $maxfraction) { $maxfraction = $question->fraction[$key]; } } + // Delete any left over old answer records. + $fs = get_file_storage(); + foreach($oldanswers as $oldanswer) { + $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id); + $DB->delete_records('question_answers', array('id' => $oldanswer->id)); + } + $question->answers = implode(',', $answers); $parentresult = parent::save_question_options($question); - if($parentresult !== null) { // Parent function returns null if all is OK + if ($parentresult !== null) { + // Parent function returns null if all is OK return $parentresult; } - // delete old answer records - if (!empty($oldanswers)) { - foreach($oldanswers as $oa) { - $DB->delete_records('question_answers', array('id' => $oa->id)); - } + // Perform sanity checks on fractional grades + if ($maxfraction != 1) { + $result->noticeyesno = get_string('fractionsnomax', 'quiz', $maxfraction * 100); + return $result; } - /// Perform sanity checks on fractional grades - if ($maxfraction != 1) { - $maxfraction = $maxfraction * 100; - $result->noticeyesno = get_string("fractionsnomax", "quiz", $maxfraction); - return $result; - } else { - return true; - } + return true; } function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { diff --git a/question/type/truefalse/questiontype.php b/question/type/truefalse/questiontype.php index afcf468e041..d9620e3e0b8 100644 --- a/question/type/truefalse/questiontype.php +++ b/question/type/truefalse/questiontype.php @@ -35,99 +35,70 @@ class question_truefalse_qtype extends default_questiontype { function save_question_options($question) { global $DB; $result = new stdClass; + $context = $question->context; + + // Fetch old answer ids so that we can reuse them + $oldanswers = $DB->get_records('question_answers', + array('question' => $question->id), 'id ASC'); + + // Save the true answer - update an existing answer if possible. + $answer = array_shift($oldanswers); + if (!$answer) { + $answer = new stdClass(); + $answer->question = $question->id; + $answer->answer = ''; + $answer->feedback = ''; + $answer->id = $DB->insert_record('question_answers', $answer); + } + + $answer->answer = get_string('true', 'quiz'); + $answer->fraction = $question->correctanswer; + $answer->feedback = $this->import_or_save_files($question->feedbacktrue, + $context, 'question', 'answerfeedback', $answer->id); + $answer->feedbackformat = $question->feedbacktrue['format']; + $DB->update_record('question_answers', $answer); + $trueid = $answer->id; + + // Save the false answer - update an existing answer if possible. + $answer = array_shift($oldanswers); + if (!$answer) { + $answer = new stdClass(); + $answer->question = $question->id; + $answer->answer = ''; + $answer->feedback = ''; + $answer->id = $DB->insert_record('question_answers', $answer); + } + + $answer->answer = get_string('false', 'quiz'); + $answer->fraction = 1 - (int)$question->correctanswer; + $answer->feedback = $this->import_or_save_files($question->feedbackfalse, + $context, 'question', 'answerfeedback', $answer->id); + $answer->feedbackformat = $question->feedbackfalse['format']; + $DB->update_record('question_answers', $answer); + $falseid = $answer->id; + + // Delete any left over old answer records. $fs = get_file_storage(); - - // fetch old answer ids so that we can reuse them - if (!$oldanswers = $DB->get_records("question_answers", array("question" => $question->id), "id ASC")) { - $oldanswers = array(); - } - - $feedbacktext = $question->feedbacktrue['text']; - $feedbackitemid = $question->feedbacktrue['itemid']; - $feedbackformat = $question->feedbacktrue['format']; - if (isset($question->feedbacktruefiles)) { - $files = $question->feedbacktruefiles; - } - // Save answer 'True' - if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it - $true->answer = get_string("true", "quiz"); - $true->fraction = $question->correctanswer; - $true->feedback = $question->feedbacktrue; - $true->feedback = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $true->id, self::$fileoptions, $feedbacktext); - $true->feedbackformat = $feedbackformat; - $DB->update_record("question_answers", $true); - } else { - unset($true); - $true = new stdClass(); - $true->answer = get_string("true", "quiz"); - $true->question = $question->id; - $true->fraction = $question->correctanswer; - $true->feedback = ''; - $true->feedbackformat = $feedbackformat; - $true->id = $DB->insert_record("question_answers", $true); - // import - if (isset($files)) { - foreach ($files as $file) { - $this->import_file($question->context, 'question', 'answerfeedback', $true->id, $file); - } - } else { - // moodle form - $feedbacktext = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $true->id, self::$fileoptions, $feedbacktext); - } - $DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$true->id)); - } - - $feedbacktext = $question->feedbackfalse['text']; - $feedbackitemid = $question->feedbackfalse['itemid']; - $feedbackformat = $question->feedbackfalse['format']; - - // Save answer 'False' - if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it - $false->answer = get_string("false", "quiz"); - $false->fraction = 1 - (int)$question->correctanswer; - $false->feedback = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $false->id, self::$fileoptions, $feedbacktext); - $false->feedbackformat = $feedbackformat; - $DB->update_record("question_answers", $false); - } else { - unset($false); - $false = new stdClass(); - $false->answer = get_string("false", "quiz"); - $false->question = $question->id; - $false->fraction = 1 - (int)$question->correctanswer; - $false->feedback = ''; - $false->feedbackformat = $feedbackformat; - $false->id = $DB->insert_record("question_answers", $false); - if ($feedbackitemid == null && !empty($files)) { - foreach ($files as $file) { - $this->import_file($question->context, 'question', 'answerfeedback', $false->id, $file); - } - } else { - $feedbacktext = file_save_draft_area_files($feedbackitemid, $question->context->id, 'question', 'answerfeedback', $false->id, self::$fileoptions, $feedbacktext); - } - $DB->set_field('question_answers', 'feedback', $feedbacktext, array('id'=>$false->id)); - } - - // delete any leftover old answer records (there couldn't really be any, but who knows) - if (!empty($oldanswers)) { - foreach($oldanswers as $oa) { - $DB->delete_records('question_answers', array('id' => $oa->id)); - } + foreach($oldanswers as $oldanswer) { + $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id); + $DB->delete_records('question_answers', array('id' => $oldanswer->id)); } // Save question options in question_truefalse table - if ($options = $DB->get_record("question_truefalse", array("question" => $question->id))) { + if ($options = $DB->get_record('question_truefalse', array('question' => $question->id))) { // No need to do anything, since the answer IDs won't have changed // But we'll do it anyway, just for robustness - $options->trueanswer = $true->id; - $options->falseanswer = $false->id; - $DB->update_record("question_truefalse", $options); + $options->trueanswer = $trueid; + $options->falseanswer = $falseid; + $DB->update_record('question_truefalse', $options); } else { - unset($options); + $options = new stdClass(); $options->question = $question->id; - $options->trueanswer = $true->id; - $options->falseanswer = $false->id; - $DB->insert_record("question_truefalse", $options); + $options->trueanswer = $trueid; + $options->falseanswer = $falseid; + $DB->insert_record('question_truefalse', $options); } + return true; }