Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

This file defines the question usage class, and a few related classes.

Copyright: 2009 The Open University
License: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
File Size: 1188 lines (48 kb)
Included or required: 1 time
Referenced: 0 times
Includes or requires: 0 files

Defines 4 classes

question_usage_by_activity:: (63 methods):
  __construct()
  set_preferred_behaviour()
  get_preferred_behaviour()
  get_owning_context()
  get_owning_component()
  get_id()
  set_id_from_database()
  get_observer()
  set_observer()
  add_question()
  add_question_in_place_of_other()
  next_slot_number()
  get_question()
  get_slots()
  get_first_question_number()
  question_count()
  get_attempt_iterator()
  check_slot()
  get_question_attempt()
  get_question_state()
  get_question_state_string()
  get_question_state_class()
  can_question_finish_during_attempt()
  get_question_action_time()
  get_question_fraction()
  get_question_mark()
  get_question_max_mark()
  get_total_mark()
  get_summary_information()
  get_question_summary()
  get_response_summary()
  get_right_answer_summary()
  get_question_attempt_metadata()
  set_question_attempt_metadata()
  render_question()
  render_question_head_html()
  render_question_at_step()
  check_file_access()
  replace_loaded_question_attempt_info()
  get_field_prefix()
  get_num_variants()
  get_variant()
  start_question()
  start_all_questions()
  start_question_based_on()
  process_all_actions()
  process_all_autosaves()
  get_slots_in_request()
  extract_responses()
  prepare_simulated_post_data()
  process_action()
  process_autosave()
  validate_sequence_number()
  is_autosave_required()
  update_question_flags()
  get_correct_response()
  finish_question()
  finish_all_questions()
  manual_grade()
  regrade_question()
  regrade_all_questions()
  set_max_mark()
  load_from_records()

question_attempt_iterator:: (10 methods):
  __construct()
  current()
  key()
  next()
  rewind()
  valid()
  offsetExists()
  offsetGet()
  offsetSet()
  offsetUnset()

question_usage_observer:: (9 methods):
  notify_modified()
  notify_attempt_added()
  notify_attempt_modified()
  notify_attempt_moved()
  notify_step_added()
  notify_step_modified()
  notify_step_deleted()
  notify_metadata_added()
  notify_metadata_modified()

question_usage_null_observer:: (9 methods):
  notify_modified()
  notify_attempt_added()
  notify_attempt_modified()
  notify_attempt_moved()
  notify_step_added()
  notify_step_modified()
  notify_step_deleted()
  notify_metadata_added()
  notify_metadata_modified()


Class: question_usage_by_activity  - X-Ref

This class keeps track of a group of questions that are being attempted,
and which state, and so on, each one is currently in.

A quiz attempt or a lesson attempt could use an instance of this class to
keep track of all the questions in the attempt and process student submissions.
It is basically a collection of {@question_attempt} objects.

The questions being attempted as part of this usage are identified by an integer
that is passed into many of the methods as $slot. ($question->id is not
used so that the same question can be used more than once in an attempt.)

Normally, calling code should be able to do everything it needs to be calling
methods of this class. You should not normally need to get individual
{@question_attempt} objects and play around with their inner workind, in code
that it outside the quetsion engine.

Instances of this class correspond to rows in the question_usages table.

__construct($component, $context)   X-Ref
Create a new instance. Normally, calling code should use
{@link question_engine::make_questions_usage_by_activity()} or
{@link question_engine::load_questions_usage_by_activity()} rather than
calling this constructor directly.

param: string $component the plugin creating this attempt. For example mod_quiz.
param: object $context the context this usage belongs to.

set_preferred_behaviour($behaviour)   X-Ref

param: string $behaviour the name of an archetypal behaviour, that should

get_preferred_behaviour()   X-Ref
No description

get_owning_context()   X-Ref
No description

get_owning_component()   X-Ref
No description

get_id()   X-Ref
No description

set_id_from_database($id)   X-Ref
For internal use only. Used by {@link question_engine_data_mapper} to set
the id when a usage is saved to the database.

param: int $id the newly determined id for this usage.

get_observer()   X-Ref
No description

set_observer($observer)   X-Ref
You should almost certainly not call this method from your code. It is for
internal use only.

param: question_usage_observer that should be used to tracking changes made to this usage.

add_question(question_definition $question, $maxmark = null)   X-Ref
Add another question to this usage.

The added question is not started until you call {@link start_question()}
on it.

param: question_definition $question the question to add.
param: number $maxmark the maximum this question will be marked out of in
return: int the number used to identify this question within this usage.

add_question_in_place_of_other($slot, question_definition $question, $maxmark = null)   X-Ref
Add another question to this usage, in the place of an existing slot.
The question_attempt that was in that slot is moved to the end at a new
slot number, which is returned.

The added question is not started until you call {@link start_question()}
on it.

param: int $slot the slot-number of the question to replace.
param: question_definition $question the question to add.
param: number $maxmark the maximum this question will be marked out of in
return: int the new slot number of the question that was displaced.

next_slot_number()   X-Ref
The slot number that will be allotted to the next question added.


get_question($slot, $requirequestioninitialised = true)   X-Ref
Get the question_definition for a question in this attempt.

param: int $slot the number used to identify this question within this usage.
param: bool $requirequestioninitialised set this to false if you don't need
return: question_definition the requested question object.

get_slots()   X-Ref
No description

get_first_question_number()   X-Ref
No description

question_count()   X-Ref
No description

get_attempt_iterator()   X-Ref
Note the part of the {@link question_usage_by_activity} comment that explains
that {@link question_attempt} objects should be considered part of the inner
workings of the question engine, and should not, if possible, be accessed directly.

return: question_attempt_iterator for iterating over all the questions being

check_slot($slot)   X-Ref
Check whether $number actually corresponds to a question attempt that is
part of this usage. Throws an exception if not.

param: int $slot a number allegedly identifying a question within this usage.

get_question_attempt($slot)   X-Ref
Note the part of the {@link question_usage_by_activity} comment that explains
that {@link question_attempt} objects should be considered part of the inner
workings of the question engine, and should not, if possible, be accessed directly.

param: int $slot the number used to identify this question within this usage.
return: question_attempt the corresponding {@link question_attempt} object.

get_question_state($slot)   X-Ref
Get the current state of the attempt at a question.

param: int $slot the number used to identify this question within this usage.
return: question_state.

get_question_state_string($slot, $showcorrectness)   X-Ref

param: int $slot the number used to identify this question within this usage.
param: bool $showcorrectness Whether right/partial/wrong states should
return: string A brief textual description of the current state.

get_question_state_class($slot, $showcorrectness)   X-Ref

param: int $slot the number used to identify this question within this usage.
param: bool $showcorrectness Whether right/partial/wrong states should
return: string a CSS class name for the current state.

can_question_finish_during_attempt($slot)   X-Ref
Whether this attempt at a given question could be completed just by the
student interacting with the question, before {@link finish_question()} is called.

param: int $slot the number used to identify this question within this usage.
return: boolean whether the attempt at the given question can finish naturally.

get_question_action_time($slot)   X-Ref
Get the time of the most recent action performed on a question.

param: int $slot the number used to identify this question within this usage.
return: int timestamp.

get_question_fraction($slot)   X-Ref
Get the current fraction awarded for the attempt at a question.

param: int $slot the number used to identify this question within this usage.
return: number|null The current fraction for this question, or null if one has

get_question_mark($slot)   X-Ref
Get the current mark awarded for the attempt at a question.

param: int $slot the number used to identify this question within this usage.
return: number|null The current mark for this question, or null if one has

get_question_max_mark($slot)   X-Ref
Get the maximum mark possible for the attempt at a question.

param: int $slot the number used to identify this question within this usage.
return: number the available marks for this question.

get_total_mark()   X-Ref
Get the total mark for all questions in this usage.

return: number The sum of marks of all the question_attempts in this usage.

get_summary_information(question_display_options $options)   X-Ref
Get summary information about this usage.

Some behaviours may be able to provide interesting summary information
about the attempt as a whole, and this method provides access to that data.
To see how this works, try setting a quiz to one of the CBM behaviours,
and then look at the extra information displayed at the top of the quiz
review page once you have sumitted an attempt.

In the return value, the array keys are identifiers of the form
qbehaviour_behaviourname_meaningfullkey. For qbehaviour_deferredcbm_highsummary.
The values are arrays with two items, title and content. Each of these
will be either a string, or a renderable.

param: question_display_options $options display options to apply.
return: array as described above.

get_question_summary($slot)   X-Ref
Get a simple textual summary of the question that was asked.

param: int $slot the slot number of the question to summarise.
return: string the question summary.

get_response_summary($slot)   X-Ref
Get a simple textual summary of response given.

param: int $slot the slot number of the question to get the response summary for.
return: string the response summary.

get_right_answer_summary($slot)   X-Ref
Get a simple textual summary of the correct response to a question.

param: int $slot the slot number of the question to get the right answer summary for.
return: string the right answer summary.

get_question_attempt_metadata($slot, $name)   X-Ref
Return one of the bits of metadata for a particular question attempt in
this usage.

param: int $slot the slot number of the question of inereest.
param: string $name the name of the metadata variable to return.
return: string the value of that metadata variable.

set_question_attempt_metadata($slot, $name, $value)   X-Ref
Set some metadata for a particular question attempt in this usage.

param: int $slot the slot number of the question of inerest.
param: string $name the name of the metadata variable to return.
param: string $value the value to set that metadata variable to.

render_question($slot, $options, $number = null)   X-Ref
Get the {@link core_question_renderer}, in collaboration with appropriate
{@link qbehaviour_renderer} and {@link qtype_renderer} subclasses, to generate the
HTML to display this question.

param: int $slot the number used to identify this question within this usage.
param: question_display_options $options controls how the question is rendered.
param: string|null $number The question number to display. 'i' is a special
return: string HTML fragment representing the question.

render_question_head_html($slot)   X-Ref
Generate any bits of HTML that needs to go in the <head> tag when this question
is displayed in the body.

param: int $slot the number used to identify this question within this usage.
return: string HTML fragment.

render_question_at_step($slot, $seq, $options, $number = null)   X-Ref
Like {@link render_question()} but displays the question at the past step
indicated by $seq, rather than showing the latest step.

param: int $slot the number used to identify this question within this usage.
param: int $seq the seq number of the past state to display.
param: question_display_options $options controls how the question is rendered.
param: string|null $number The question number to display. 'i' is a special
return: string HTML fragment representing the question.

check_file_access($slot, $options, $component, $filearea,$args, $forcedownload)   X-Ref
Checks whether the users is allow to be served a particular file.

param: int $slot the number used to identify this question within this usage.
param: question_display_options $options the options that control display of the question.
param: string $component the name of the component we are serving files for.
param: string $filearea the name of the file area.
param: array $args the remaining bits of the file path.
param: bool $forcedownload whether the user must be forced to download the file.
return: bool true if the user can access this file.

replace_loaded_question_attempt_info($slot, $qa)   X-Ref
Replace a particular question_attempt with a different one.

For internal use only. Used when reloading the state of a question from the
database.

param: int $slot the slot number of the question to replace.
param: question_attempt $qa the question attempt to put in that place.

get_field_prefix($slot)   X-Ref
You should probably not use this method in code outside the question engine.
The main reason for exposing it was for the benefit of unit tests.

param: int $slot the number used to identify this question within this usage.
return: string return the prefix that is pre-pended to field names in the HTML

get_num_variants($slot)   X-Ref
Get the number of variants available for the question in this slot.

param: int $slot the number used to identify this question within this usage.
return: int the number of variants available.

get_variant($slot)   X-Ref
Get the variant of the question being used in a given slot.

param: int $slot the number used to identify this question within this usage.
return: int the variant of this question that is being used.

start_question($slot, $variant = null, $timenow = null)   X-Ref
Start the attempt at a question that has been added to this usage.

param: int $slot the number used to identify this question within this usage.
param: int $variant which variant of the question to use. Must be between
param: int|null $timenow optional, the timstamp to record for this action. Defaults to now.

start_all_questions(question_variant_selection_strategy $variantstrategy = null,$timestamp = null, $userid = null)   X-Ref
Start the attempt at all questions that has been added to this usage.

param: question_variant_selection_strategy how to pick which variant of each question to use.
param: int $timestamp optional, the timstamp to record for this action. Defaults to now.
param: int $userid optional, the user to attribute this action to. Defaults to the current user.

start_question_based_on($slot, question_attempt $oldqa)   X-Ref
Start the attempt at a question, starting from the point where the previous
question_attempt $oldqa had reached. This is used by the quiz 'Each attempt
builds on last' mode.

param: int $slot the number used to identify this question within this usage.
param: question_attempt $oldqa a previous attempt at this quetsion that

process_all_actions($timestamp = null, $postdata = null)   X-Ref
Process all the question actions in the current request.

If there is a parameter slots included in the post data, then only
those question numbers will be processed, otherwise all questions in this
useage will be.

This function also does {@link update_question_flags()}.

param: int $timestamp optional, use this timestamp as 'now'.
param: array $postdata optional, only intended for testing. Use this data

process_all_autosaves($timestamp = null, $postdata = null)   X-Ref
Process all the question autosave data in the current request.

If there is a parameter slots included in the post data, then only
those question numbers will be processed, otherwise all questions in this
useage will be.

This function also does {@link update_question_flags()}.

param: int $timestamp optional, use this timestamp as 'now'.
param: array $postdata optional, only intended for testing. Use this data

get_slots_in_request($postdata = null)   X-Ref
Get the list of slot numbers that should be processed as part of processing
the current request.

param: array $postdata optional, only intended for testing. Use this data
return: array of slot numbers.

extract_responses($slot, $postdata = null)   X-Ref
Get the submitted data from the current request that belongs to this
particular question.

param: int $slot the number used to identify this question within this usage.
param: array|null $postdata optional, only intended for testing. Use this data
return: array submitted data specific to this question.

prepare_simulated_post_data($simulatedresponses)   X-Ref
Transform an array of response data for slots to an array of post data as you would get from quiz attempt form.

param: $simulatedresponses array keys are slot nos => contains arrays representing student
return: array simulated post data

process_action($slot, $submitteddata, $timestamp = null)   X-Ref
Process a specific action on a specific question.

param: int $slot the number used to identify this question within this usage.
param: array $submitteddata the submitted data that constitutes the action.
param: int|null $timestamp (optional) the timestamp to consider 'now'.

process_autosave($slot, $submitteddata, $timestamp = null)   X-Ref
Process an autosave action on a specific question.

param: int $slot the number used to identify this question within this usage.
param: array $submitteddata the submitted data that constitutes the action.
param: int|null $timestamp (optional) the timestamp to consider 'now'.

validate_sequence_number($slot, $postdata = null)   X-Ref
Check that the sequence number, that detects weird things like the student clicking back, is OK.

If the sequence check variable is not present, returns
false. If the check variable is present and correct, returns true. If the
variable is present and wrong, throws an exception.

param: int $slot the number used to identify this question within this usage.
param: array|null $postdata (optional) data to use in place of $_POST.
return: bool true if the check variable is present and correct. False if it

is_autosave_required($slot, $postdata = null)   X-Ref
Check, based on the sequence number, whether this auto-save is still required.

param: int $slot the number used to identify this question within this usage.
param: array|null $postdata the submitted data that constitutes the action.
return: bool true if the check variable is present and correct, otherwise false.

update_question_flags($postdata = null)   X-Ref
Update the flagged state for all question_attempts in this usage, if their
flagged state was changed in the request.

param: array|null $postdata optional, only intended for testing. Use this data

get_correct_response($slot)   X-Ref
Get the correct response to a particular question. Passing the results of
this method to {@link process_action()} will probably result in full marks.
If it is not possible to compute a correct response, this method should return null.

param: int $slot the number used to identify this question within this usage.
return: array that constitutes a correct response to this question.

finish_question($slot, $timestamp = null)   X-Ref
Finish the active phase of an attempt at a question.

This is an external act of finishing the attempt. Think, for example, of
the 'Submit all and finish' button in the quiz. Some behaviours,
(for example, immediatefeedback) give a way of finishing the active phase
of a question attempt as part of a {@link process_action()} call.

After the active phase is over, the only changes possible are things like
manual grading, or changing the flag state.

param: int $slot the number used to identify this question within this usage.
param: int|null $timestamp (optional) the timestamp to consider 'now'.

finish_all_questions($timestamp = null)   X-Ref
Finish the active phase of an attempt at a question. See {@link finish_question()}
for a fuller description of what 'finish' means.

param: int|null $timestamp (optional) the timestamp to consider 'now'.

manual_grade($slot, $comment, $mark, $commentformat = null)   X-Ref
Perform a manual grading action on a question attempt.

param: int $slot the number used to identify this question within this usage.
param: string $comment the comment being added to the question attempt.
param: number $mark the mark that is being assigned. Can be null to just
param: int $commentformat one of the FORMAT_... constants. The format of $comment.

regrade_question($slot, $finished = false, $newmaxmark = null)   X-Ref
Regrade a question in this usage. This replays the sequence of submitted
actions to recompute the outcomes.

param: int $slot the number used to identify this question within this usage.
param: bool $finished whether the question attempt should be forced to be finished
param: number $newmaxmark (optional) if given, will change the max mark while regrading.

regrade_all_questions($finished = false)   X-Ref
Regrade all the questions in this usage (without changing their max mark).

param: bool $finished whether each question should be forced to be finished

set_max_mark($slot, $maxmark)   X-Ref
Change the max mark for this question_attempt.

param: int $slot the slot number of the question of inerest.
param: float $maxmark the new max mark.

load_from_records($records, $qubaid)   X-Ref
Create a question_usage_by_activity from records loaded from the database.

For internal use only.

param: Iterator $records Raw records loaded from the database.
param: int $qubaid The id of the question usage we are loading.
return: question_usage_by_activity The newly constructed usage.

Class: question_attempt_iterator  - X-Ref

A class abstracting access to the {@link question_usage_by_activity::$questionattempts} array.

This class snapshots the list of {@link question_attempts} to iterate over
when it is created. If a question is added to the usage mid-iteration, it
will now show up.

To create an instance of this class, use
{@link question_usage_by_activity::get_attempt_iterator()}

__construct(question_usage_by_activity $quba)   X-Ref
To create an instance of this class, use
{@link question_usage_by_activity::get_attempt_iterator()}.

param: question_usage_by_activity $quba the usage to iterate over.

current()   X-Ref
Standard part of the Iterator interface.

return: question_attempt

key()   X-Ref
Standard part of the Iterator interface.

return: int

next()   X-Ref
Standard part of the Iterator interface.


rewind()   X-Ref
Standard part of the Iterator interface.


valid()   X-Ref
Standard part of the Iterator interface.

return: bool

offsetExists($slot)   X-Ref
Standard part of the ArrayAccess interface.

param: int $slot
return: bool

offsetGet($slot)   X-Ref
Standard part of the ArrayAccess interface.

param: int $slot
return: question_attempt

offsetSet($slot, $value)   X-Ref
Standard part of the ArrayAccess interface.

param: int $slot
param: question_attempt $value

offsetUnset($slot)   X-Ref
Standard part of the ArrayAccess interface.

param: int $slot

Interface: question_usage_observer  - X-Ref

Interface for things that want to be notified of signficant changes to a
{@link question_usage_by_activity}.

A question behaviour controls the flow of actions a student can
take as they work through a question, and later, as a teacher manually grades it.

notify_modified()   X-Ref
No description

notify_attempt_added(question_attempt $qa)   X-Ref
Called when a new question attempt is added to this usage.

param: question_attempt $qa the newly added question attempt.

notify_attempt_modified(question_attempt $qa)   X-Ref
Called when the fields of a question attempt in this usage are modified.

param: question_attempt $qa the newly added question attempt.

notify_attempt_moved(question_attempt $qa, $oldslot)   X-Ref
Called when a question_attempt has been moved to a new slot.

param: question_attempt $qa The question attempt that was moved.
param: int $oldslot The previous slot number of that attempt.

notify_step_added(question_attempt_step $step, question_attempt $qa, $seq)   X-Ref
Called when a new step is added to a question attempt in this usage.

param: question_attempt_step $step the new step.
param: question_attempt $qa the usage it is being added to.
param: int $seq the sequence number of the new step.

notify_step_modified(question_attempt_step $step, question_attempt $qa, $seq)   X-Ref
Called when a new step is updated in a question attempt in this usage.

param: question_attempt_step $step the step that was updated.
param: question_attempt $qa the usage it is being added to.
param: int $seq the sequence number of the new step.

notify_step_deleted(question_attempt_step $step, question_attempt $qa)   X-Ref
Called when a new step is updated in a question attempt in this usage.

param: question_attempt_step $step the step to delete.
param: question_attempt $qa the usage it is being added to.

notify_metadata_added(question_attempt $qa, $name)   X-Ref
Called when a new metadata variable is set on a question attempt in this usage.

param: question_attempt $qa the question attempt the metadata is being added to.
param: int $name the name of the metadata variable added.

notify_metadata_modified(question_attempt $qa, $name)   X-Ref
Called when a metadata variable on a question attempt in this usage is updated.

param: question_attempt $qa the question attempt where the metadata is being modified.
param: int $name the name of the metadata variable modified.

Class: question_usage_null_observer  - X-Ref

Null implmentation of the {@link question_usage_watcher} interface.
Does nothing.

notify_modified()   X-Ref
No description

notify_attempt_added(question_attempt $qa)   X-Ref
No description

notify_attempt_modified(question_attempt $qa)   X-Ref
No description

notify_attempt_moved(question_attempt $qa, $oldslot)   X-Ref
No description

notify_step_added(question_attempt_step $step, question_attempt $qa, $seq)   X-Ref
No description

notify_step_modified(question_attempt_step $step, question_attempt $qa, $seq)   X-Ref
No description

notify_step_deleted(question_attempt_step $step, question_attempt $qa)   X-Ref
No description

notify_metadata_added(question_attempt $qa, $name)   X-Ref
No description

notify_metadata_modified(question_attempt $qa, $name)   X-Ref
No description