The problems of linking the lesson module with the question engine is exists long ago in the Moodle. We at the Volgograd State Technical University are interested in it too, and may spent some effort developing it.
However, good link require some additions to the question interface. We are supposing to add two simple functions, which don't interfere with other parts, but would allow question to report it state in universal manner.
Goal of all this is to create API flexibile enought to allow 3d party question authors (as well as core question authors) to add new properties and even data types for the properties - right in their questions (behavours?) - and they should be accessible by lesson without changing it.
Let's call a question attempt property (if anyone could propose a better word, I gladly rename them) some piece of data, describing current state of the attempt - i.e. number of submitting student made (in interactive/adaptive mode), matching answer, that used for grading (for shortanswer/numerical question), grade given (with or without penalties) etc. The property could use
Property datatype is a type of data which is expected from the property. It should be a pluginable, so 3d party question authors working with something new (like pictures, sound or video) could throw in new datatypes. That means we shoudn't presume anything about property data type in DB structure. It should be serialised in some sort of big field - TEXT or BLOB or something. I don't fond of serialisation in general, but it is necessary to allow flexibility we aim for. Actually lesson even don't need to serialise the property value - see below.
When a lesson determines whether it should do a particular jump, it should test some condition on the question attempt. Like "number of submitted wrong answers is greater than 3" or "student's answer match with this string (regex)" etc. The condition consists of three parts:
- a property been tested - selected from a property name list, available depending on the question type (and may be a behavour) in use;
- a conditional operation - selected from a list, depending on data type of the selected property (defined in data type class which should return a list of supported operations and contains a function that performs test), some examples:
- for a number - equal, greater than, less than, between etc
- for a string - contains (another string), match (with another string or regex), etc
- for a set (multichoice in multiple select mode) - has an item, is subset of, etc
- a conditional value - depends on property data type and the operation selected, the data type class should provide a form to edit it, way to serialise into DB (and unserialise)
- even for a number, it depends on operation selected
- equal or less take one number as conditional value;
- is between take two numbers as conditional value.
- even for a number, it depends on operation selected
It is the conditional value (not the property value) that should be serialised to DB by lesson. We could even think of example, where property value isn't easily serialised while conditional value could, like testing a picture (property) for an area of particular color (operation) where conditional value consists of area coordinates and the color. However, it may be wise to add a possibility to serialise property value to (or tell it couldn't be serialised) for the data type - if any other future activity would need it. The need to serialise conditional value is the only restriction this API placed on possible properties I know of.
One of the central place of the property data type class is a function that perform a conditional operation given property value, operation and conditional value, and returns true or false.
Now we need just two functions like supported_attempt_properties() and get_attempt_property()
supported_attempt_properties function returns an array of properties this question type supports and the type of their values (i.e. number, string etc). Like for shortanswer
array( 'numattempts' => array('type' => TYPE_INT, 'min' => '0', max => '...'), 'answer' => array('type' => TYPE_STRING), ... )
The possible data types could be defined, so that even complex types like multichoice or match could report anything important.
get_attempt_property has a two arguments: object, representing the question state (whatever this is in a new question engine) and a property name. It returns the actual value of given property for a given attempt. It is used by external module to query the properties value.
Those two functions with appropriate data types would allow to report almost anything, and place property reporting on appropriate inheritance levels (number of attempts could be reported by generic question class). They allow very much flexibility for the 3d party question authors while remaining easy to implement. They also allowed for a greater flexibility for a lesson module, like redirecting student somewhere after 4 unsuccessful tries at question, or something. What's more, the only thing that is presumed in that kind of link is available data types, anything else could be changed without affecting class's interface. We could even make data types a classes, then it could be easy to add new ones too.
I guess not all behavours are good for lesson. But it may be some is. However, if there is a place (is there?) to put this two functions so they could internally query both question state and behavour, it could support a properties from behavours too.
When editing the lesson you may add a question from question bank (or, probably, even a random one given all questions of the category are the same qtype), then you have to set up the jumps.
Each jump consist of two parts:
- three-parts condition, described above
- operation to test
- conditional value
- a place to jump - lesson page, selected from a list
There also may be a default jump, which defines where user goes when no condition is met (by default - on this very page probably). If several conditions is met, the first one in the list selected.
Another more potential problem is the user locked up doing lesson due to badly planned jumps. But then, it's possible even now.
When user submit an answer to a question, lesson will test each condition, asking the property value from the question (via get_attempt_property) and performing compare using data type class function (supplying the propery value, operation and conditional value). The first condition to return true would define what jump user would take.