class qformat_blackboard_6 in Quiz 6.6
Same name and namespace in other branches
- 6.5 includes/moodle/question/format/blackboard_6/format.php \qformat_blackboard_6
Hierarchy
- class \qformat_default
- class \qformat_blackboard_6
Expanded class hierarchy of qformat_blackboard_6
File
- includes/
moodle/ question/ format/ blackboard_6/ format.php, line 18
View source
class qformat_blackboard_6 extends qformat_default {
function provide_import() {
return true;
}
//Function to check and create the needed dir to unzip file to
function check_and_create_import_dir($unique_code) {
global $CFG;
$status = $this
->check_dir_exists($CFG->dataroot . "/temp", true);
if ($status) {
$status = $this
->check_dir_exists($CFG->dataroot . "/temp/bbquiz_import", true);
}
if ($status) {
$status = $this
->check_dir_exists($CFG->dataroot . "/temp/bbquiz_import/" . $unique_code, true);
}
return $status;
}
function clean_temp_dir($dir = '') {
// for now we will just say everything happened okay note
// that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import
// TODO return true at top of the function renders all the following code useless
return true;
if ($dir == '') {
$dir = $this->temp_dir;
}
$slash = "/";
// Create arrays to store files and directories
$dir_files = array();
$dir_subdirs = array();
// Make sure we can delete it
chmod($dir, 0777);
if (($handle = opendir($dir)) == FALSE) {
// The directory could not be opened
return false;
}
// Loop through all directory entries, and construct two temporary arrays containing files and sub directories
while (false !== ($entry = readdir($handle))) {
if (is_dir($dir . $slash . $entry) && $entry != ".." && $entry != ".") {
$dir_subdirs[] = $dir . $slash . $entry;
}
else {
if ($entry != ".." && $entry != ".") {
$dir_files[] = $dir . $slash . $entry;
}
}
}
// Delete all files in the curent directory return false and halt if a file cannot be removed
for ($i = 0; $i < count($dir_files); $i++) {
chmod($dir_files[$i], 0777);
if (unlink($dir_files[$i]) == FALSE) {
return false;
}
}
// Empty sub directories and then remove the directory
for ($i = 0; $i < count($dir_subdirs); $i++) {
chmod($dir_subdirs[$i], 0777);
if ($this
->clean_temp_dir($dir_subdirs[$i]) == FALSE) {
return false;
}
else {
if (rmdir($dir_subdirs[$i]) == FALSE) {
return false;
}
}
}
// Close directory
closedir($handle);
if (rmdir($this->temp_dir) == FALSE) {
return false;
}
// Success, every thing is gone return true
return true;
}
//Function to check if a directory exists and, optionally, create it
function check_dir_exists($dir, $create = false) {
global $CFG;
$status = true;
if (!is_dir($dir)) {
if (!$create) {
$status = false;
}
else {
umask(00);
$status = mkdir($dir, $CFG->directorypermissions);
}
}
return $status;
}
function importpostprocess() {
/// Does any post-processing that may be desired
/// Argument is a simple array of question ids that
/// have just been added.
// need to clean up temporary directory
return $this
->clean_temp_dir();
}
function copy_file_to_course($filename) {
global $CFG, $COURSE;
$filename = str_replace('\\', '/', $filename);
$fullpath = $this->temp_dir . '/res00001/' . $filename;
$basename = basename($filename);
$copy_to = $CFG->dataroot . '/' . $COURSE->id . '/bb_import';
if ($this
->check_dir_exists($copy_to, true)) {
if (is_readable($fullpath)) {
$copy_to .= '/' . $basename;
if (!copy($fullpath, $copy_to)) {
return false;
}
else {
return $copy_to;
}
}
}
else {
return false;
}
}
function readdata($filename) {
/// Returns complete file with an array, one item per line
global $CFG;
// if the extension is .dat we just return that,
// if .zip we unzip the file and get the data
$ext = substr($this->realfilename, strpos($this->realfilename, '.'), strlen($this->realfilename) - 1);
if ($ext == '.dat') {
if (!is_readable($filename)) {
error("File is not readable");
}
return file($filename);
}
$unique_code = time();
$temp_dir = $CFG->dataroot . "/temp/bbquiz_import/" . $unique_code;
$this->temp_dir = $temp_dir;
if ($this
->check_and_create_import_dir($unique_code)) {
if (is_readable($filename)) {
if (!copy($filename, "{$temp_dir}/bboard.zip")) {
error("Could not copy backup file");
}
if (unzip_file("{$temp_dir}/bboard.zip", '', false)) {
// assuming that the information is in res0001.dat
// after looking at 6 examples this was always the case
$q_file = "{$temp_dir}/res00001.dat";
if (is_file($q_file)) {
if (is_readable($q_file)) {
$filearray = file($q_file);
/// Check for Macintosh OS line returns (ie file on one line), and fix
if (ereg("\r", $filearray[0]) and !ereg("\n", $filearray[0])) {
return explode("\r", $filearray[0]);
}
else {
return $filearray;
}
}
}
else {
error("Could not find question data file in zip");
}
}
else {
print "filename: {$filename}<br />tempdir: {$temp_dir} <br />";
error("Could not unzip file.");
}
}
else {
error("Could not read uploaded file");
}
}
else {
error("Could not create temporary directory");
}
}
function save_question_options($question) {
return true;
}
function readquestions($lines) {
/// Parses an array of lines into an array of questions,
/// where each item is a question object as defined by
/// readquestion().
$text = implode($lines, " ");
$xml = xmlize($text, 0);
$raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];
$questions = array();
foreach ($raw_questions as $quest) {
$question = $this
->create_raw_question($quest);
switch ($question->qtype) {
case "Matching":
$this
->process_matching($question, $questions);
break;
case "Multiple Choice":
$this
->process_mc($question, $questions);
break;
case "Essay":
$this
->process_essay($question, $questions);
break;
case "Multiple Answer":
$this
->process_ma($question, $questions);
break;
case "True/False":
$this
->process_tf($question, $questions);
break;
case 'Fill in the Blank':
$this
->process_fblank($question, $questions);
break;
case 'Short Response':
$this
->process_essay($question, $questions);
break;
default:
print "Unknown or unhandled question type: \"{$question->qtype}\"<br />";
break;
}
}
return $questions;
}
// creates a cleaner object to deal with for processing into moodle
// the object created is NOT a moodle question object
function create_raw_question($quest) {
$question = new StdClass();
$question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];
$question->id = $quest['#']['itemmetadata'][0]['#']['bbmd_asi_object_id'][0]['#'];
$presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];
foreach ($presentation->blocks as $pblock) {
$block = NULL;
$block->type = $pblock['@']['class'];
switch ($block->type) {
case 'QUESTION_BLOCK':
$sub_blocks = $pblock['#']['flow'];
foreach ($sub_blocks as $sblock) {
//echo "Calling process_block from line 263<br>";
$this
->process_block($sblock, $block);
}
break;
case 'RESPONSE_BLOCK':
$choices = NULL;
switch ($question->qtype) {
case 'Matching':
$bb_subquestions = $pblock['#']['flow'];
$sub_questions = array();
foreach ($bb_subquestions as $bb_subquestion) {
$sub_question = NULL;
$sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];
$this
->process_block($bb_subquestion['#']['flow'][0], $sub_question);
$bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
$choices = array();
$this
->process_choices($bb_choices, $choices);
$sub_question->choices = $choices;
if (!isset($block->subquestions)) {
$block->subquestions = array();
}
$block->subquestions[] = $sub_question;
}
break;
case 'Multiple Answer':
$bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
$choices = array();
$this
->process_choices($bb_choices, $choices);
$block->choices = $choices;
break;
case 'Essay':
// Doesn't apply since the user responds with text input
break;
case 'Multiple Choice':
$mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
foreach ($mc_choices as $mc_choice) {
$choices = NULL;
$choices = $this
->process_block($mc_choice, $choices);
$block->choices[] = $choices;
}
break;
case 'Short Response':
// do nothing?
break;
case 'Fill in the Blank':
// do nothing?
break;
case 'Fill in the Blank Plus':
// do nothing?
break;
case 'Numeric':
// do nothing?
break;
default:
$bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
$choices = array();
$this
->process_choices($bb_choices, $choices);
$block->choices = $choices;
}
break;
case 'RIGHT_MATCH_BLOCK':
$matching_answerset = $pblock['#']['flow'];
$answerset = array();
foreach ($matching_answerset as $answer) {
// $answerset[] = $this->process_block($answer, $bb_answer);
$bb_answer = null;
$bb_answer->text = $answer['#']['flow'][0]['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
$answerset[] = $bb_answer;
}
$block->matching_answerset = $answerset;
break;
default:
print "UNHANDLED PRESENTATION BLOCK";
break;
}
$question->{$block->type} = $block;
}
// determine response processing
// there is a section called 'outcomes' that I don't know what to do with
$resprocessing = $quest['#']['resprocessing'];
$respconditions = $resprocessing[0]['#']['respcondition'];
$responses = array();
if ($question->qtype == 'Matching') {
$this
->process_matching_responses($respconditions, $responses);
}
else {
$this
->process_responses($respconditions, $responses);
}
$question->responses = $responses;
$feedbackset = $quest['#']['itemfeedback'];
$feedbacks = array();
$this
->process_feedback($feedbackset, $feedbacks);
$question->feedback = $feedbacks;
return $question;
}
function process_block($cur_block, &$block) {
global $COURSE, $CFG;
$cur_type = $cur_block['@']['class'];
switch ($cur_type) {
case 'FORMATTED_TEXT_BLOCK':
$block->text = $this
->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']);
break;
case 'FILE_BLOCK':
//revisit this to make sure it is working correctly
// Commented out ['matapplication']..., etc. because I
// noticed that when I imported a new Blackboard 6 file
// and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06
$block->file = $cur_block['#']['material'][0]['#'];
//['matapplication'][0]['@']['uri'];
if ($block->file != '') {
// if we have a file copy it to the course dir and adjust its name to be visible over the web.
$block->file = $this
->copy_file_to_course($block->file);
$block->file = $CFG->wwwroot . '/file.php/' . $COURSE->id . '/bb_import/' . basename($block->file);
}
break;
case 'Block':
if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {
$block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];
}
else {
if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {
$block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
}
else {
if (isset($cur_block['#']['response_label'])) {
// this is a response label block
$sub_blocks = $cur_block['#']['response_label'][0];
if (!isset($block->ident)) {
if (isset($sub_blocks['@']['ident'])) {
$block->ident = $sub_blocks['@']['ident'];
}
}
foreach ($sub_blocks['#']['flow_mat'] as $sub_block) {
$this
->process_block($sub_block, $block);
}
}
else {
if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {
if (isset($cur_block['#']['flow_mat'])) {
$sub_blocks = $cur_block['#']['flow_mat'];
}
elseif (isset($cur_block['#']['flow'])) {
$sub_blocks = $cur_block['#']['flow'];
}
foreach ($sub_blocks as $sblock) {
// this will recursively grab the sub blocks which should be of one of the other types
$this
->process_block($sblock, $block);
}
}
}
}
}
break;
case 'LINK_BLOCK':
// not sure how this should be included
if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {
$block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];
}
else {
$block->link = '';
}
break;
}
return $block;
}
function process_choices($bb_choices, &$choices) {
foreach ($bb_choices as $choice) {
if (isset($choice['@']['ident'])) {
$cur_choice = $choice['@']['ident'];
}
else {
//for multiple answer
$cur_choice = $choice['#']['response_label'][0];
//['@']['ident'];
}
if (isset($choice['#']['flow_mat'][0])) {
//for multiple answer
$cur_block = $choice['#']['flow_mat'][0];
// Reset $cur_choice to NULL because process_block is expecting an object
// for the second argument and not a string, which is what is was set as
// originally - CT 8/7/06
$cur_choice = null;
$this
->process_block($cur_block, $cur_choice);
}
elseif (isset($choice['#']['response_label'])) {
// Reset $cur_choice to NULL because process_block is expecting an object
// for the second argument and not a string, which is what is was set as
// originally - CT 8/7/06
$cur_choice = null;
$this
->process_block($choice, $cur_choice);
}
$choices[] = $cur_choice;
}
}
function process_matching_responses($bb_responses, &$responses) {
foreach ($bb_responses as $bb_response) {
$response = NULL;
if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {
$response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];
$response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];
}
else {
$response->correct = 'Broken Question?';
$response->ident = 'Broken Question?';
}
$response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
$responses[] = $response;
}
}
function process_responses($bb_responses, &$responses) {
foreach ($bb_responses as $bb_response) {
//Added this line to instantiate $response.
// Without instantiating the $response variable, the same object
// gets added to the array
$response = null;
if (isset($bb_response['@']['title'])) {
$response->title = $bb_response['@']['title'];
}
else {
$reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
}
$reponse->ident = array();
if (isset($bb_response['#']['conditionvar'][0]['#'])) {
//['varequal'][0]['#'])) {
$response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];
//['varequal'][0]['#'];
}
else {
if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {
$response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];
}
}
if (isset($bb_response['#']['conditionvar'][0]['#']['and'])) {
//[0]['#'])) {
$responseset = $bb_response['#']['conditionvar'][0]['#']['and'];
//[0]['#']['varequal'];
foreach ($responseset as $rs) {
$response->ident[] = $rs['#'];
if (!isset($response->feedback) and isset($rs['@'])) {
$response->feedback = $rs['@']['respident'];
}
}
}
else {
$response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
}
// determine what point value to give response
if (isset($bb_response['#']['setvar'])) {
switch ($bb_response['#']['setvar'][0]['#']) {
case "SCORE.max":
$response->fraction = 1;
break;
default:
// I have only seen this being 0 or unset
// there are probably fractional values of SCORE.max, but I'm not sure what they look like
$response->fraction = 0;
break;
}
}
else {
// just going to assume this is the case this is probably not correct.
$response->fraction = 0;
}
$responses[] = $response;
}
}
function process_feedback($feedbackset, &$feedbacks) {
foreach ($feedbackset as $bb_feedback) {
// Added line $feedback=null so that $feedback does not get reused in the loop
// and added the the $feedbacks[] array multiple times
$feedback = null;
$feedback->ident = $bb_feedback['@']['ident'];
if (isset($bb_feedback['#']['flow_mat'][0])) {
$this
->process_block($bb_feedback['#']['flow_mat'][0], $feedback);
}
elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {
$this
->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);
}
$feedbacks[] = $feedback;
}
}
/**
* Create common parts of question
*/
function process_common($quest) {
$question = $this
->defaultquestion();
$question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
$question->name = shorten_text($quest->id, 250);
return $question;
}
//----------------------------------------
// Process True / False Questions
//----------------------------------------
function process_tf($quest, &$questions) {
$question = $this
->process_common($quest);
$question->qtype = TRUEFALSE;
$question->single = 1;
// Only one answer is allowed
// 0th [response] is the correct answer.
$responses = $quest->responses;
$correctresponse = $responses[0]->ident[0]['varequal'][0]['#'];
if ($correctresponse != 'false') {
$correct = true;
}
else {
$correct = false;
}
foreach ($quest->feedback as $fb) {
$fback->{$fb->ident} = $fb->text;
}
if ($correct) {
// true is correct
$question->answer = 1;
$question->feedbacktrue = addslashes($fback->correct);
$question->feedbackfalse = addslashes($fback->incorrect);
}
else {
// false is correct
$question->answer = 0;
$question->feedbacktrue = addslashes($fback->incorrect);
$question->feedbackfalse = addslashes($fback->correct);
}
$question->correctanswer = $question->answer;
$questions[] = $question;
}
//----------------------------------------
// Process Fill in the Blank
//----------------------------------------
function process_fblank($quest, &$questions) {
$question = $this
->process_common($quest);
$question->qtype = SHORTANSWER;
$question->single = 1;
$answers = array();
$fractions = array();
$feedbacks = array();
// extract the feedback
$feedback = array();
foreach ($quest->feedback as $fback) {
if (isset($fback->ident)) {
if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {
$feedback[$fback->ident] = $fback->text;
}
}
}
foreach ($quest->responses as $response) {
if (isset($response->title)) {
if (isset($response->ident[0]['varequal'][0]['#'])) {
//for BB Fill in the Blank, only interested in correct answers
if ($response->feedback = 'correct') {
$answers[] = addslashes($response->ident[0]['varequal'][0]['#']);
$fractions[] = 1;
if (isset($feedback['correct'])) {
$feedbacks[] = addslashes($feedback['correct']);
}
else {
$feedbacks[] = '';
}
}
}
}
}
//Adding catchall to so that students can see feedback for incorrect answers when they enter something the
//instructor did not enter
$answers[] = '*';
$fractions[] = 0;
if (isset($feedback['incorrect'])) {
$feedbacks[] = addslashes($feedback['incorrect']);
}
else {
$feedbacks[] = '';
}
$question->answer = $answers;
$question->fraction = $fractions;
$question->feedback = $feedbacks;
// Changed to assign $feedbacks to $question->feedback instead of
if (!empty($question)) {
$questions[] = $question;
}
}
//----------------------------------------
// Process Multiple Choice Questions
//----------------------------------------
function process_mc($quest, &$questions) {
$question = $this
->process_common($quest);
$question->qtype = MULTICHOICE;
$question->single = 1;
$feedback = array();
foreach ($quest->feedback as $fback) {
$feedback[$fback->ident] = addslashes($fback->text);
}
foreach ($quest->responses as $response) {
if (isset($response->title)) {
if ($response->title == 'correct') {
// only one answer possible for this qtype so first index is correct answer
$correct = $response->ident[0]['varequal'][0]['#'];
}
}
else {
// fallback method for when the title is not set
if ($response->feedback == 'correct') {
// only one answer possible for this qtype so first index is correct answer
$correct = $response->ident[0]['varequal'][0]['#'];
// added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06
}
}
}
$i = 0;
foreach ($quest->RESPONSE_BLOCK->choices as $response) {
$question->answer[$i] = addslashes($response->text);
if ($correct == $response->ident) {
$question->fraction[$i] = 1;
// this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists
// then specific feedback for this question (maybe this should be switched?, but from my example
// question pools I have not seen response specific feedback, only correct or incorrect feedback
if (!empty($feedback['correct'])) {
$question->feedback[$i] = $feedback['correct'];
}
elseif (!empty($feedback[$i])) {
$question->feedback[$i] = $feedback[$i];
}
else {
// failsafe feedback (should be '' instead?)
$question->feedback[$i] = "correct";
}
}
else {
$question->fraction[$i] = 0;
if (!empty($feedback['incorrect'])) {
$question->feedback[$i] = $feedback['incorrect'];
}
elseif (!empty($feedback[$i])) {
$question->feedback[$i] = $feedback[$i];
}
else {
// failsafe feedback (should be '' instead?)
$question->feedback[$i] = 'incorrect';
}
}
$i++;
}
if (!empty($question)) {
$questions[] = $question;
}
}
//----------------------------------------
// Process Multiple Choice Questions With Multiple Answers
//----------------------------------------
function process_ma($quest, &$questions) {
$question = $this
->process_common($quest);
// copied this from process_mc
$question->qtype = MULTICHOICE;
$question->single = 0;
// More than one answer allowed
$answers = $quest->responses;
$correct_answers = array();
foreach ($answers as $answer) {
if ($answer->title == 'correct') {
$answerset = $answer->ident[0]['and'][0]['#']['varequal'];
foreach ($answerset as $ans) {
$correct_answers[] = $ans['#'];
}
}
}
foreach ($quest->feedback as $fb) {
$feedback->{$fb->ident} = addslashes(trim($fb->text));
}
$correct_answer_count = count($correct_answers);
$choiceset = $quest->RESPONSE_BLOCK->choices;
$i = 0;
foreach ($choiceset as $choice) {
$question->answer[$i] = addslashes(trim($choice->text));
if (in_array($choice->ident, $correct_answers)) {
// correct answer
$question->fraction[$i] = floor(100000 / $correct_answer_count) / 100000;
// strange behavior if we have more than 5 decimal places
$question->feedback[$i] = $feedback->correct;
}
else {
// wrong answer
$question->fraction[$i] = 0;
$question->feedback[$i] = $feedback->incorrect;
}
$i++;
}
$questions[] = $question;
}
//----------------------------------------
// Process Essay Questions
//----------------------------------------
function process_essay($quest, &$questions) {
// this should be rewritten to accomodate moodle 1.6 essay question type eventually
if (defined("ESSAY")) {
// treat as short answer
$question = $this
->process_common($quest);
// copied this from process_mc
$question->qtype = ESSAY;
$question->feedback = array();
// not sure where to get the correct answer from
foreach ($quest->feedback as $feedback) {
// Added this code to put the possible solution that the
// instructor gives as the Moodle answer for an essay question
if ($feedback->ident == 'solution') {
$question->feedback = addslashes($feedback->text);
}
}
//Added because essay/questiontype.php:save_question_option is expecting a
//fraction property - CT 8/10/06
$question->fraction[] = 1;
if (!empty($question)) {
$questions[] = $question;
}
}
else {
print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";
print " Omitted Question: " . $quest->QUESTION_BLOCK->text . '<br/><br/>';
}
}
//----------------------------------------
// Process Matching Questions
//----------------------------------------
function process_matching($quest, &$questions) {
global $QTYPES;
// renderedmatch is an optional plugin, so we need to check if it is defined
if (array_key_exists('renderedmatch', $QTYPES)) {
$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 = addslashes($resp->correct);
$feedback = addslashes($resp->feedback);
}
}
foreach ($subq->choices as $cid => $choice) {
if ($choice == $correct) {
$question->subquestions[] = addslashes($subq->text);
$question->subanswers[] = addslashes($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 " Omitted Question: " . $quest->QUESTION_BLOCK->text . '<br/><br/>';
}
}
function strip_applet_tags_get_mathml($string) {
if (stristr($string, '</APPLET>') === FALSE) {
return $string;
}
else {
// strip all applet tags keeping stuff before/after and inbetween (if mathml) them
while (stristr($string, '</APPLET>') !== FALSE) {
preg_match("/(.*)\\<applet.*value=\"(\\<math\\>.*\\<\\/math\\>)\".*\\<\\/applet\\>(.*)/i", $string, $mathmls);
$string = $mathmls[1] . $mathmls[2] . $mathmls[3];
}
return $string;
}
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function |
Override if any post-processing is required Overrides qformat_default:: |
||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | Create common parts of question | ||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function |
Overrides qformat_default:: |
||
qformat_blackboard_6:: |
function |
Return complete file within an array, one item per line Overrides qformat_default:: |
||
qformat_blackboard_6:: |
function |
Parses an array of lines into an array of questions,
where each item is a question object as defined by
readquestion(). Questions are defined as anything
between blank lines. Overrides qformat_default:: |
||
qformat_blackboard_6:: |
function | |||
qformat_blackboard_6:: |
function | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
property | |||
qformat_default:: |
function | Count all non-category questions in the questions array. | ||
qformat_default:: |
function | find and/or create the category described by a delimited list e.g. $course$/tom/dick/harry or tom/dick/harry | ||
qformat_default:: |
function | return an "empty" question Somewhere to specify question parameters that are not handled by import but are required db fields. This should not be overridden. | ||
qformat_default:: |
function | Handle parsing error | ||
qformat_default:: |
function | Do an post-processing that may be required | ||
qformat_default:: |
function | Do any pre-processing that may be required | 1 | |
qformat_default:: |
function | Do the export For most types this should not need to be overrided | 1 | |
qformat_default:: |
function | Return the files extension appropriate for this type override if you don't want .txt | 3 | |
qformat_default:: |
function | where question specifies a moodle (text) format this performs the conversion. | ||
qformat_default:: |
function | get the category as a path (e.g., tom/dick/harry) | ||
qformat_default:: |
function | Import an image file encoded in base64 format | ||
qformat_default:: |
function | Perform any required pre-processing | 2 | |
qformat_default:: |
function | Process the file This method should not normally be overidden | 1 | |
qformat_default:: |
function | Enable any processing to be done on the content just prior to the file being saved default is to do nothing | 2 | |
qformat_default:: |
function | 4 | ||
qformat_default:: |
function | get directory into which export is going | ||
qformat_default:: |
function | Given the data known to define a question in this format, this function converts it into a question object suitable for processing and insertion into Moodle. | 5 | |
qformat_default:: |
function | set the category | ||
qformat_default:: |
function | set catfromfile | ||
qformat_default:: |
function | set cattofile | ||
qformat_default:: |
function | set contextfromfile | ||
qformat_default:: |
function | set an array of contexts. | ||
qformat_default:: |
function | set contexttofile | ||
qformat_default:: |
function | set the course class variable | ||
qformat_default:: |
function | set the filename | ||
qformat_default:: |
function | set matchgrades | ||
qformat_default:: |
function | Set the specific questions to export. Should not include questions with parents (sub questions of cloze question type). Only used for question export. | ||
qformat_default:: |
function | set the "real" filename (this is what the user typed, regardless of wha happened next) | ||
qformat_default:: |
function | set stoponerror | ||
qformat_default:: |
function | |||
qformat_default:: |
function | Provide export functionality for plugin questiontypes Do not override | ||
qformat_default:: |
function | Import for questiontype plugins Do not override. | ||
qformat_default:: |
function | convert a single question object into text output in the given format. This must be overriden | 4 |