Note:

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

Calculated multiquestions proposal

From MoodleDocs

This page will be used to document and structure a project of adding multiquestion capability to the calculated question like the cloze questiontype and allowing the calculated questions to be used as usual calculated question or as multiplechoice question.

Intro

This imply developping a structure similar to the multiquestion i.e adding calculated questions records with the main question as parent. An additional multiplechoice record is necessary to each calculated question.

Actually (august 2007) the general interface to create and edit this improved calculated questiontype is almost completed. The real difficulties are to modify the code related to grade each subquestion and store the session and responses parameters. If we only allowed single response multichoice question, the code will be a quite straightforward version of the multiquestion one.

Question Object structure

Here is the proposed structure of the question object after calling get_question_options records

  • main mdl_question
    • for each subquestion an mdl_question with the parent field set to main->id
      • for each mdl_question record
        • a mdl_question_calculated and
        • a mdl_question_multichoice

The usual answers records for each question and subquestion All the datasets, data_items records are associated with the main question All these data are structure like the following example. Probably to simplify the code the main question (#0) data will be repeated in the subquestions

stdClass Object
(
   [category] => 1
   [parent] => 0
   [name] => my first multichoice
   [questiontext] => What is the surface of a rectangle of {h} m by {l} m ?
{#0}
What is the perimeter of this rectangle?
{#1}
   [questiontextformat] => 1
   [image] => 
   [generalfeedback] => 
   [defaultgrade] => 1
   [penalty] => 0.1
   [qtype] => calculated
   [length] => 1
   [stamp] => 132.208.141.198+070613190851+gCcidQ
   [version] => 132.208.141.198+070812043753+37cXs7
   [hidden] => 0
   [id] => 382
   [maxgrade] => 1
   [name_prefix] => resp382_
   [options] => stdClass Object
       (
           [answers] => Array
               (
                   [1141] => stdClass Object
                       (
                           [question] => 382
                           [answer] => {h}* {l}
                           [fraction] => 1
                           [feedback] => OK
                           [tolerance] => 0.01
                           [tolerancetype] => 1
                           [correctanswerlength] => 2
                           [correctanswerformat] => 1
                           [id] => 1141
                       )
                   [1142] => stdClass Object
                       (
                           [question] => 382
                           [answer] => 2*({h}+{l})
                           [fraction] => 0.5
                           [feedback] => You give me the perimeter !
                           [tolerance] => 0.01
                           [tolerancetype] => 1
                           [correctanswerlength] => 2
                           [correctanswerformat] => 1
                           [id] => 1142
                       )
                   [1143] => stdClass Object
                       (
                           [question] => 382
                           [answer] => {rr}
                           [fraction] => 0
                           [feedback] => Go back and try again
                           [tolerance] => 0.01
                           [tolerancetype] => 1
                           [correctanswerlength] => 2
                           [correctanswerformat] => 1
                           [id] => 1143
                       )
               )
           [multichoice] => stdClass Object
               (
                   [id] => 257
                   [question] => 382
                   [layout] => 0
                   [answers] => 0
                   [single] => 1
                   [shuffleanswers] => 1
                   [correctfeedback] => 
                   [partiallycorrectfeedback] => 
                   [incorrectfeedback] => 
                   [answernumbering] => abc
               )
           [subquestions] => Array
               (
                   [383] => stdClass Object
                       (
                           [category] => 1
                           [parent] => 382
                           [name] => {#1}
                           [questiontext] => {#1}
                           [questiontextformat] => 1
                           [image] => 
                           [generalfeedback] => 
                           [defaultgrade] => 1
                           [penalty] => 0.1
                           [qtype] => calculated
                           [length] => 1
                           [stamp] => 132.208.141.198+070613203735+MrdwQ3
                           [version] => 132.208.141.198+070812043754+Os3B8Z
                           [hidden] => 0
                           [id] => 383
                           [options] => stdClass Object
                               (
                                   [answers] => Array
                                       (
                                           [1144] => stdClass Object
                                               (
                                                   [question] => 383
                                                   [answer] => 2*({h}+{l})
                                                   [fraction] => 1
                                                   [feedback] => OK 1
                                                   [tolerance] => 0.01
                                                   [tolerancetype] => 1
                                                   [correctanswerlength] => 0
                                                   [correctanswerformat] => 1
                                                   [id] => 1144
                                               )
                                       )
                                   [multichoice] => stdClass Object
                                       (
                                           [id] => 258
                                           [question] => 383
                                           [layout] => 0
                                           [answers] => 0
                                           [single] => 0
                                           [shuffleanswers] => 1
                                           [correctfeedback] => 
                                           [partiallycorrectfeedback] => 
                                           [incorrectfeedback] => 
                                           [answernumbering] => abc
                                       )
                                   [units] => Array
                                       (
                                       )
                               )
                           [editasmultichoice] => 0
                       )
               )
           [units] => Array
               (
               )
       )
   [editasmultichoice] => 0
)

Create and save sessions

For calculated questions the answer field of the mdl_question_states record store the responses with the dataset number followed by the responses the two being separated by -

   function save_session_and_responses(&$question, &$state) {
       $responses = 'dataset'.$state->options->datasetitem.'-'.
        $state->responses[];
example 'dataset13-2916m2'

For multichoice questiontype

       // The serialized format for multiple choice quetsions
       // is an optional comma separated list of answer ids (the order of the
       // answers) followed by a colon, followed by another comma separated
       // list of answer ids, which are the radio/checkboxes that were
       // ticked.
       // E.g. 1,3,2,4:2,4 means that the answers were shown in the order
       // 1, 3, 2 and then 4 and the answers 2 and 4 were checked.

For multianswer questiontype

The format is similar to the calculated, the order of the questions followed by the responses the two being separated by - , each answer being separated by ,

       $responses = $state->responses;
       // encode - (hyphen) and , (comma) to - because they are used as
       // delimiters
       array_walk($responses, create_function('&$val, $key',
               '$val = str_replace(array(",", "-"), array(",", "-"), $val);
               $val = "$key-$val";'));
       $responses = implode(',', $responses);

this give answer value like 1-8,2-yes,3-1.23,4-15,5-12.

To identify the subquestion and their corresponding answers, in the calculated question type we will use the question->id because the questions (#0,#1 etc.) can be placed everywhere in the text and possibly we could manage a rewowrking of this order in the case that one of the subquestion is dropped. So each question and subquestions will be separated by , and the first term will be the question_id. This should be coherent with the existing format. There is however a problem because actually there is no conversion of the - and , in the answer in the actual code. Given that the answer can contain number and the units, almost any character can be present as typing error.

We need a way to identify the new format.

The only real characteristic is the word dataset which could be used to identify records from preceeding calculated questiontype if we set new introductory word to the new questiontype. A spontaneous choice is to use DATASET instead of dataset.

How do we decide in which format we encode the responses. We need a flag from the question object for old type calculated questions that do not contain subquestions and do not have an associated multichoice record.

if (isset($question->options->multichoice) && isset($question->options->subquestion) {
 proceed with the new encoding
}else {
 use the old one
}

For the preceeding example

DATASET13-12.4cm2,