var $catfromfile = 0;
var $cattofile = 0;
var $questionids = array();
+ var $importerrors = 0;
+ var $stoponerror = true;
// functions to indicate import/export functionality
// override to return true if implemented
$this->cattofile = $cattofile;
}
-/// Importing functions
+ /**
+ * set stoponerror
+ * @param bool stoponerror stops database write if any errors reported
+ */
+ function setStoponerror( $stoponerror ) {
+ $this->stoponerror = $stoponerror;
+ }
+
+/***********************
+ * IMPORTING FUNCTIONS
+ ***********************/
+
+ /**
+ * Handle parsing error
+ */
+ function error( $message, $text='', $questionname='' ) {
+ echo "<div class=\"importerror\">\n";
+ echo "<strong>Error in question $questionname</strong>";
+ if (!empty($text)) {
+ $text = s($text);
+ echo "<blockquote>$text</blockquote>\n";
+ }
+ echo "<strong>$message</strong>\n";
+ echo "</div>";
+
+ $this->importerrors++;
+ }
/**
* Perform any required pre-processing
+ * @return boolean success
*/
function importpreprocess() {
return true;
/**
* Process the file
* This method should not normally be overidden
+ * @return boolean success
*/
function importprocess() {
+
+ // STAGE 1: Parse the file
+ notify( get_string('parsingquestions','quiz') );
+
if (! $lines = $this->readdata($this->filename)) {
notify( get_string('cannotread','quiz') );
return false;
return false;
}
+ // STAGE 2: Write data to database
notify( get_string('importingquestions','quiz',count($questions)) );
+ // check for errors before we continue
+ if ($this->stoponerror and ($this->importerrors>0)) {
+ return false;
+ }
+
// get list of valid answer grades
$grades = get_grade_options();
$gradeoptionsfull = $grades->gradeoptionsfull;
return true;
}
-
+ /**
+ * Return complete file within an array, one item per line
+ * @param string filename name of file
+ * @return mixed contents array or false on failure
+ */
function readdata($filename) {
- /// Returns complete file with an array, one item per line
-
if (is_readable($filename)) {
$filearray = file($filename);
return false;
}
+ /**
+ * 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.
+ *
+ * If your format does not use blank lines as a delimiter
+ * then you will need to override this method. Even then
+ * try to use readquestion for each question
+ * @param array lines array of lines from readdata
+ * @return array array of question objects
+ */
function readquestions($lines) {
- /// 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.
$questions = array();
$currentquestion = array();
}
+ /**
+ * 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.
+ * @return object default question
+ */
function defaultquestion() {
- // returns an "empty" question
- // Somewhere to specify question parameters that are not handled
- // by import but are required db fields.
- // This should not be overridden.
global $CFG;
$question = new stdClass();
return $question;
}
+ /**
+ * 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.
+ *
+ * If your format does not use blank lines to delimit questions
+ * (e.g. an XML format) you must override 'readquestions' too
+ * @param $lines mixed data that represents question
+ * @return object question object
+ */
function readquestion($lines) {
- /// Given an array of lines known to define a question in
- /// this format, this function converts it into a question
- /// object suitable for processing and insertion into Moodle.
$formatnotimplemented = get_string( 'formatnotimplemented','quiz' );
echo "<p>$formatnotimplemented</p>";
return NULL;
}
-
+ /**
+ * Override if any post-processing is required
+ * @return boolean success
+ */
function importpostprocess() {
- /// Does any post-processing that may be desired
- /// Argument is a simple array of question ids that
- /// have just been added.
-
return true;
}
+ /**
+ * Import an image file encoded in base64 format
+ * @param string path path (in course data) to store picture
+ * @param string base64 encoded picture
+ * @return string filename (nb. collisions are handled)
+ */
function importimagefile( $path, $base64 ) {
- /// imports an image file encoded in base64 format
- /// This should not be overridden.
global $CFG;
// all this to get the destination directory
return $newfile;
}
-//=================
-// Export functions
-//=================
+/*******************
+ * EXPORT FUNCTIONS
+ *******************/
+ /**
+ * Return the files extension appropriate for this type
+ * override if you don't want .txt
+ * @return string file extension
+ */
function export_file_extension() {
- /// return the files extension appropriate for this type
- /// override if you don't want .txt
-
return ".txt";
}
+ /**
+ * Do any pre-processing that may be required
+ * @param boolean success
+ */
function exportpreprocess() {
- /// Does any pre-processing that may be desired
-
return true;
}
+ /**
+ * Enable any processing to be done on the content
+ * just prior to the file being saved
+ * default is to do nothing
+ * @param string output text
+ * @param string processed output text
+ */
function presave_process( $content ) {
- /// enables any processing to be done on the content
- /// just prior to the file being saved
- /// default is to do nothing
-
return $content;
}
+ /**
+ * Do the export
+ * For most types this should not need to be overrided
+ * @return boolean success
+ */
function exportprocess() {
- /// Exports a given category. There's probably little need to change this
-
global $CFG;
// create a directory for the exports (if not already existing)
return true;
}
+ /**
+ * Do an post-processing that may be required
+ * @return boolean success
+ */
function exportpostprocess() {
- /// Does any post-processing that may be desired
-
return true;
}
+ /**
+ * convert a single question object into text output in the given
+ * format.
+ * This must be overriden
+ * @param object question question object
+ * @return mixed question export text or null if not implemented
+ */
function writequestion($question) {
- /// Turns a question object into textual output in the given format
- /// must be overidden
-
// if not overidden, then this is an error.
$formatnotimplemented = get_string( 'formatnotimplemented','quiz' );
echo "<p>$formatnotimplemented</p>";
return NULL;
}
+ /**
+ * get directory into which export is going
+ * @return string file path
+ */
function question_get_export_dir() {
$dirname = get_string("exportfilename","quiz");
$path = $this->course->id.'/backupdata/'.$dirname; // backupdata is protected directory
return $path;
}
+ /**
+ * where question specifies a moodle (text) format this
+ * performs the conversion.
+ */
function format_question_text($question) {
$formatoptions = new stdClass;
$formatoptions->noclean = true;
function check_answer_count( $min, $answers, $text ) {
$countanswers = count($answers);
if ($countanswers < $min) {
- if ($this->displayerrors) {
- $errormessage = get_string( 'importminerror', 'quiz' );
- echo "<p>$text</p>\n";
- echo "<p>$errormessage</p>\n";
- }
+ $importminerror = get_string( 'importminerror', 'quiz' );
+ $this->error( $importminerror, $text );
return false;
}
foreach ($lines as $key => $line) {
$line = trim($line);
if (substr($line, 0, 2) == "//") {
- // echo "Commented line removed.<br />";
$lines[$key] = " ";
}
}
$text = trim(implode(" ", $lines));
if ($text == "") {
- // echo "<p>Empty line.</p>";
return false;
}
// FIND ANSWER section
$answerstart = strpos($text, "{");
if ($answerstart === false) {
- if ($this->displayerrors) {
- echo "<p>$text<p>Could not find a {";
- }
+ $this->error( 'Could not find a {', $text );
return false;
}
$answerfinish = strpos($text, "}");
if ($answerfinish === false) {
- if ($this->displayerrors) {
- echo "<p>$text<p>Could not find a }";
- }
+ $this->error( 'Could not find a }', $text );
return false;
}
}
if (!isset($question->qtype)) {
- if ($this->displayerrors) {
- echo "<p>$text<p>Question type not set.";
- }
+ $this->error( 'Question type not set', $text );
return false;
}
foreach ($answers as $key => $answer) {
$answer = trim($answer);
if (strpos($answer, "->") === false) {
- if ($this->displayerrors) {
- echo "<p>$text<p>Error processing Matching question.<br />
- Improperly formatted answer: $answer";
- }
+ $this->error('Improperly formatted Matching Question answer', $answer );
return false;
break 2;
}
} // end foreach answer
- //$question->defaultgrade = 1;
- //$question->image = ""; // No images with this format
return $question;
break;
if (count($answers) == 0) {
// invalid question
- if ($this->displayerrors) {
- echo "<p>$text<p>No answers found in answertext (Numerical answer)";
- }
+ $this->error( 'No answers found in Numerical answer', $text );
return false;
break;
}
}
if (!(is_numeric($ans) || $ans = '*') || !is_numeric($tol)) {
- if ($this->displayerrors) {
- $err = get_string( 'errornotnumbers' );
- echo "<p>$text</p><p>$err</p>
- <p>Answer: <u>$answer</u></p><p>Tolerance: <u>$tol</u></p> ";
- }
+ $errornotnumbers = get_string( 'errornotnumbers' );
+ $this->error( $errornotnumbers, $text );
return false;
break;
}
$question->tolerance[$key] = '';
}
- //$question->defaultgrade = 1;
- //$question->image = ""; // No images with this format
- //$question->multiplier = array(); // no numeric multipliers with GIFT
return $question;
break;
default:
- if ($this->displayerrors) {
- echo "<p>$text<p> No valid question type. Error in switch(question->qtype)";
- }
+ $this->error( 'No valid question detected', $text );
return false;
break;
$courseid = optional_param('course', 0, PARAM_INT);
$format = optional_param('format','',PARAM_FILE);
$params->matchgrades = optional_param('matchgrades','',PARAM_ALPHA);
+ $params->stoponerror = optional_param('stoponerror', 0, PARAM_BOOL);
// get display strings
$txt = new stdClass();
$txt->onlyteachersimport = get_string('onlyteachersimport','quiz');
$txt->questions = get_string("questions", "quiz");
$txt->quizzes = get_string('modulenameplural', 'quiz');
+ $txt->stoponerror = get_string('stoponerror', 'quiz');
$txt->upload = get_string('upload');
$txt->uploadproblem = get_string('uploadproblem');
$txt->uploadthisfile = get_string('uploadthisfile');
$qformat->setFilename( $importfile );
$qformat->setMatchgrades( $params->matchgrades );
$qformat->setCatfromfile( $catfromfile );
+ $qformat->setStoponerror( $params->stoponerror );
- if (! $qformat->importpreprocess()) { // Do anything before that we need to
+ // Do anything before that we need to
+ if (! $qformat->importpreprocess()) {
error( $txt->importerror ,
"$CFG->wwwroot/question/import.php?courseid={$course->id}&category=$category->id");
}
- if (! $qformat->importprocess() ) { // Process the uploaded file
+ // Process the uploaded file
+ if (! $qformat->importprocess() ) {
error( $txt->importerror ,
"$CFG->wwwroot/question/import.php?courseid={$course->id}&category=$category->id");
}
- if (! $qformat->importpostprocess()) { // In case anything needs to be done after
+ // In case anything needs to be done after
+ if (! $qformat->importpostprocess()) {
error( $txt->importerror ,
"$CFG->wwwroot/question/import.php?courseid={$course->id}&category=$category->id");
}
<tr>
<td align="right"><?php echo $txt->fileformat; ?>:</td>
- <td><?php choose_from_menu($fileformatnames, "format", "gift", "");
- helpbutton("import", $txt->importquestions, "quiz"); ?></td>
+ <td><?php choose_from_menu($fileformatnames, 'format', 'gift', '');
+ helpbutton("import", $txt->importquestions, 'quiz'); ?></td>
</tr>
<tr>
<td align="right"><?php echo $txt->matchgrades; ?></td>
<td><?php choose_from_menu($matchgrades,'matchgrades',$txt->matchgradeserror,'' );
helpbutton('matchgrades', $txt->matchgrades, 'quiz'); ?></td>
</tr>
+ <tr>
+ <td align="right"><?php echo $txt->stoponerror; ?></td>
+ <td><input name="stoponerror" type="checkbox" checked="checked" />
+ <?php helpbutton('stoponerror', $txt->stoponerror, 'quiz'); ?></td>
+ </tr>
</table>
<?php
print_simple_box_end();