Skip to content

Commit

Permalink
Start documenting core_question and qbank_
Browse files Browse the repository at this point in the history
  • Loading branch information
timhunt committed Feb 26, 2024
1 parent 27d0a90 commit f9d3265
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 4 deletions.
15 changes: 11 additions & 4 deletions docs/apis/plugintypes/qbank/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
---
title: Question Bank plugins
title: Question bank plugins
tags:
- Plugins
- Question
- qbank
- Quiz
description: Question type plugins allow you to extend the functionality of the Moodle Question bank.
description: Question bank plugins allow you to extend the functionality of the Moodle Question bank.
documentationDraft: true
---

Expand All @@ -16,10 +15,18 @@ import { Since } from '@site/src/components';
issueNumber="MDL-70329"
/>

Question type plugins allow you to extend the functionality of the Moodle Question bank, and support features including:
Question bank plugins allow you to extend the functionality of the Moodle Question bank. They just one of the plugin
types used by core_question. To see how they fit in, please read
[this overview of the question subsystems](../subsystems/question/).

Question bank plugins can extend the question bank in many ways, including:

- Table columns
- Action menu items
- Bulk actions
- Navigation node (tabs)
- Question preview additions (via callback)

The place to start implementing most of these is with a class `classes/plugin_features.php` in your plugin,
that declares which features you want to add to the question bank. Until more documentation is written,
looking at the examples of the plugins in Moodle core should give you a good idea what you need to do.
28 changes: 28 additions & 0 deletions docs/apis/plugintypes/qtype/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Question type plugins
tags:
- Plugins
- Question
- qtype
description: Question type plugins implement the different types of question that the core Question subsystem can handle.
---

Question types are one of the plugins used by the question subsystem. To see how they fit in, please read
[this overview of the question subsystems](../subsystems/question/).

Question types have to do many things:

1. `edit_..._form.php` - Provide an editing form so that teachers can create and edit questions of this type.
2. `questiontypes.php` - Define a class to handle loading and saving data from this form.
3. ... and related methods providing metadata about this question types.
4. ... and import and export in any Question formats that the type wants to support.
5. `question.php` - this class represents one instance of this question type, while it is being attempted by a user. It must do many things
6. ... Start a new attempt (e.g. in a multiple choice question, this is where we randomly shuffle the choices).
7. ... or if we are continuing an existing attmept, re-initalise the question to the same state, using the data from the DB.
8. ... Tell the question engine what data this question type is expecting to be submitted.
9. ... Analyse those submitted responses: e.g. has it changed? is it complete.
10. ... Automatically grade the response to give a 'fraction' (mark between 0 and 1) and a state (correct / partially correct / incorrect).
11. ... check access to files for the file API.
12. `renderer.php` - to display the key bits of this question types for the `core_question_renderer` to combine into the overall question display.
13. Implements Backup and restore, and all the other standard parts of a Moodle plugin like DB tables.
14. Track [users preferences for the settings used for newly created questions](./qtype/newquestiondefaults).
73 changes: 73 additions & 0 deletions docs/apis/plugintypes/qtype/newquestiondefaults.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Question type plugins - defaults for new questions
tags:
- Plugins
- Question
- qtype
description: A way for question types to remember a user's preferred settings for creating questions of a given type.
documentationDraft: true
---

Many question types are quite flexible, and so have a lot of options on their editing form. Quite often, when a teacher
is creating a number of questions, it is likely that the teacher will want to keep using the same values for some options.
Therefore, the question system has a way for question types to easily save certain settings, and re-use them.

Note, this is only done when a teacher creates and saves a new question. We don't save the preferences when a teacher edits
an existing question (which might have been created by someone else with different preferences).

Here is how you implement this:

### Decide which settings should be saved

It does not make sense to save all settings. For example, it woule by stupid to remember the name and question text,
because these are things that make a particular question what it is, and will alwasy be different. So, we only want to
save settings where that makes sense. For example do you want the choices in your multiple-choice question numbered
'a, b, c, ...' or '1, 2, 3, ...' or not numbered at all? You need to think about this. Looking through what other question
types do is probably a good way to get a feel for what sorts of things it makes sense to remember.

### In the form class - use any previously saved defaults

Before implementing this feature, your form class is likely to have code like

```php
$mform->setDefault('shuffleanswers', 1);
```

For all the settings where you want to implement this feature, need to change the hard-coded default (`1` here) to instead
fetch the default from the user's preferences using the `get_default_value` method:

```php
$mform->setDefault('shuffleanswers', $this->get_default_value('shuffleanswers', 1));
```

### In the question-type class

Here we need to override the method `save_defaults_for_new_questions` to save the values these settings. For example:

```php
public function save_defaults_for_new_questions(stdClass $fromform): void {
parent::save_defaults_for_new_questions($fromform);
$this->set_default_value('shuffleanswers', $fromform->shuffleanswers);
}
```

All the settings save here should match the ones fetched by `get_default_value` in the form.
You need to call `parent` because Moodle core saves some of the settings that apply to all question types.

### Privacy provider

Because this feature works using user preferences, you need to declare that in your privacy provider.

This is boring but necessary. Easiest way to see what to do is to [copy another quetion type](https://github.com/moodle/moodle/blob/master/question/type/match/classes/privacy/provider.php).

Note, it is necessary for your provider to declare the ones saved by core. (I suppose, ideally, someone would make a helpful base class, or trait, to make it easier to implement this.)

### Automated tests

Always a good idea. You are likely to need:

1. [Unit tests for the privacy provider](https://github.com/moodle/moodle/blob/master/question/type/match/tests/privacy/provider_test.php).
2. Behat test to show that the saved settings are re-used. Many question types have
[a `behat/add.feature` file where it is easy to add coverage for this](https://github.com/moodle/moodle/blob/master/question/type/match/tests/behat/add.feature).

The links in that list go to examples of how these are implemented in `qtype_match`.
73 changes: 73 additions & 0 deletions docs/apis/subsystems/question/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Questions API
tags:
- API
- Subsystem
- Question
documentationDraft: true
---

The question subsystem in Moodle manages the creation, editing and management of interactive questions,
and then enables those questions to be presented to users so they can be attempted. It is useful to
consider these as separate subcomponents.

## The question engine

This is the part that makes questions work when users attempt or otherwise interact with questions as part of a learning experience.

The main user of this in the standard Moodle package is mod_quiz, but there is also qbank_previewquestion, and numerous plugins, includin
[filter_embedquestion](https://moodle.org/plugins/filter_embedquestion).

The goal of this part of the system is to allow the widest ranges of interactive learning experiences to be created, therefore the question
engine supports two types of plugin:

### [Question types (qtype_)](../../plugintypes/qtype/index.md)

This defines what the question is. For example a multiple choice or drag-drop question question, or
a text input question graded as eith a string (e.g. shortanswer or [pattern-match](https://moodle.org/plugins/qtype_pmatch))
or as a number. It might be something much more complex, like a [crossword](https://moodle.org/plugins/qtype_crossword), or a [coding exercise](https://moodle.org/plugins/qtype_coderunner).

### Question behaviours (qbehaviour_)

These let Moodle support different ways for a student to interact with questions.
For example it might be like a classic exams, where initially the student just inputs their answers to all the questions, which are then
only graded, and feedback given later (qbehaviour_deferredfeedback). Or it the student might have a 'Check' button in each question
so their work can be graded immediately (qbahviour_immediatefeebdack). It might even be that after their first try, if that is not right,
the students can immediately Try again, to see if they can correct their mistake based on the initial feedback (qbehaviour_interactive).

### Core question engine

So, core question engine mostly serves orchestrates these two plugin types working together to present a attempt at a particular question to a user.
Some key classes here are:

1. `question_engine` - this class is the main entry point into this part of the API.
2. `question_attempt` - this represents a users attempt at on question. Since most of the time user's attempt a group of related
questions together, and even more important class is `question_usage_by_activity`.
3. `question state` - as stated above, question types and behaviours should have as much freedom as possible to present interesting
educational interactions to users. But, on the other hand, parts of the system that use questions (e.g. the quiz) need to have some
idea what is going on with each question. The various question states try to find an appropriate compromise, so the state of each
question can be tracked, but withough restricting the freedom of the question behaviours to work how they want.
4. `question_display_options` - when questions are used, e.g. in a quiz, there may be limitations one what the user can see. For example,
perhaps the student is only allowed to see the grade and feedback on their attempt after all students have finished. The display options
class is how the quiz can control which bits should be visible when a question is rendered. In addition, depending what state we are in
with the question behviour might also affect what is visible right now, so qbehaviour_plugins can modify the display options based
on the current state of the question_attempt, as part of the rendering process.
5. `core_question_renderer` - renders the overall layout of the questions. It works with the applicable qtype_ and qbehaviour_ renderer to
rendner the details of the current attempt.

## Question bank

The question bank provies the UI where teachers create, edit and manage questions.

### [Question bank plugins (qbank_)](../../plugintypes/qbank/index.md)

These add features to the qusetion bank. The core question bank code mainly just ties all these features together.

### Question import/export plugins (qformat_)

Allow questions to be exported and imported in a variety of formats. Use by plugins like qbank_exportquestions, qbank_importquestions and qbank_exporttoxml.

### [Question types (qtype_)](../../plugintypes/qtype/index.md)

Question types do not only interact with the question engine. They also need to work with the question bank, so that teachers
can create and edit questions of their type.

0 comments on commit f9d3265

Please sign in to comment.