mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 14:27:22 +01:00
d08e16b2a5
in 'base64' format.
345 lines
10 KiB
PHP
345 lines
10 KiB
PHP
<?php // $Id$
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
/// format.php - Default format class for file imports/exports. //
|
|
/// //
|
|
/// Doesn't do everything on it's own -- it needs to be extended. //
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
// Included by import.php and export.php
|
|
|
|
class qformat_default {
|
|
|
|
var $displayerrors = true;
|
|
var $category = NULL;
|
|
var $course = NULL;
|
|
var $questionids = array();
|
|
|
|
// functions to indicate import/export functionality
|
|
// override to return true if implemented
|
|
|
|
function provide_import() {
|
|
return false;
|
|
}
|
|
|
|
function provide_export() {
|
|
return false;
|
|
}
|
|
|
|
/// Importing functions
|
|
|
|
function importpreprocess($category, $course=NULL ) {
|
|
/// Does any pre-processing that may be desired
|
|
|
|
$this->category = $category; // Important
|
|
$this->course = $course;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @PARAM $matchgrades string 'error' or 'nearest', mismatched grades handling
|
|
*/
|
|
function importprocess($filename, $matchgrades='error') {
|
|
/// Processes a given file. There's probably little need to change this
|
|
|
|
if (! $lines = $this->readdata($filename)) {
|
|
notify( get_string('cannotread','quiz') );
|
|
return false;
|
|
}
|
|
|
|
if (! $questions = $this->readquestions($lines)) { // Extract all the questions
|
|
notify( get_string('noquestionsinfile','quiz') );
|
|
return false;
|
|
}
|
|
|
|
notify( get_string('importingquestions','quiz',count($questions)) );
|
|
|
|
// get list of valid answer grades
|
|
$grades = get_grade_options();
|
|
$gradeoptionsfull = $grades->gradeoptionsfull;
|
|
|
|
$count = 0;
|
|
|
|
foreach ($questions as $question) { // Process and store each question
|
|
$count++;
|
|
|
|
echo "<hr /><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
|
|
|
|
// check for answer grades validity (must match fixed list of grades)
|
|
$fractions = $question->fraction;
|
|
if (!empty($fractions)) {
|
|
$answersvalid = true; // in case they are!
|
|
foreach ($fractions as $key => $fraction) {
|
|
$newfraction = match_grade_options($gradeoptionsfull, $fraction, $matchgrades);
|
|
if ($newfraction===false) {
|
|
$answersvalid = false;
|
|
}
|
|
else {
|
|
$fractions[$key] = $newfraction;
|
|
}
|
|
}
|
|
if (!$answersvalid) {
|
|
notify( get_string('matcherror','quiz') );
|
|
continue;
|
|
}
|
|
else {
|
|
$question->fraction = $fractions;
|
|
}
|
|
}
|
|
|
|
$question->category = $this->category->id;
|
|
$question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
|
|
|
|
if (!$question->id = insert_record("question", $question)) {
|
|
error( get_string('cannotinsert','quiz') );
|
|
}
|
|
|
|
$this->questionids[] = $question->id;
|
|
|
|
// Now to save all the answers and type-specific options
|
|
|
|
global $QTYPES;
|
|
$result = $QTYPES[$question->qtype]
|
|
->save_question_options($question);
|
|
|
|
if (!empty($result->error)) {
|
|
notify($result->error);
|
|
return false;
|
|
}
|
|
|
|
if (!empty($result->notice)) {
|
|
notify($result->notice);
|
|
return true;
|
|
}
|
|
|
|
// Give the question a unique version stamp determined by question_hash()
|
|
set_field('question', 'version', question_hash($question), 'id', $question->id);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
function readdata($filename) {
|
|
/// Returns complete file with an array, one item per line
|
|
|
|
if (is_readable($filename)) {
|
|
$filearray = file($filename);
|
|
|
|
/// 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;
|
|
}
|
|
|
|
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();
|
|
|
|
foreach ($lines as $line) {
|
|
$line = trim($line);
|
|
if (empty($line)) {
|
|
if (!empty($currentquestion)) {
|
|
if ($question = $this->readquestion($currentquestion)) {
|
|
$questions[] = $question;
|
|
}
|
|
$currentquestion = array();
|
|
}
|
|
} else {
|
|
$currentquestion[] = $line;
|
|
}
|
|
}
|
|
|
|
if (!empty($currentquestion)) { // There may be a final question
|
|
if ($question = $this->readquestion($currentquestion)) {
|
|
$questions[] = $question;
|
|
}
|
|
}
|
|
|
|
return $questions;
|
|
}
|
|
|
|
|
|
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.
|
|
$question = new stdClass();
|
|
$question->shuffleanswers = 0;
|
|
$question->defaultgrade = 1;
|
|
$question->image = "";
|
|
$question->usecase = 0;
|
|
$question->multiplier = array();
|
|
|
|
return $question;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
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
|
|
// and filename!
|
|
$fullpath = "{$CFG->dataroot}/{$this->course->id}/$path";
|
|
$path_parts = pathinfo( $fullpath );
|
|
$destination = $path_parts['dirname'];
|
|
$file = clean_filename( $path_parts['basename'] );
|
|
|
|
// detect and fix any filename collision - get unique filename
|
|
$newfiles = resolve_filename_collisions( $destination, array($file) );
|
|
$newfile = $newfiles[0];
|
|
|
|
// convert and save file contents
|
|
if (!$content = base64_decode( $base64 )) {
|
|
return false;
|
|
}
|
|
$newfullpath = "$destination/$newfile";
|
|
if (!$fh = fopen( $newfullpath, 'w' )) {
|
|
return false;
|
|
}
|
|
if (!fwrite( $fh, $content )) {
|
|
return false;
|
|
}
|
|
fclose( $fh );
|
|
|
|
// return the (possibly) new filename
|
|
return $newfile;
|
|
}
|
|
|
|
// Export functions
|
|
|
|
|
|
function export_file_extension() {
|
|
/// return the files extension appropriate for this type
|
|
/// override if you don't want .txt
|
|
|
|
return ".txt";
|
|
}
|
|
|
|
function exportpreprocess($category, $course) {
|
|
/// Does any pre-processing that may be desired
|
|
|
|
$this->category = $category; // Important
|
|
$this->course = $course; // As is this!
|
|
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
function exportprocess($filename) {
|
|
/// Exports a given category. There's probably little need to change this
|
|
|
|
global $CFG;
|
|
|
|
// create a directory for the exports (if not already existing)
|
|
$dirname = get_string("exportfilename","quiz");
|
|
$courseid = $this->course->id;
|
|
$path = $CFG->dataroot.'/'.$courseid.'/'.$dirname;
|
|
if (!is_dir($path)) {
|
|
if (!mkdir($path, $CFG->directorypermissions)) {
|
|
error( get_string('cannotcreatepath','quiz',$path) );
|
|
}
|
|
}
|
|
|
|
// get the questions (from database) in this category
|
|
// only get q's with no parents (no cloze subquestions specifically)
|
|
$questions = get_questions_category( $this->category, true );
|
|
|
|
notify( get_string('exportingquestions','quiz') );
|
|
if (!count($questions)) {
|
|
notify( get_string('noquestions','quiz') );
|
|
return false;
|
|
}
|
|
$count = 0;
|
|
|
|
// results are first written into string (and then to a file)
|
|
// so create/initialize the string here
|
|
$expout = "";
|
|
|
|
// iterate through questions
|
|
foreach($questions as $question) {
|
|
$count++;
|
|
$qtype = $question->qtype;
|
|
// ignore random questiond
|
|
if ($qtype!=RANDOM) {
|
|
echo "<hr /><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
|
|
$expout .= $this->writequestion( $question ) . "\n";
|
|
}
|
|
}
|
|
|
|
// final pre-process on exported data
|
|
$expout = $this->presave_process( $expout );
|
|
|
|
// write file
|
|
$filepath = $path."/".$filename . $this->export_file_extension();
|
|
if (!$fh=fopen($filepath,"w")) {
|
|
error( get_string('cannotopen','quiz',$filepath) );
|
|
}
|
|
if (!fwrite($fh, $expout)) {
|
|
error( get_string('cannotwrite','quiz',$filepath) );
|
|
}
|
|
fclose($fh);
|
|
|
|
return true;
|
|
}
|
|
|
|
function exportpostprocess() {
|
|
/// Does any post-processing that may be desired
|
|
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
?>
|