Note:

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

Question types

From MoodleDocs
Revision as of 14:05, 27 April 2010 by Tim Hunt (talk | contribs)

This page explains how to go about writing a new Question Type for the new Moodle question engine.

For instructions on making a question type for current versions of Moodle, see Question_type_plugin_how_to.

Previous section: Developing a Question Behaviour

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.


To learn to write Question Types, you are highly encouraged to read the code of some of the existing question types in the Moodle code base.

Also 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.

This document assumes that you understand the data model, where a question attempt comprises a number of steps, and each step has some properties like a state and a mark, and an array of submitted data.


File layout

Question types live in a folder in question/type. The layout inside this folder follows the typical layout for a Moodle plugin. For example, inside the question/type/mytype/ folder we would have:

questiontype.php
Defines the qtype_mytype class. This must extend question_type.
question.php
This contains the definition of the qtype_mytype_question class, which should extend the question_definition base class.
renderer.php
This contains the definition of the qtype_mytype_renderer class, which should extend the qtype_renderer base class.
simpletest/...
Contains the unit tests for this question type. You are strongly encouraged to write thorough unit tests to ensure the correctness of your question type.
lang/en_utf8/qtype_myqtype.php
English language strings for this question type. You can, of course, include other languages too. The language file must define at least the string giving the model a name, for example $string['addingmyqtype'] = 'Adding a My question type';, $string['editingmyqtype'] = 'Editing a My question type'; and $string['myqtype'] = 'My question type';
dm/install.xml, db/upgrade.php
For creating any database tables required, as normal. See #Database_tables below.
db/access.php
Defines any capabilities required by this question type. This is very rarely needed.

Database tables

Note that question types should only have database tables for the question definition. All runtime data is managed by the question engine.

Question definitions should use the core table question, and can use the core table question_answers. You only need to define database tables if your question definition requires extra information that cannot be stored in either of these.


Question type class

This class represents the question type. It is responsible for loading and saving instances of questions of this class. It is also responsible for backing them up and restoring them. It also provides meta-data about the question type.


TODO

Question definition class

This holds the definition of a particular question of this type. There may also be some methods to perform processing. For example grade_responses.


TODO

Renderer class

Renderers are all about generating HTML output. The overall output of questions is controlled by the core_question_renderer::question(...), which in turn calls other methods of itself, the question type renderer and the behaviour renderer, to generate the various bits of output. See this overview of the parts of a question.

Once again, in what follows, I only list the methods your are most likely to want to override.


formulation_and_controls

This displays the the question text, and the controls the student will use to input their response. Some question types choose to display some feedback embedded in this area, for example ticks and crosses next to parts of the student's response.

The output code must respect the question_display_options and only reveal as much information as the calling code wants revealed. For example, the teacher creating a quiz may not want the correct answer revealed until after the quiz close date. Also, when outputting the controls, you need to respect the ->readonly option.


specific_feedback

Anything returned by this method is included in the 'outcome' area of the question, it is some feedback that particularly relates to the response the student gave. This method is only called if the display options allow this to be shows, so you don't have to worry about testing that.


correct_response

This would also be included in the 'outcome' area. This should be an automatically generated (from the question definition) display of what the correct answer to the question is.


Unit tests

For a general introduction, see the Moodle unit testing documentation.

The most important parts of your question type to test are the parts of the question_definition class that process the students responses, including the compare and grade methods.

The best way to start is probably to look at the tests for some of the standard question types.


Advanced ideas

Note that there is actually no reason why you should only have a single question_definition class for your question type. You may decide, depending on the question options, to use different definition classes where question options cause questions to behave in different ways. The multiple-choice question type does this, using different definition and renderer classes for single-response and multiple-response questions (but with common subclasses). This is possible because your question type can override the question_type::make_question_instance and question_definition::get_renderer methods.


Converting a Moodle 1.9 question type

1. Change the class definition in questiontype.php from

class question_myqtype_qtype extends default_questiontype {

to

class question_ddwtos_qtype extends question_type {


2. Create new renderer.php and question.php files, with a suitable blank class definition in them. (Perhaps copy the files from another question type, then delete everything in the class.)


3. Create Copy the question definition class, including:

3a. appropriate fields to store the question definition.

3b. create init_first_step, based on the old create_session_and_responses.

3c. Implement the grading logic get_expected_data, is_complete_response, is_gradable_response, is_same_response, grade_response, get_num_parts_right, clear_wrong_from_response. Some of this will be based on the old grade_responses method. You may also find some of the necessary code mixed into places like print_question_formulation_and_controls.

3d. Implement the reporting functionality get_correct_response, get_question_summary, summarise_response. Some of this may be related to the old grading methods.

3e. Write a test helper class to create one or more typical test instances of your question definition class.

3f. Write unit tests for the grading and reporting methods.


4. Copy all the code from print_question_formulation_and_controls and display.html, and related methods, and split it into the appropriate methods in the renderer class.


5. Write one or more walk-through tests that take instances of your question with different behaviours.


See also

Next section: Using the question engine from a module.

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