Skip to content

Commit

Permalink
MDL-80945 quiz: Add hooks to override access settings.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Kotlyar committed Dec 16, 2024
1 parent aa55f38 commit a279da1
Show file tree
Hide file tree
Showing 7 changed files with 406 additions and 22 deletions.
144 changes: 144 additions & 0 deletions mod/quiz/classes/access_manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace mod_quiz;

use core_component;
use mod_quiz\form\edit_override_form;
use mod_quiz\form\preflight_check_form;
use mod_quiz\local\access_rule_base;
use mod_quiz\output\renderer;
Expand Down Expand Up @@ -103,6 +104,17 @@ protected static function get_rule_classes(): array {
return core_component::get_plugin_list_with_class('quizaccess', '', 'rule.php');
}

/**
* Get the names of overridable rule classes.
*
* @return array of class names.
*/
protected static function get_overridable_rule_classes(): array {
return array_filter(self::get_rule_classes(), function($rule) {
return in_array(\mod_quiz\local\access_rule_overridable::class, class_implements($rule));
});
}

/**
* Add any form fields that the access rules require to the settings form.
*
Expand Down Expand Up @@ -279,6 +291,138 @@ public static function load_quiz_and_settings(int $quizid): stdClass {
return $quiz;
}

/**
* Add any form fields that the access rules require to the override form.
*
* Note that the standard plugins do not use this mechanism, becuase all their
* settings are stored in the quiz table.
*
* @param edit_override_form $quizform the quiz override settings form being built.
* @param MoodleQuickForm $mform the wrapped MoodleQuickForm.
* @return boolean return true if fields have been added.
*/
public static function add_override_form_fields(
edit_override_form $quizform, MoodleQuickForm $mform): bool {
$fieldsadded = false;
foreach (self::get_overridable_rule_classes() as $rule) {
$element = $rule::get_override_form_section_header();
$mform->addElement('header', $element['name'], $element['title']);
$mform->setExpanded($element['name'], $rule::get_override_form_section_expand($quizform));
$rule::add_override_form_fields($quizform, $mform);
$fieldsadded = true;
}
return $fieldsadded;
}

/**
* Validate the data from any form fields added using {@see add_override_form_fields()}.
*
* @param array $errors the errors found so far.
* @param array $data the submitted form data.
* @param array $files information about any uploaded files.
* @param edit_override_form $quizform the quiz override form object.
* @return array $errors the updated $errors array.
*/
public static function validate_override_form_fields(array $errors,
array $data, array $files, edit_override_form $quizform): array {
foreach (self::get_overridable_rule_classes() as $rule) {
$errors = $rule::validate_override_form_fields($errors, $data, $files, $quizform);
}
return $errors;
}

/**
* Save any submitted settings when the quiz override settings form is submitted.
*
* @param array $override data from the override form.
* @return void
*/
public static function save_override_settings(array $override): void {
foreach (self::get_overridable_rule_classes() as $rule) {
$rule::save_override_settings($override);
}
}

/**
* Delete any rule-specific override settings when the quiz override is deleted.
*
* @param int $quizid all overrides being deleted should belong to the same quiz.
* @param array $overrides an array of override objects to be deleted.
* @return void
*/
public static function delete_override_settings($quizid, $overrides): void {
foreach (self::get_overridable_rule_classes() as $rule) {
$rule::delete_override_settings($quizid, $overrides);
}
}

/**
* Get components of the SQL query to fetch the access rule components' override
* settings. To be used as part of a quiz_override query to reference.
*
* @param string $overridetablename Name of the table to reference for joins.
* @return array 'selects', 'joins' and 'params'.
*/
public static function get_override_settings_sql($overridetablename = 'quiz_overrides'): array {
$allfields = [];
$alljoins = [];
$allparams = [];

foreach (self::get_overridable_rule_classes() as $rule) {
[$fields, $joins, $params] = $rule::get_override_settings_sql($overridetablename);
$fields && $allfields[] = $fields;
$joins && $alljoins[] = $joins;
$params && $allparams += $params;
}

$allfields = implode(', ', $allfields);
$alljoins = implode(' ', $alljoins);

return [$allfields, $alljoins, $allparams];
}

/**
* Retrieve all keys of fields to be used in the override form.
*
* @return array
*/
public static function get_override_setting_keys(): array {
$keys = [];
foreach (self::get_overridable_rule_classes() as $rule) {
$keys += $rule::get_override_setting_keys();
}
return $keys;
}

/**
* Retrieve keys of fields that are required to be filled in.
*
* @return array
*/
public static function get_override_required_setting_keys(): array {
$keys = [];
foreach (self::get_overridable_rule_classes() as $rule) {
$keys += $rule::get_override_required_setting_keys();
}
return $keys;
}

/**
* Update fields and values of the override table using the override settings.
*
* @param object $override the override data to use to update the $fields and $values.
* @param array $fields the fields to populate.
* @param array $values the fields to populate.
* @param context $context the context of which the override is being applied to.
* @return array
*/
public static function add_override_table_fields($override, $fields, $values, $context): array {
foreach (self::get_overridable_rule_classes() as $rule) {
[$fields, $values] = $rule::add_override_table_fields($override, $fields, $values, $context);
}
return [$fields, $values];
}

/**
* Get an array of the class names of all the active rules.
*
Expand Down
33 changes: 33 additions & 0 deletions mod/quiz/classes/form/edit_override_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use moodle_url;
use moodleform;
use stdClass;
use mod_quiz\access_manager;

defined('MOODLE_INTERNAL') || die();

Expand Down Expand Up @@ -84,6 +85,30 @@ public function __construct(moodle_url $submiturl,
parent::__construct($submiturl);
}

/**
* Return the course context for new modules, or the module context for existing modules.
* @return context_module
*/
public function get_context(): context_module {
return $this->context;
}

/**
* Get the quiz override ID.
* @return int
*/
public function get_overrideid(): int {
return $this->overrideid;
}

/**
* Get the quiz object.
* @return \stdClass
*/
public function get_quiz(): \stdClass {
return $this->quiz;
}

protected function definition() {
global $DB;

Expand Down Expand Up @@ -224,6 +249,11 @@ protected function definition() {
$mform->addHelpButton('attempts', 'attempts', 'quiz');
$mform->setDefault('attempts', $this->quiz->attempts);

// Access-rule fields.
if (access_manager::add_override_form_fields($this, $mform)) {
$mform->closeHeaderBefore('resetbutton');
}

// Submit buttons.
$mform->addElement('submit', 'resetbutton',
get_string('reverttodefaults', 'quiz'));
Expand Down Expand Up @@ -289,6 +319,9 @@ public function validation($data, $files): array {
}
}

// Apply access-rule validation.
$errors = access_manager::validate_override_form_fields($errors, $data, $files, $this);

return $errors;
}
}
120 changes: 120 additions & 0 deletions mod/quiz/classes/local/access_rule_overridable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?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/>.

namespace mod_quiz\local;

use mod_quiz\form\edit_override_form;
use MoodleQuickForm;

/**
* Class overridable
*
* @package mod_quiz
* @copyright 2024 Michael Kotlyar <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface access_rule_overridable {

/**
* Add fields to the quiz override form.
*
* @param edit_override_form $quizform the quiz override settings form being built.
* @param MoodleQuickForm $mform the wrapped MoodleQuickForm.
* @return void
*/
public static function add_override_form_fields(edit_override_form $quizform, MoodleQuickForm $mform): void;

/**
* Override form section header.
*
* Array must have three keys. The 'name' key for the name of the heading element, the 'title' key for the
* text to display in the heading and true/false for the 'expand' key to determine if the section containing
* these fields should be expanded.
*
* @return array [name, title]
*/
public static function get_override_form_section_header(): array;

/**
* Determine whether the rule section should be expanded or not in the override form.
*
* @param edit_override_form $quizform the quiz override settings form being built.
* @return bool return true if section should be expanded.
*/
public static function get_override_form_section_expand(edit_override_form $quizform): bool;

/* Validate the data from any form fields added using {@see add_override_form_fields()}.
*
* @param array $errors the errors found so far.
* @param array $data the submitted form data.
* @param array $files information about any uploaded files.
* @param edit_override_form $quizform the quiz override form object.
* @return array the updated $errors array.
*/
public static function validate_override_form_fields(array $errors,
array $data, array $files, edit_override_form $quizform): array;

/**
* Save any submitted settings when the quiz override settings form is submitted.
*
* @param array $override data from the override form.
* @return void
*/
public static function save_override_settings(array $override): void;

/**
* Delete any rule-specific override settings when the quiz override is deleted.
*
* @param int $quizid all overrides being deleted should belong to the same quiz.
* @param array $overrides an array of override objects to be deleted.
* @return void
*/
public static function delete_override_settings($quizid, $overrides): void;

/**
* Provide form field keys in the override form as a string array
*
* @return array e.g. ['rule_enabled', 'rule_password'].
*/
public static function get_override_setting_keys(): array;

/**
* Provide required form field keys in the override form as a string array
*
* @return array e.g. ['rule_enabled'].
*/
public static function get_override_required_setting_keys(): array;

/**
* Get components of the SQL query to fetch the access rule components' override
* settings. To be used as part of a quiz_override query to reference.
*
* @param string $overridetablename Name of the table to reference for joins.
* @return array [$selects, $joins, $params']
*/
public static function get_override_settings_sql($overridetablename): array;

/**
* Update fields and values of the override table using the override settings.
*
* @param object $override the override data to use to update the $fields and $values.
* @param array $fields the fields to populate.
* @param array $values the fields to populate.
* @param context $context the context of which the override is being applied to.
* @return array [$fields, $values]
*/
public static function add_override_table_fields($override, $fields, $values, $context): array;
}
Loading

0 comments on commit a279da1

Please sign in to comment.