MDL-14625 more tolerant to missing subquestions merged from HEAD
This commit is contained in:
@@ -32,8 +32,13 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||
$this->questiondisplay = "";
|
||||
}
|
||||
|
||||
if ( isset($this->questiondisplay->options->questions) && count($this->questiondisplay->options->questions) > 0 ) {
|
||||
$countsubquestions = count($this->questiondisplay->options->questions);
|
||||
if ( isset($this->questiondisplay->options->questions) && is_array($this->questiondisplay->options->questions) ) {
|
||||
$countsubquestions =0;
|
||||
foreach($this->questiondisplay->options->questions as $subquestion){
|
||||
if ($subquestion != ''){
|
||||
$countsubquestions++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$countsubquestions =0;
|
||||
}
|
||||
@@ -83,6 +88,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||
if (isset($question->id) and $question->id and $question->qtype and $question->questiontext) {
|
||||
|
||||
foreach ($question->options->questions as $key => $wrapped) {
|
||||
if($wrapped != ''){
|
||||
// The old way of restoring the definitions is kept to gradually
|
||||
// update all multianswer questions
|
||||
if (empty($wrapped->questiontext)) {
|
||||
@@ -126,6 +132,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||
$question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set default to $questiondisplay questions elements
|
||||
if (isset($this->questiondisplay->options->questions)) {
|
||||
@@ -230,7 +237,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
||||
$sub++;
|
||||
}
|
||||
} else {
|
||||
$errors['questiontext']=get_string('questions missing', 'question');
|
||||
$errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,9 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
|
||||
// Get relevant data indexed by positionkey from the multianswers table
|
||||
if (!$sequence = get_field('question_multianswer', 'sequence', 'question', $question->id)) {
|
||||
notify('Error: Cloze question '.$question->id.' is missing question options!');
|
||||
return false;
|
||||
notify(get_string('noquestions','qtype_multianswer',$question->name));
|
||||
$question->options->questions['1']= '';
|
||||
return true ;
|
||||
}
|
||||
|
||||
$wrappedquestions = get_records_list('question', 'id', $sequence, 'id ASC');
|
||||
@@ -37,17 +38,31 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
// We want an array with question ids as index and the positions as values
|
||||
$sequence = array_flip(explode(',', $sequence));
|
||||
array_walk($sequence, create_function('&$val', '$val++;'));
|
||||
|
||||
//If a question is lost, the corresponding index is null
|
||||
// so this null convention is used to test $question->options->questions
|
||||
// before using the values.
|
||||
// first all possible questions from sequence are nulled
|
||||
// then filled with the data if available in $wrappedquestions
|
||||
$nbvaliquestion = 0 ;
|
||||
foreach($sequence as $seq){
|
||||
$question->options->questions[$seq]= '';
|
||||
}
|
||||
if (isset($wrappedquestions) && is_array($wrappedquestions)){
|
||||
foreach ($wrappedquestions as $wrapped) {
|
||||
if (!$QTYPES[$wrapped->qtype]->get_question_options($wrapped)) {
|
||||
notify("Unable to get options for questiontype {$wrapped->qtype} (id={$wrapped->id})");
|
||||
}
|
||||
}else {
|
||||
// for wrapped questions the maxgrade is always equal to the defaultgrade,
|
||||
// there is no entry in the question_instances table for them
|
||||
$wrapped->maxgrade = $wrapped->defaultgrade;
|
||||
|
||||
$nbvaliquestion++ ;
|
||||
$question->options->questions[$sequence[$wrapped->id]] = clone($wrapped); // ??? Why do we need a clone here?
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($nbvaliquestion == 0 ) {
|
||||
notify(get_string('noquestions','qtype_multianswer',$question->name));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -65,31 +80,36 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
|
||||
// First we get all the existing wrapped questions
|
||||
if (!$oldwrappedids = get_field('question_multianswer', 'sequence', 'question', $question->id)) {
|
||||
$oldwrappedids = array();
|
||||
$oldwrappedquestions = array();
|
||||
} else {
|
||||
$oldwrappedids = explode(',', $oldwrappedids);
|
||||
$oldwrappedquestions = get_records_list('question', 'id', $oldwrappedids, 'id ASC');
|
||||
}
|
||||
$sequence = array();
|
||||
foreach($question->options->questions as $wrapped) {
|
||||
if ($wrapped != ''){
|
||||
// if we still have some old wrapped question ids, reuse the next of them
|
||||
if ($oldwrappedid = array_shift($oldwrappedids)) {
|
||||
$wrapped->id = $oldwrappedid;
|
||||
$oldqtype = get_field('question', 'qtype', 'id',$oldwrappedid) ;
|
||||
if($oldqtype != $wrapped->qtype ) {
|
||||
switch ($oldqtype) {
|
||||
|
||||
if (is_array($oldwrappedquestions) && $oldwrappedquestion = array_shift($oldwrappedquestions)) {
|
||||
$wrapped->id = $oldwrappedquestion->id;
|
||||
if($oldwrappedquestion->qtype != $wrapped->qtype ) {
|
||||
switch ($oldwrappedquestion->qtype) {
|
||||
case 'multichoice':
|
||||
delete_records('question_multichoice', 'question', $oldwrappedid);
|
||||
delete_records('question_multichoice', 'question' , $oldwrappedquestion->id );
|
||||
break;
|
||||
case 'shortanswer':
|
||||
delete_records('question_shortanswer', 'question', $oldwrappedid);
|
||||
delete_records('question_shortanswer', 'question' , $oldwrappedquestion->id );
|
||||
break;
|
||||
case 'numerical':
|
||||
delete_records('question_numerical', 'question', $oldwrappedid);
|
||||
delete_records('question_numerical', 'question' , $oldwrappedquestion->id );
|
||||
break;
|
||||
default:
|
||||
error("questiontype $wrapped->qtype not recognized");
|
||||
$wrapped->id = 0 ;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
$wrapped->id = 0 ;
|
||||
}
|
||||
}
|
||||
$wrapped->name = $question->name;
|
||||
$wrapped->parent = $question->id;
|
||||
@@ -197,6 +217,7 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
global $QTYPES;
|
||||
$responses = array();
|
||||
foreach($question->options->questions as $key => $wrapped) {
|
||||
if ($wrapped != ''){
|
||||
if ($correct = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state)) {
|
||||
$responses[$key] = $correct[''];
|
||||
} else {
|
||||
@@ -206,6 +227,7 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $responses;
|
||||
}
|
||||
|
||||
@@ -247,9 +269,10 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
$qtextremaining = $qtextsplits[1];
|
||||
|
||||
$positionkey = $regs[1];
|
||||
if (isset($question->options->questions[$positionkey]) && $question->options->questions[$positionkey] != ''){
|
||||
$wrapped = &$question->options->questions[$positionkey];
|
||||
$answers = &$wrapped->options->answers;
|
||||
$correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state);
|
||||
// $correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $state);
|
||||
|
||||
$inputname = $nameprefix.$positionkey;
|
||||
if (isset($state->responses[$positionkey])) {
|
||||
@@ -262,6 +285,38 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
$popup = '';
|
||||
$style = '';
|
||||
$feedbackimg = '';
|
||||
$feedback = '' ;
|
||||
$correctanswer = '';
|
||||
$strfeedbackwrapped = $strfeedback;
|
||||
// if($wrapped->qtype == 'numerical' ||$wrapped->qtype == 'shortanswer'){
|
||||
$testedstate = clone($state);
|
||||
if ($correctanswers = $QTYPES[$wrapped->qtype]->get_correct_responses($wrapped, $testedstate)) {
|
||||
if ($options->readonly && $options->correct_responses) {
|
||||
$delimiter = '';
|
||||
if ($correctanswers) {
|
||||
foreach ($correctanswers as $ca) {
|
||||
switch($wrapped->qtype){
|
||||
case 'numerical':
|
||||
case 'shortanswer':
|
||||
$correctanswer .= $delimiter.$ca;
|
||||
break ;
|
||||
case 'multichoice':
|
||||
if (isset($answers[$ca])){
|
||||
$correctanswer .= $delimiter.$answers[$ca]->answer;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
$delimiter = ', ';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($correctanswer) {
|
||||
$feedback = '<div class="correctness">';
|
||||
$feedback .= get_string('correctansweris', 'quiz', s($correctanswer, true));
|
||||
$feedback .= '</div>';
|
||||
// $strfeedbackwrapped = get_string('correctanswer and', 'quiz').get_string('feedback', 'quiz');
|
||||
}
|
||||
}
|
||||
if ($options->feedback) {
|
||||
$chosenanswer = null;
|
||||
switch ($wrapped->qtype) {
|
||||
@@ -294,8 +349,13 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
}
|
||||
|
||||
if (!empty($chosenanswer->feedback)) {
|
||||
$feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $chosenanswer->feedback));
|
||||
$popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedback', FGCOLOR, '#FFFFFF');\" ".
|
||||
$feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback.$chosenanswer->feedback));
|
||||
if ($options->readonly && $options->correct_responses) {
|
||||
$strfeedbackwrapped = get_string('correctanswerandfeedback', 'qtype_multianswer');
|
||||
}else {
|
||||
$strfeedbackwrapped = get_string('feedback', 'quiz');
|
||||
}
|
||||
$popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedbackwrapped', FGCOLOR, '#FFFFFF');\" ".
|
||||
" onmouseout=\"return nd();\" ";
|
||||
}
|
||||
|
||||
@@ -308,6 +368,12 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
$feedbackimg = '';
|
||||
}
|
||||
}
|
||||
if ($feedback !='' && $popup == ''){
|
||||
$strfeedbackwrapped = get_string('correctanswer', 'qtype_multianswer');
|
||||
$feedback = s(str_replace(array("\\", "'"), array("\\\\", "\\'"), $feedback));
|
||||
$popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedbackwrapped', FGCOLOR, '#FFFFFF');\" ".
|
||||
" onmouseout=\"return nd();\" ";
|
||||
}
|
||||
|
||||
// Print the input control
|
||||
switch ($wrapped->qtype) {
|
||||
@@ -384,6 +450,14 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
}
|
||||
echo "</label>"; // MDL-7497
|
||||
}
|
||||
else {
|
||||
if(! isset($question->options->questions[$positionkey])){
|
||||
echo $regs[0]."</label>";
|
||||
}else {
|
||||
echo '</label><div class="error" >'.get_string('questionnotfound','qtype_multianswer',$positionkey).'</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print the final piece of question text:
|
||||
echo $qtextremaining;
|
||||
@@ -396,6 +470,7 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
$teststate = clone($state);
|
||||
$state->raw_grade = 0;
|
||||
foreach($question->options->questions as $key => $wrapped) {
|
||||
if ($wrapped != ''){
|
||||
$state->responses[$key] = $state->responses[$key];
|
||||
$teststate->responses = array('' => $state->responses[$key]);
|
||||
$teststate->raw_grade = 0;
|
||||
@@ -405,6 +480,7 @@ class embedded_cloze_qtype extends default_questiontype {
|
||||
}
|
||||
$state->raw_grade += $teststate->raw_grade;
|
||||
}
|
||||
}
|
||||
$state->raw_grade /= $question->defaultgrade;
|
||||
$state->raw_grade = min(max((float) $state->raw_grade, 0.0), 1.0)
|
||||
* $question->maxgrade;
|
||||
@@ -724,6 +800,7 @@ function qtype_multianswer_extract_question($text) {
|
||||
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE])) {
|
||||
$wrapped->qtype = 'multichoice';
|
||||
$wrapped->single = 1;
|
||||
$wrapped->answernumbering = 0;
|
||||
$wrapped->correctfeedback = '';
|
||||
$wrapped->partiallycorrectfeedback = '';
|
||||
$wrapped->incorrectfeedback = '';
|
||||
|
||||
Reference in New Issue
Block a user