예제 #1
0
 public function test_import_match()
 {
     $xml = $this->make_test_xml();
     $importer = new qformat_blackboard_six();
     $questions = $importer->readquestions($xml);
     $q = $questions[5];
     // If qtype_ddmatch is installed, the formatter produces ddmatch
     // qtypes, not match ones.
     $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
     $expectedq = new stdClass();
     $expectedq->qtype = $ddmatchisinstalled ? 'ddmatch' : 'match';
     $expectedq->name = 'Classify the animals.';
     $expectedq->questiontext = '<i>Classify the animals.</i>';
     $expectedq->questiontextformat = FORMAT_HTML;
     $expectedq->correctfeedback = array('text' => '', 'format' => FORMAT_HTML);
     $expectedq->partiallycorrectfeedback = array('text' => '', 'format' => FORMAT_HTML);
     $expectedq->incorrectfeedback = array('text' => '', 'format' => FORMAT_HTML);
     $expectedq->generalfeedback = '';
     $expectedq->generalfeedbackformat = FORMAT_HTML;
     $expectedq->defaultmark = 1;
     $expectedq->length = 1;
     $expectedq->penalty = 0.3333333;
     $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
     $expectedq->subquestions = array(array('text' => 'cat', 'format' => FORMAT_HTML), array('text' => '', 'format' => FORMAT_HTML), array('text' => 'frog', 'format' => FORMAT_HTML), array('text' => 'newt', 'format' => FORMAT_HTML));
     if ($ddmatchisinstalled) {
         $expectedq->subanswers = array(array('text' => 'mammal', 'format' => FORMAT_HTML), array('text' => 'insect', 'format' => FORMAT_HTML), array('text' => 'amphibian', 'format' => FORMAT_HTML), array('text' => 'amphibian', 'format' => FORMAT_HTML));
     } else {
         $expectedq->subanswers = array('mammal', 'insect', 'amphibian', 'amphibian');
     }
     $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 }
예제 #2
0
/**
 * Private function to factor common code out of get_question_options().
 *
 * @param object $question the question to tidy.
 * @param boolean $loadtags load the question tags from the tags table. Optional, default false.
 */
function _tidy_question($question, $loadtags = false)
{
    global $CFG;
    // Load question-type specific fields.
    if (!question_bank::is_qtype_installed($question->qtype)) {
        $question->questiontext = html_writer::tag('p', get_string('warningmissingtype', 'qtype_missingtype')) . $question->questiontext;
    }
    question_bank::get_qtype($question->qtype)->get_question_options($question);
    // Convert numeric fields to float. (Prevents these being displayed as 1.0000000.)
    $question->defaultmark += 0;
    $question->penalty += 0;
    if (isset($question->_partiallyloaded)) {
        unset($question->_partiallyloaded);
    }
    if ($loadtags && !empty($CFG->usetags)) {
        require_once $CFG->dirroot . '/tag/lib.php';
        $question->tags = tag_get_tags_array('question', $question->id);
    }
}
예제 #3
0
 /**
  * Process Matching Questions
  * Parse a matching rawquestion and add the result
  * to the array of questions already parsed.
  * @param object $quest rawquestion
  * @param array $questions array of Moodle questions already done.
  */
 public function process_matching($quest, &$questions)
 {
     // Blackboard matching questions can't be imported in core Moodle without a loss in data,
     // as core match question don't allow HTML in subanswers. The contributed ddmatch
     // question type support HTML in subanswers.
     // The ddmatch question type is not part of core, so we need to check if it is defined.
     $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
     $question = $this->process_common($quest);
     $question = $this->add_blank_combined_feedback($question);
     $question->valid = true;
     if ($ddmatchisinstalled) {
         $question->qtype = 'ddmatch';
     } else {
         $question->qtype = 'match';
     }
     // Construction of the array holding mappings between subanswers and subquestions.
     foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
         foreach ($quest->responses as $rid => $resp) {
             if (isset($resp->ident) && $resp->ident == $subq->ident) {
                 $correct = $resp->correct;
             }
         }
         foreach ($subq->choices as $cid => $choice) {
             if ($choice == $correct) {
                 $mappings[$subq->ident] = $cid;
             }
         }
     }
     foreach ($subq->choices as $choiceid => $choice) {
         $subanswertext = $quest->RIGHT_MATCH_BLOCK->matchinganswerset[$choiceid]->text;
         if ($ddmatchisinstalled) {
             $subanswer = $this->cleaned_text_field($subanswertext);
         } else {
             $subanswertext = html_to_text($this->cleaninput($subanswertext), 0);
             $subanswer = $subanswertext;
         }
         if ($subanswertext != '') {
             // Only import non empty subanswers.
             $subquestion = '';
             $fiber = array_keys($mappings, $choiceid);
             foreach ($fiber as $correctanswerid) {
                 // We have found a correspondance for this subanswer so we need to take the associated subquestion.
                 foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
                     $currentsubqid = $subq->ident;
                     if (strcmp($currentsubqid, $correctanswerid) == 0) {
                         $subquestion = $subq->text;
                         break;
                     }
                 }
                 $question->subquestions[] = $this->cleaned_text_field($subquestion);
                 $question->subanswers[] = $subanswer;
             }
             if ($subquestion == '') {
                 // Then in this case, $choice is a distractor.
                 $question->subquestions[] = $this->text_field('');
                 $question->subanswers[] = $subanswer;
             }
         }
     }
     // Verify that this matching question has enough subquestions and subanswers.
     $subquestioncount = 0;
     $subanswercount = 0;
     $subanswers = $question->subanswers;
     foreach ($question->subquestions as $key => $subquestion) {
         $subquestion = $subquestion['text'];
         $subanswer = $subanswers[$key];
         if ($subquestion != '') {
             $subquestioncount++;
         }
         $subanswercount++;
     }
     if ($subquestioncount < 2 || $subanswercount < 3) {
         $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext));
     } else {
         $questions[] = $question;
     }
 }
 function process_matching($quest, &$questions)
 {
     // renderedmatch is an optional plugin, so we need to check if it is defined
     if (question_bank::is_qtype_installed('renderedmatch')) {
         $question = $this->process_common($quest);
         $question->valid = true;
         $question->qtype = 'renderedmatch';
         foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
             foreach ($quest->responses as $rid => $resp) {
                 if ($resp->ident == $subq->ident) {
                     $correct = $resp->correct;
                     $feedback = $resp->feedback;
                 }
             }
             foreach ($subq->choices as $cid => $choice) {
                 if ($choice == $correct) {
                     $question->subquestions[] = $subq->text;
                     $question->subanswers[] = $quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text;
                 }
             }
         }
         // check format
         $status = true;
         if (count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {
             $status = false;
         } else {
             // need to redo to make sure that no two questions have the same answer (rudimentary now)
             foreach ($question->subanswers as $qstn) {
                 if (isset($previous)) {
                     if ($qstn == $previous) {
                         $status = false;
                     }
                 }
                 $previous = $qstn;
                 if ($qstn == '') {
                     $status = false;
                 }
             }
         }
         if ($status) {
             $questions[] = $question;
         } else {
             global $COURSE, $CFG;
             print '<table class="boxaligncenter" border="1">';
             print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>';
             print "<tr><td>Question:</td><td>" . $quest->QUESTION_BLOCK->text;
             if (isset($quest->QUESTION_BLOCK->file)) {
                 print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/' . basename($quest->QUESTION_BLOCK->file) . '</font>';
                 if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {
                     print '<img src="' . $CFG->wwwroot . '/file.php/' . $COURSE->id . '/bb_import/' . basename($quest->QUESTION_BLOCK->file) . '" />';
                 }
             }
             print "</td></tr>";
             print "<tr><td>Subquestions:</td><td><ul>";
             foreach ($quest->responses as $rs) {
                 $correct_responses->{$rs->ident} = $rs->correct;
             }
             foreach ($quest->RESPONSE_BLOCK->subquestions as $subq) {
                 print '<li>' . $subq->text . '<ul>';
                 foreach ($subq->choices as $id => $choice) {
                     print '<li>';
                     if ($choice == $correct_responses->{$subq->ident}) {
                         print '<font color="green">';
                     } else {
                         print '<font color="red">';
                     }
                     print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text . '</font></li>';
                 }
                 print '</ul>';
             }
             print '</ul></td></tr>';
             print '<tr><td>Feedback:</td><td><ul>';
             foreach ($quest->feedback as $fb) {
                 print '<li>' . $fb->ident . ': ' . $fb->text . '</li>';
             }
             print '</ul></td></tr></table>';
         }
     } else {
         print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";
         print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: " . $quest->QUESTION_BLOCK->text . '<br/><br/>';
     }
 }
예제 #5
0
/**
 * Private function to factor common code out of get_question_options().
 *
 * @param object $question the question to tidy.
 * @param boolean $loadtags load the question tags from the tags table. Optional, default false.
 */
function _tidy_question($question, $loadtags = false)
{
    global $CFG;
    if (!question_bank::is_qtype_installed($question->qtype)) {
        $question->questiontext = html_writer::tag('p', get_string('warningmissingtype', 'qtype_missingtype')) . $question->questiontext;
    }
    question_bank::get_qtype($question->qtype)->get_question_options($question);
    if (isset($question->_partiallyloaded)) {
        unset($question->_partiallyloaded);
    }
    if ($loadtags && !empty($CFG->usetags)) {
        require_once $CFG->dirroot . '/tag/lib.php';
        $question->tags = tag_get_tags_array('question', $question->id);
    }
}
예제 #6
0
 /**
  * Process Matching Questions
  * @param array $xml the xml tree
  * @param array $questions the questions already parsed
  */
 public function process_matching($xml, &$questions)
 {
     if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MATCH'), false, false)) {
         $matchquestions = $this->getpath($xml, array('POOL', '#', 'QUESTION_MATCH'), false, false);
     } else {
         return;
     }
     // Blackboard questions can't be imported in core Moodle without a loss in data,
     // as core match question don't allow HTML in subanswers. The contributed ddmatch
     // question type support HTML in subanswers.
     // The ddmatch question type is not part of core, so we need to check if it is defined.
     $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
     foreach ($matchquestions as $thisquestion) {
         $question = $this->process_common($thisquestion);
         if ($ddmatchisinstalled) {
             $question->qtype = 'ddmatch';
         } else {
             $question->qtype = 'match';
         }
         $correctfeedback = $this->getpath($thisquestion, array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'), '', true);
         $incorrectfeedback = $this->getpath($thisquestion, array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'), '', true);
         $question->correctfeedback = $this->cleaned_text_field($correctfeedback);
         // As there is no partially correct feedback we use incorrect one.
         $question->partiallycorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
         $question->incorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
         $choices = $this->getpath($thisquestion, array('#', 'CHOICE'), false, false);
         // Blackboard "choices" are Moodle subanswers.
         $answers = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
         // Blackboard "answers" are Moodle subquestions.
         $correctanswers = $this->getpath($thisquestion, array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false);
         // Mapping between choices and answers.
         $mappings = array();
         foreach ($correctanswers as $correctanswer) {
             if ($correctanswer) {
                 $correctchoiceid = $this->getpath($correctanswer, array('@', 'choice_id'), '', true);
                 $correctanswerid = $this->getpath($correctanswer, array('@', 'answer_id'), '', true);
                 $mappings[$correctanswerid] = $correctchoiceid;
             }
         }
         foreach ($choices as $choice) {
             if ($ddmatchisinstalled) {
                 $choicetext = $this->cleaned_text_field($this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true));
             } else {
                 $choicetext = trim(strip_tags($this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true)));
             }
             if ($choicetext != '') {
                 // Only import non empty subanswers.
                 $subquestion = '';
                 $choiceid = $this->getpath($choice, array('@', 'id'), '', true);
                 $fiber = array_search($choiceid, $mappings);
                 $fiber = array_keys($mappings, $choiceid);
                 foreach ($fiber as $correctanswerid) {
                     // We have found a correspondance for this choice so we need to take the associated answer.
                     foreach ($answers as $answer) {
                         $currentanswerid = $this->getpath($answer, array('@', 'id'), '', true);
                         if (strcmp($currentanswerid, $correctanswerid) == 0) {
                             $subquestion = $this->getpath($answer, array('#', 'TEXT', 0, '#'), '', true);
                             break;
                         }
                     }
                     $question->subquestions[] = $this->cleaned_text_field($subquestion);
                     $question->subanswers[] = $choicetext;
                 }
                 if ($subquestion == '') {
                     // Then in this case, $choice is a distractor.
                     $question->subquestions[] = $this->text_field('');
                     $question->subanswers[] = $choicetext;
                 }
             }
         }
         // Verify that this matching question has enough subquestions and subanswers.
         $subquestioncount = 0;
         $subanswercount = 0;
         $subanswers = $question->subanswers;
         foreach ($question->subquestions as $key => $subquestion) {
             $subquestion = $subquestion['text'];
             $subanswer = $subanswers[$key];
             if ($subquestion != '') {
                 $subquestioncount++;
             }
             $subanswercount++;
         }
         if ($subquestioncount < 2 || $subanswercount < 3) {
             $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext));
         } else {
             $questions[] = $question;
         }
     }
 }