Differences Between: [Versions 311 and 402] [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 declare(strict_types=1); 18 19 namespace mod_quiz\completion; 20 21 use context_module; 22 use core_completion\activity_custom_completion; 23 use mod_quiz\quiz_settings; 24 use mod_quiz\access_manager; 25 26 /** 27 * Activity custom completion subclass for the quiz activity. 28 * 29 * Class for defining mod_quiz's custom completion rules and fetching the completion statuses 30 * of the custom completion rules for a given quiz instance and a user. 31 * 32 * @package mod_quiz 33 * @copyright 2021 Shamim Rezaie <shamim@moodle.com> 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class custom_completion extends activity_custom_completion { 37 38 /** 39 * Check passing grade (or no attempts left) requirement for completion. 40 * 41 * @return bool True if the passing grade (or no attempts left) requirement is disabled or met. 42 */ 43 protected function check_passing_grade_or_all_attempts(): bool { 44 global $CFG; 45 require_once($CFG->libdir . '/gradelib.php'); 46 47 $completionpassorattempts = $this->cm->customdata['customcompletionrules']['completionpassorattemptsexhausted']; 48 49 if (empty($completionpassorattempts['completionpassgrade'])) { 50 return true; 51 } 52 53 if ($this->completionstate && 54 isset($this->completionstate['passgrade']) && 55 $this->completionstate['passgrade'] == COMPLETION_COMPLETE_PASS) { 56 return true; 57 } 58 59 // If a passing grade is required and exhausting all available attempts is not accepted for completion, 60 // then this quiz is not complete. 61 if (empty($completionpassorattempts['completionattemptsexhausted'])) { 62 return false; 63 } 64 65 // Check if all attempts are used up. 66 $attempts = quiz_get_user_attempts($this->cm->instance, $this->userid, 'finished', true); 67 if (!$attempts) { 68 return false; 69 } 70 $lastfinishedattempt = end($attempts); 71 $context = context_module::instance($this->cm->id); 72 $quizobj = quiz_settings::create((int) $this->cm->instance, $this->userid); 73 $accessmanager = new access_manager( 74 $quizobj, 75 time(), 76 has_capability('mod/quiz:ignoretimelimits', $context, $this->userid, false) 77 ); 78 79 return $accessmanager->is_finished(count($attempts), $lastfinishedattempt); 80 } 81 82 /** 83 * Check minimum attempts requirement for completion. 84 * 85 * @return bool True if minimum attempts requirement is disabled or met. 86 */ 87 protected function check_min_attempts() { 88 $minattempts = $this->cm->customdata['customcompletionrules']['completionminattempts']; 89 if (!$minattempts) { 90 return true; 91 } 92 93 // Check if the user has done enough attempts. 94 $attempts = quiz_get_user_attempts($this->cm->instance, $this->userid, 'finished', true); 95 return $minattempts <= count($attempts); 96 } 97 98 /** 99 * Fetches the completion state for a given completion rule. 100 * 101 * @param string $rule The completion rule. 102 * @return int The completion state. 103 */ 104 public function get_state(string $rule): int { 105 $this->validate_rule($rule); 106 107 switch ($rule) { 108 case 'completionpassorattemptsexhausted': 109 $status = static::check_passing_grade_or_all_attempts(); 110 break; 111 case 'completionminattempts': 112 $status = static::check_min_attempts(); 113 break; 114 } 115 116 return empty($status) ? COMPLETION_INCOMPLETE : COMPLETION_COMPLETE; 117 } 118 119 /** 120 * Fetch the list of custom completion rules that this module defines. 121 * 122 * @return array 123 */ 124 public static function get_defined_custom_rules(): array { 125 return [ 126 'completionpassorattemptsexhausted', 127 'completionminattempts', 128 ]; 129 } 130 131 /** 132 * Returns an associative array of the descriptions of custom completion rules. 133 * 134 * @return array 135 */ 136 public function get_custom_rule_descriptions(): array { 137 $minattempts = $this->cm->customdata['customcompletionrules']['completionminattempts'] ?? 0; 138 $description['completionminattempts'] = get_string('completiondetail:minattempts', 'mod_quiz', $minattempts); 139 140 // Completion pass grade is now part of core. Only show the following if it's combined with min attempts. 141 $completionpassorattempts = $this->cm->customdata['customcompletionrules']['completionpassorattemptsexhausted'] ?? []; 142 if (!empty($completionpassorattempts['completionattemptsexhausted'])) { 143 $description['completionpassorattemptsexhausted'] = get_string('completiondetail:passorexhaust', 'mod_quiz'); 144 } 145 146 return $description; 147 } 148 149 /** 150 * Returns an array of all completion rules, in the order they should be displayed to users. 151 * 152 * @return array 153 */ 154 public function get_sort_order(): array { 155 return [ 156 'completionview', 157 'completionminattempts', 158 'completionusegrade', 159 'completionpassgrade', 160 'completionpassorattemptsexhausted', 161 ]; 162 } 163 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body