Note:

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

Using the question engine from module: Difference between revisions

From MoodleDocs
No edit summary
No edit summary
Line 9: Line 9:


Note that all the question engine code has extensive PHP documenter comments that should explain the purpose of every class and method. This document is supposed to provide an overview of the key points to get you started. It does not attempt to duplicate all the details in the PHPdocs.
Note that all the question engine code has extensive PHP documenter comments that should explain the purpose of every class and method. This document is supposed to provide an overview of the key points to get you started. It does not attempt to duplicate all the details in the PHPdocs.
==Overview==
The key class you will be working with is <tt>question_usage_by_activity</tt>. This tracks an attempt at some questions, for example a quiz attempt. The usage should provide all the interface methods you need to do things with the question engine. You should rarely need to dive deeper into the inner workings of the question engine than this.
The usage is a a collection of <tt>question_attempt</tt> objects. A question attempt represents the state of the user's attempt at one question within the usage. When you add a question to the usage, you get back a '''slot''' number. This server to index that question within the attempt. Using slot numbers like this means that the same question can be added more than once to the same usage. A lot of the usage API calls take this slot number to indicate which question attempt to operate on. Other API methods let you perform batch actions on all the question attempts within the usage.




==Starting an attempt at some questions==
==Starting an attempt at some questions==


TODO
===Creating the usage===
 
To create a new usage, ask the question engine:
<code php>
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
$quba->set_preferred_behaviour($quiz->preferredbehaviour);
</code>
 
You will see that the constructor takes the plugin name (using the Moodle 2.0 'frankenstyle' naming convention) and the context that owns the usage. Usages should be cleaned up automatically when a context is deleted or a plugin un-installed. You also have to tell the usage which behaviour should be used when creating the attempt at each question.
 
===Adding questions===
 
Having got a usage, you will probably then want to add some questions to it. The question data you loaded from the database (probably using the <tt>get_question_options</tt> function) come in a form suitable for data handling like import/export, backup/restore, and so on. We need to convert that to an <tt>question_definition</tt> object. That can be done using the <tt>question_bank::make_question</tt> method. Alternatively, you could just use the <tt>question_bank::load_question</tt> method, but that can only load one question at a time.
 
Once you have a <tt>question_definition</tt> object, you add it to the usage by calling the <tt>add_question</dd> method passing the question definition, and also the score you want this question marked out of. You get back the slot number that has been assigned to this question. The slot numbers are allocated in order, starting from 1. You can rely on that numbering convention. For example, the quiz module uses the slot numbers to make sure the grade for each question lines up properly in the reports.
 
Here is the applicable code from the quiz module
<code php>
foreach ($quizobj->get_questions() as $i => $questiondata) {
    $question = question_bank::make_question($questiondata);
    $idstonumbers[$i] = $quba->add_question($question, $questiondata->maxmark);
}
</code>
 
===Starting the question attempts===
 
The usage does not do much when the question is added. Before the user can start interacting with the question, you have to start it. You can either do that in bulk:
<code php>
$quba->start_all_questions();
</code>
or you can start just one particular question using the <tt>start_question($slot)</tt> method.
 
===Saving the usage===
 
So far, all these method calls have just built up a data structure in memory. If you want to save it, you have to ask for it to be saved to the database. Fortunately, that is easy:
<code php>
question_engine::save_questions_usage_by_activity($quba);
</code>





Revision as of 22:18, 4 November 2010

This page explains how to use the new Moodle question engine in an activity module you are developing.

Previous section: Developing a Question Type

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.


The first example of a module that uses the question engine is the quiz module. Looking at how the quiz code works will let you see a real working example of what explained on this page.

Note that all the question engine code has extensive PHP documenter comments that should explain the purpose of every class and method. This document is supposed to provide an overview of the key points to get you started. It does not attempt to duplicate all the details in the PHPdocs.


Overview

The key class you will be working with is question_usage_by_activity. This tracks an attempt at some questions, for example a quiz attempt. The usage should provide all the interface methods you need to do things with the question engine. You should rarely need to dive deeper into the inner workings of the question engine than this.

The usage is a a collection of question_attempt objects. A question attempt represents the state of the user's attempt at one question within the usage. When you add a question to the usage, you get back a slot number. This server to index that question within the attempt. Using slot numbers like this means that the same question can be added more than once to the same usage. A lot of the usage API calls take this slot number to indicate which question attempt to operate on. Other API methods let you perform batch actions on all the question attempts within the usage.


Starting an attempt at some questions

Creating the usage

To create a new usage, ask the question engine: $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); $quba->set_preferred_behaviour($quiz->preferredbehaviour);

You will see that the constructor takes the plugin name (using the Moodle 2.0 'frankenstyle' naming convention) and the context that owns the usage. Usages should be cleaned up automatically when a context is deleted or a plugin un-installed. You also have to tell the usage which behaviour should be used when creating the attempt at each question.

Adding questions

Having got a usage, you will probably then want to add some questions to it. The question data you loaded from the database (probably using the get_question_options function) come in a form suitable for data handling like import/export, backup/restore, and so on. We need to convert that to an question_definition object. That can be done using the question_bank::make_question method. Alternatively, you could just use the question_bank::load_question method, but that can only load one question at a time.

Once you have a question_definition object, you add it to the usage by calling the add_question method passing the question definition, and also the score you want this question marked out of. You get back the slot number that has been assigned to this question. The slot numbers are allocated in order, starting from 1. You can rely on that numbering convention. For example, the quiz module uses the slot numbers to make sure the grade for each question lines up properly in the reports. Here is the applicable code from the quiz module foreach ($quizobj->get_questions() as $i => $questiondata) { $question = question_bank::make_question($questiondata); $idstonumbers[$i] = $quba->add_question($question, $questiondata->maxmark); }

Starting the question attempts

The usage does not do much when the question is added. Before the user can start interacting with the question, you have to start it. You can either do that in bulk: $quba->start_all_questions(); or you can start just one particular question using the start_question($slot) method.

Saving the usage

So far, all these method calls have just built up a data structure in memory. If you want to save it, you have to ask for it to be saved to the database. Fortunately, that is easy: question_engine::save_questions_usage_by_activity($quba);


Displaying questions

TODO

Call JavaScript function question_init_form just after outputting the form tag.

Include a qnumbers hidden field.


Processing student responses

TODO


A nicety: scroll position

Add <input type="hidden" name="scrollpos" value="" /> to the question form.

On the processing page, if that scrollpos is set, add it to the URL you redirect back to.


See also

In the next section, Implementation plan outlines how I will implement this proposal.

  • The PHP documenter comments that explain the purposes of every method in the question engine code.
  • Back to Question Engine 2