2006-09-08 10:27:48 +00:00
< ? php
////////////////////////////////////////////////////////////////////////////
/// Blackboard 6.x Format
///
/// This Moodle class provides all functions necessary to import and export
///
///
////////////////////////////////////////////////////////////////////////////
// Based on default.php, included by ../import.php
require_once ( " $CFG->libdir /xmlize.php " );
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 = '' ) {
2006-09-14 13:59:08 +00:00
// for now we will just say everything happened okay note
// that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import
2006-09-08 10:27:48 +00:00
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 ( $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 ( 0000 );
$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 ;
global $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 ;
$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 ;
}
return false ;
}
}
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 );
2006-09-14 13:59:08 +00:00
switch ( $question -> qtype ) {
2006-09-08 10:27:48 +00:00
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 ;
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 ) {
2006-09-14 13:59:08 +00:00
$question = $this -> defaultquestion ();
2006-09-08 10:27:48 +00:00
$question -> qtype = $quest [ '#' ][ 'itemmetadata' ][ 0 ][ '#' ][ 'bbmd_questiontype' ][ 0 ][ '#' ];
$presentation -> blocks = $quest [ '#' ][ 'presentation' ][ 0 ][ '#' ][ 'flow' ][ 0 ][ '#' ][ 'flow' ];
2006-09-14 13:59:08 +00:00
foreach ( $presentation -> blocks as $pblock ) {
2006-09-08 10:27:48 +00:00
$block = NULL ;
$block -> type = $pblock [ '@' ][ 'class' ];
2006-09-14 13:59:08 +00:00
2006-09-08 10:27:48 +00:00
switch ( $block -> type ) {
case 'QUESTION_BLOCK' :
$sub_blocks = $pblock [ '#' ][ 'flow' ];
foreach ( $sub_blocks as $sblock ) {
2006-09-14 13:59:08 +00:00
//echo "Calling process_block from line 263<br>";
2006-09-08 10:27:48 +00:00
$this -> process_block ( $sblock , $block );
}
break ;
2006-09-14 13:59:08 +00:00
2006-09-08 10:27:48 +00:00
case 'RESPONSE_BLOCK' :
$choices = NULL ;
switch ( $question -> qtype ) {
case 'Matching' :
$bb_subquestions = $pblock [ '#' ][ 'flow' ];
$sub_questions = array ();
foreach ( $bb_subquestions as $bb_subquestion ) {
2006-09-14 13:59:08 +00:00
$sub_question = NULL ;
2006-09-08 10:27:48 +00:00
$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 );
2006-09-14 13:59:08 +00:00
$block -> choices = $choices ;
break ;
2006-09-08 10:27:48 +00:00
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' ];
2006-09-14 13:59:08 +00:00
foreach ( $mc_choices as $mc_choice ) {
2006-09-08 10:27:48 +00:00
$choices = NULL ;
2006-09-14 13:59:08 +00:00
$choices = $this -> process_block ( $mc_choice , $choices );
$block -> choices [] = $choices ;
2006-09-08 10:27:48 +00:00
}
break ;
case 'Fill in the Blank' :
// 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 ) {
$this -> process_block ( $answer , $bb_answer );
$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' ];
2006-09-14 13:59:08 +00:00
$respconditions = $resprocessing [ 0 ][ '#' ][ 'respcondition' ];
$reponses = array ();
2006-09-08 10:27:48 +00:00
if ( $question -> qtype == 'Matching' ) {
$this -> process_matching_responses ( $respconditions , $responses );
}
else {
$this -> process_responses ( $respconditions , $responses );
}
$question -> responses = $responses ;
$feedbackset = $quest [ '#' ][ 'itemfeedback' ];
2006-09-14 13:59:08 +00:00
$feedbacks = array ();
$this -> process_feedback ( $feedbackset , $feedbacks );
2006-09-08 10:27:48 +00:00
$question -> feedback = $feedbacks ;
return $question ;
}
function process_block ( $cur_block , & $block ) {
2006-09-14 13:59:08 +00:00
global $course , $CFG ;
2006-09-08 10:27:48 +00:00
$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 ][ '#' ]);
2006-09-14 13:59:08 +00:00
break ;
2006-09-08 10:27:48 +00:00
case 'FILE_BLOCK' :
//revisit this to make sure it is working correctly
2006-09-14 13:59:08 +00:00
// 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
2006-09-08 10:27:48 +00:00
$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' :
2006-09-14 13:59:08 +00:00
if ( isset ( $cur_block [ '#' ][ 'material' ][ 0 ][ '#' ][ 'mattext' ][ 0 ][ '#' ])) {
$block -> text = $cur_block [ '#' ][ 'material' ][ 0 ][ '#' ][ 'mattext' ][ 0 ][ '#' ];
2006-09-08 10:27:48 +00:00
}
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' ];
}
}
2006-09-08 15:51:11 +00:00
foreach ( $sub_blocks [ '#' ][ 'flow_mat' ] as $sub_block ) {
2006-09-08 10:27:48 +00:00
$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 ;
}
2006-09-14 13:59:08 +00:00
return $block ;
2006-09-08 10:27:48 +00:00
}
function process_choices ( $bb_choices , & $choices ) {
2006-09-14 13:59:08 +00:00
foreach ( $bb_choices as $choice ) {
if ( isset ( $choice [ '@' ][ 'ident' ])) {
2006-09-08 10:27:48 +00:00
$cur_choice = $choice [ '@' ][ 'ident' ];
}
2006-09-14 13:59:08 +00:00
else { //for multiple answer
2006-09-08 10:27:48 +00:00
$cur_choice = $choice [ '#' ][ 'response_label' ][ 0 ]; //['@']['ident'];
}
2006-09-14 13:59:08 +00:00
if ( isset ( $choice [ '#' ][ 'flow_mat' ][ 0 ])) { //for multiple answer
2006-09-08 10:27:48 +00:00
$cur_block = $choice [ '#' ][ 'flow_mat' ][ 0 ];
2006-09-14 13:59:08 +00:00
// 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 );
2006-09-08 10:27:48 +00:00
}
elseif ( isset ( $choice [ '#' ][ 'response_label' ])) {
2006-09-14 13:59:08 +00:00
// 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 ;
2006-09-08 10:27:48 +00:00
$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 ) {
2006-09-14 13:59:08 +00:00
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' ])) {
2006-09-08 10:27:48 +00:00
$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 :
2006-09-14 13:59:08 +00:00
// 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
2006-09-08 10:27:48 +00:00
$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 ) {
2006-09-14 13:59:08 +00:00
// 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' ];
2006-09-08 10:27:48 +00:00
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 ;
}
}
//----------------------------------------
// Process True / False Questions
//----------------------------------------
function process_tf ( $quest , & $questions ) {
$question = $this -> defaultquestion ();
$question -> qtype = TRUEFALSE ;
$question -> defaultgrade = 1 ;
2006-09-14 13:59:08 +00:00
$question -> single = 1 ; // Only one answer is allowed
$question -> image = " " ; // No images with this format
$question -> questiontext = addslashes ( $quest -> QUESTION_BLOCK -> text );
2006-09-08 10:27:48 +00:00
// put name in question object
$question -> name = $question -> questiontext ;
// first choice is true, second is false.
if ( $quest -> responses [ 0 ] -> fraction == 1 ) {
$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 );
}
$questions [] = $question ;
}
//----------------------------------------
// Process Fill in the Blank
//----------------------------------------
function process_fblank ( $quest , & $questions ) {
2006-09-14 13:59:08 +00:00
$question = $this -> defaultquestion ();
2006-09-08 10:27:48 +00:00
$question -> qtype = SHORTANSWER ;
$question -> defaultgrade = 1 ;
$question -> single = 1 ;
$question -> usecase = 0 ;
$question -> image = '' ;
$question -> questiontext = addslashes ( $quest -> QUESTION_BLOCK -> text );
$question -> name = $question -> questiontext ;
$answers = array ();
$fractions = array ();
$feedbacks = array ();
// extract the feedback
$feedback = array ();
foreach ( $quest -> feedback as $fback ) {
if ( isset ( $fback -> ident )) {
2006-09-14 13:59:08 +00:00
if ( $fback -> ident == 'correct' || $fback -> ident == 'incorrect' ) {
$feedback [ $fback -> ident ] = $fback -> text ;
}
2006-09-08 10:27:48 +00:00
}
}
foreach ( $quest -> responses as $response ) {
if ( isset ( $response -> title )) {
2006-09-14 13:59:08 +00:00
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 [] = '' ;
}
}
}
2006-09-08 10:27:48 +00:00
}
}
2006-09-14 13:59:08 +00:00
//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 [] = '' ;
}
2006-09-08 10:27:48 +00:00
$question -> answer = $answers ;
$question -> fraction = $fractions ;
2006-09-14 13:59:08 +00:00
$question -> feedback = $feedbacks ; // Changed to assign $feedbacks to $question->feedback instead of
2006-09-08 10:27:48 +00:00
if ( ! empty ( $question )) {
$questions [] = $question ;
}
}
//----------------------------------------
// Process Multiple Choice Questions
//----------------------------------------
function process_mc ( $quest , & $questions ) {
2006-09-14 13:59:08 +00:00
$question = $this -> defaultquestion ();
2006-09-08 10:27:48 +00:00
$question -> qtype = MULTICHOICE ;
$question -> defaultgrade = 1 ;
$question -> single = 1 ;
$question -> image = " " ;
$question -> questiontext = addslashes ( $quest -> QUESTION_BLOCK -> text );
$question -> name = $question -> questiontext ;
$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
2006-09-14 13:59:08 +00:00
$correct = $response -> ident [ 0 ][ 'varequal' ][ 0 ][ '#' ];
2006-09-08 10:27:48 +00:00
}
}
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 ) {
2006-09-14 13:59:08 +00:00
$question -> answer [ $i ] = addslashes ( $response -> text );
2006-09-08 10:27:48 +00:00
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 ) {
2006-09-14 13:59:08 +00:00
$question = $this -> defaultquestion (); // copied this from process_mc
2006-09-08 10:27:48 +00:00
$question -> questiontext = addslashes ( $quest -> QUESTION_BLOCK -> text );
$question -> name = $question -> questiontext ;
$question -> qtype = MULTICHOICE ;
$question -> defaultgrade = 1 ;
2006-09-14 13:59:08 +00:00
$question -> single = 0 ; // More than one answer allowed
$question -> image = " " ; // No images with this format
2006-09-08 10:27:48 +00:00
$answers = $quest -> responses ;
$correct_answers = array ();
foreach ( $answers as $answer ) {
if ( $answer -> title == 'correct' ) {
2006-09-14 13:59:08 +00:00
$answerset = $answer -> ident [ 0 ][ 'and' ][ 0 ][ '#' ][ 'varequal' ];
2006-09-08 10:27:48 +00:00
foreach ( $answerset as $ans ) {
2006-09-14 13:59:08 +00:00
$correct_answers [] = $ans [ '#' ];
2006-09-08 10:27:48 +00:00
}
}
}
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
2006-09-14 13:59:08 +00:00
$question = $this -> defaultquestion (); // copied this from process_mc
2006-09-08 10:27:48 +00:00
$question -> qtype = ESSAY ;
$question -> defaultgrade = 1 ;
2006-09-14 13:59:08 +00:00
$question -> usecase = 0 ; // Ignore case
$question -> image = " " ; // No images with this format
2006-09-08 10:27:48 +00:00
$question -> questiontext = addslashes ( trim ( $quest -> QUESTION_BLOCK -> text ));
$question -> name = $question -> questiontext ;
print $question -> name ;
$question -> feedback = array ();
// not sure where to get the correct answer from
foreach ( $quest -> feedback as $feedback ) {
2006-09-14 13:59:08 +00:00
// 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 = $feedback -> text ;
}
}
//Added because essay/questiontype.php:save_question_option is expecting a
//fraction property - CT 8/10/06
$question -> fraction [] = 1 ;
2006-09-08 10:27:48 +00:00
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 ) {
if ( defined ( " RENDEREDMATCH " )) {
$question = $this -> defaultquestion ( $this -> defaultquestion ());
$question -> valid = true ;
$question -> qtype = RENDEREDMATCH ;
$question -> defaultgrade = 1 ;
$question -> questiontext = addslashes ( $quest -> QUESTION_BLOCK -> text );
$question -> name = $question -> questiontext ;
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 align="center" 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 ;
}
}
} // close object
?>