Skip to main content
Version: main (5.0)

Quiz access rule sub-plugins

Quiz access rule sub-plugins extend the ability to add conditions a user must meet to attempt a given quiz.

The following rules are readily available as part of Moodle core:

  • quizaccess_delaybetweenattempts
  • quizaccess_ipaddress
  • quizaccess_numattempts
  • quizaccess_offlineattempts
  • quizaccess_openclosedate
  • quizaccess_password
  • quizaccess_seb
  • quizaccess_securewindow
  • quizaccess_timelimit

File structure

Quiz access rule sub-plugins are located in the /mod/quiz/accessrule directory. A plugin should not include any custom files outside of it's own plugin folder.

Each plugin is in a separate subdirectory and consists of a number of mandatory files and any other files the developer is going to use.

View an example directory layout for the quizaccess_delaybetweenattempts plugin.
mod/quiz/accessrule/delaybetweenattempts
├── classes
│   └── privacy
│   └── provider.php
├── lang
│   └── en
│   └── quizaccess_delaybetweenattempts.php
├── tests
│   └── rule_test.php
├── rule.php
└── version.php

Some of the important files for the format plugintype are described below. See the common plugin files documentation for details of other files which may be useful in your plugin.

rule.php

Rule definition class

Required
File path: /rule.php

The rule class defines the behaviour of your rule and how it will restrict access for users attempting a quiz.

Please refer to the inline phpdocs of the mod_quiz::access_rule_base class for detailed descriptions of the functions and meaning.

View example
[path/to/quizaccessrule]/pluginname/rule.php
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Rule definition class for the quizaccessrule_pluginname plugin.
*
* @package quizaccessrule_pluginname
* @copyright Year, You Name <your@email.address>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

use mod_quiz\form\edit_override_form;
use mod_quiz\form\preflight_check_form;
use mod_quiz\quiz_settings;
use mod_quiz\local\access_rule_base;
use mod_quiz_mod_form;
use MoodleQuickForm;

class quizaccess_pluginname extends access_rule_base {

/**
* Below are methods inherited from mod_quiz\local\access_rule_base. All of these functions,
* are optional to rewrite - although it depends on the behaviour of your rule which will
* determine which functions should be reimplemented.
*/

public function __construct($quizobj, $timenow) {
$this->quizobj = $quizobj;
$this->quiz = $quizobj->get_quiz();
$this->timenow = $timenow;
}

public static function make(quiz_settings $quizobj, $timenow, $canignoretimelimits) {
return null;
}

public function prevent_new_attempt($numprevattempts, $lastattempt) {
return false;
}

public function prevent_access() {
return false;
}

public function is_preflight_check_required($attemptid) {
return false;
}

public function add_preflight_check_form_fields(preflight_check_form $quizform,
MoodleQuickForm $mform, $attemptid) {
// Do nothing by default.
}

public function validate_preflight_check($data, $files, $errors, $attemptid) {
return $errors;
}

public function notify_preflight_check_passed($attemptid) {
// Do nothing by default.
}

public function current_attempt_finished() {
// Do nothing by default.
}

public function description() {
return '';
}

public function is_finished($numprevattempts, $lastattempt) {
return false;
}

public function end_time($attempt) {
return false;
}

public function time_left_display($attempt, $timenow) {
$endtime = $this->end_time($attempt);
if ($endtime === false) {
return false;
}
return $endtime - $timenow;
}

public function attempt_must_be_in_popup() {
return false;
}

public function get_popup_options() {
return [];
}

public function setup_attempt_page($page) {
// Do nothing by default.
}

public function get_superceded_rules() {
return [];
}

public static function add_settings_form_fields(
mod_quiz_mod_form $quizform, MoodleQuickForm $mform) {
// By default do nothing.
}

public static function validate_settings_form_fields(array $errors,
array $data, $files, mod_quiz_mod_form $quizform) {
return $errors;
}

public static function get_browser_security_choices() {
return [];
}

public static function save_settings($quiz) {
// By default do nothing.
}

public static function delete_settings($quiz) {
// By default do nothing.
}

public static function get_settings_sql($quizid) {
return ['', '', []];
}

public static function get_extra_settings($quizid) {
return [];
}
}

Rule definition class with override

File path: /rule.php

Most quiz settings can be overridden on a per user and/or group level and you can extend this ability to your rule as well. To make your rule overridable, you must implement the rule_overridable interface in your rule class definition.

Please refer to the inline phpdocs of the mod_quiz::rule_overridable interface for detailed descriptions of the functions and meaning.

View example
[path/to/quizaccessrule]/pluginname/rule.php
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Rule definition class with override for the quizaccessrule_pluginname plugin.
*
* @package quizaccessrule_pluginname
* @copyright Year, You Name <your@email.address>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

use mod_quiz\form\edit_override_form;
use mod_quiz\local\access_rule_base;
use mod_quiz\local\rule_overridable;
use MoodleQuickForm;

class quizaccess_pluginname extends access_rule_base implements rule_overridable {

/**
* All of the below rule_overridable interface functions will need to be implemented.
*/

public static function add_override_form_fields(edit_override_form $quizform, MoodleQuickForm $mform): void {
// Use the $mform to add the rule override fields...
$mform->addElement(
'select',
'plgn_setting1',
get_string('plgn_setting1', 'quizaccess_pluginname'),
['A', 'B', 'C'],
);

$mform->addElement(
'select',
'plgn_setting2',
get_string('plgn_setting2', 'quizaccess_pluginname'),
['1', '2', '3'],
);
}

public static function get_override_form_section_header(): array {
// Return the label and content of the section header in an array.
return ['name' => 'pluginname', 'title' => get_string('pluginname', 'quizaccess_pluginname')];
}

public static function get_override_form_section_expand(edit_override_form $quizform): bool {
// Determine if rule section in override form should load expanded.
// Should typically return true if the quiz has existing rule settings.
global $DB;
return $DB->record_exists('quizaccess_pluginname', ['quiz' => $quizform->get_quiz()->id]);
}

public static function validate_override_form_fields(array $errors,
array $data, array $files, edit_override_form $quizform): array {
// Check and push to $errors array...
return $errors;
}

public static function save_override_settings(array $override): void {
// Save $override data to plugin settings table...
global $DB;

$plgnoverride = (object)[
'overrideid' => $override['overrideid'],
'setting1' => $override['plgnm_setting1'],
'setting2' => $override['plgnm_setting2'],
];

if ($plgnoverrideid = $DB->get_field('quizaccess_pluginname_overrides', 'id', ['overrideid' => $override['overrideid']])) {
$plgnoverride->id = $plgnoverrideid;
$DB->update_record('quizaccess_pluginname_overrides', $plgnoverride);
} else {
$DB->insert_record('quizaccess_pluginname_overrides', $plgnoverride);
}
}

public static function delete_override_settings($quizid, $overrides): void {
// Remove $overrides from $quiz.
global $DB;
$ids = array_column($overrides, 'id');
list($insql, $inparams) = $DB->get_in_or_equal($ids);
$DB->delete_records_select('quizaccess_pluginname_overrides', "id $insql", $inparams);
}

public static function get_override_setting_keys(): array {
// Return string array of all override form setting keys.
return ['plgnm_setting1', 'plgnm_setting2'];
}

public static function get_override_required_setting_keys(): array {
// Return string array of override form setting keys that are required.
return ['plgnm_setting1'];
}

public static function get_override_settings_sql($overridetablename): array {
// Return an array of selects, joins and parameters to be used to query relevant rule overrides...
return [
"plgnm.setting1 plgnm_setting1, plgnm.setting2 plgnm_setting2",
"LEFT JOIN {quizaccess_pluginname_overrides} plgnm ON plgnm.overrideid = {$overridetablename}.id",
[],
];
}

public static function add_override_table_fields($override, $fields, $values, $context): array {
// Extend the override table view by adding fields and values that display the rule's overrides.
if (!empty($override->plgnm_setting1)) {
$fields[] = get_string('pluginname', 'quizaccess_pluginname');
$values[] = "{$override->plgnm_setting1}, {$override->plgnm_setting2}";
}
return [$fields, $values];
}
}
info

Implementing rule_overridable is not required but can enhance the usability of the rule.