Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Question formats

From MoodleDocs

Importing or exporting questions

Questions coming from other Moodle courses or from other e-learning systems (i.e. Blackboard, Webct etc.) can be imported in Moodle. Similarlay Moodle offers a process to export questions to other systems in different format ( XML, QTI etc.). The import and export code is mostly written in format.php files located in a directory specific to the type of format files from which the import or export is done.

  • examples:
    • question/format/aiken/format.php
    • question/format/blackboard/format.php
    • question/format/qti2/format.php
    • question/format/xml/format.php

there is a default class qformat_default defined in question/format.php and the process is controlled by

  • question/import.php
  • question/export.php

Where to find the information to code for import/export format.php files.

As we are developping new questiontypes or new import functions from external files, we need to safeguard the default_questiontype->save_question() from importing bad question data. We must well document these question parameters and get stronger validation before saving a new question.

The most exhaustive developper documentations rely on the knowledge of the database tables, the tags definition and a good comprehension of the few comments inserted in the code.

Efforts have been made to document the database (i.e. Gustav Delius has work a lot on the question part) but as usual solving the bugs and developping new features took most of the energy.

For the description of the different question parameters you should look at the developper docs Quiz database structure and the quiz_questions table that have been renamed question when the question code has been replaced as independent from the quiz in moodle 1.6.

These docs illustrate well the difficulty to maintain an up-to-date, I had to correct it (at least I try...) for the modifications done by Gustav himself in the database .

The format.php code flow for import

When importing questions

  • the import.php let select the file and import format
    • pass the control to format.php and format/$format/format.php
$format being the selected file format ( Blackboard, XML etc.)
       require("format.php");  // Parent class
       require("format/$format/format.php");
       $classname = "qformat_$format";
       $qformat = new $classname();
       if (! $qformat->importpreprocess($category,$course)) {  // Do anything before that we need to
           error( $txt->importerror ,
                     "$CFG->wwwroot/question/import.php?courseid={$course->id}&category=$category->id");
       }
       if (! $qformat->importprocess($importfile, $params->matchgrades) ) {  // Process the uploaded file
           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
  • format.php call format/$format/format.php (i.e. the the specific format.php)
to read the imput file and return the questions (if any) that are in the imported files
        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;
  • Process some data and store each question
  • check for answer grades validity (must match fixed list of grades)
  • store question general parameters DIRECTLY in the dadabase
           $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;
  • save the options using the qtype->save_question_options() function
$QTYPES being the different questiontypes (shortanwer,truefalse etc.)
           global $QTYPES;
           $result = $QTYPES[$question->qtype]
                   ->save_question_options($question);
  • diplay errors or notices
           if (!empty($result->error)) {
               notify($result->error);
               return false;
           }
           if (!empty($result->notice)) {
               notify($result->notice);
               return true;
           }
  • if noerrors and no notices
Give the question a unique version stamp determined by question_hash()
           set_field('question', 'version', question_hash($question), 'id', $question->id);
Process the next question until the last question in the file
Return to the question or quiz editing.

Cloning the default_questiontype->save_question() implications

Comments by --Pierre Pichet 08:25, 20 June 2006 (WST)

saving the question common elements

the format.php clone in a certain way the default_questiontype->save_question() by saving the question common elements. However the format.php do not verify or validate these common elements the same way that question/type/questiontype->save_question()do. format.php let to each filetype/format.php the responsability to verify or validate these common question elements.

A more stable code will be to centralize the verification and validation of the question common elements to questiontype->save_question(). However the code flow of the questiontype->save_question() when creating or modifying a question by the user is not necesseraly the code flow when importing from files in format->save_question() when errors occured in one or the other process.

A better solution will be to separate the three steps of questiontype->save_question().
# verification and validation of the question common elements 
# question saving in the database
# call to qtype/questiontype->save_question_options()
by creating two new functions
*questiontype->validate_question_common_elements()
*questiontype->save_question_common_elements()

With these two additional functions, questiontype->save_question() and format->save_question() could process the saving of questions by a call to

  1. questiontype->validate_question_common_elements()
    1. questiontype or format processing of errors and notices.
  2. questiontype->save_question_common_elements()
    1. questiontype or format processing of errors and notices.
  3. qtype->save_question_options()
    1. questiontype or format processing of errors and notices.

and each class have the complete control for the treatment of errors or notices at the return of the three common functions.

saving the question options elements

format.php calls the specific qtype->save_question_options() function. 

This is the regular way to save these options that were retrieved from the imported file.
This should be the correct way to implement a stable code and it will work correctly if ALL the necessary data supplementary to have a valid question of the questiontype that is currently saved, is handled by a one call to the regular specific qtype/questiontype->save_question_options().
This is the case for almost all actual questiontypes implemented in Moodle, one of the exceptions being calculated questiontype.
The solution found in older Moodle versions was to create a special save_question_options() in the extended filetype/format.php file to handle the saving of the data items elements.

ex. $QTYPES[CALCULATED]= new qformat_webct_modified_calculated_qtype();) 

This imply that for each new file format you need to create a new code or copy the qformat_webct_modified_calculated_qtype one.
A better solution would be to modify the calculated/questiontype.php->save_question_options() function so that it could save all the data ( options and data items).

This could be done by checking if the dataitemset definitions and the associated data items are set in $question

See also

Lesson question types - both Lesson and Quiz can import the basic Moodle question types.