Differences Between: [Versions 311 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
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_scorm\completion; 20 21 defined('MOODLE_INTERNAL') || die(); 22 23 use core_completion\activity_custom_completion; 24 25 require_once($CFG->dirroot.'/mod/scorm/locallib.php'); 26 27 /** 28 * Activity custom completion subclass for the scorm activity. 29 * 30 * Contains the class for defining mod_scorm's custom completion rules 31 * and fetching a scorm instance's completion statuses for a user. 32 * 33 * @package mod_scorm 34 * @copyright Michael Hawkins <michaelh@moodle.com> 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class custom_completion extends activity_custom_completion { 38 39 /** 40 * Fetches the completion state for a given completion rule. 41 * 42 * @param string $rule The completion rule. 43 * @return int The completion state. 44 */ 45 public function get_state(string $rule): int { 46 global $DB; 47 48 $this->validate_rule($rule); 49 50 // Base query used when fetching user's tracks data. 51 $basequery = "SELECT v.id, v.scoid, e.element, v.value 52 FROM {scorm_scoes_value} v 53 JOIN {scorm_attempt} a ON a.id = v.attemptid 54 JOIN {scorm_element} e ON e.id = v.elementid 55 WHERE a.scormid = ? 56 AND a.userid = ?"; 57 58 switch ($rule) { 59 case 'completionstatusrequired': 60 $status = COMPLETION_INCOMPLETE; 61 $query = $basequery . 62 " AND e.element IN ( 63 'cmi.core.lesson_status', 64 'cmi.completion_status', 65 'cmi.success_status' 66 )"; 67 68 $tracks = $DB->get_records_sql($query, [$this->cm->instance, $this->userid]); 69 70 // Get available status list. 71 $statuses = array_flip(\scorm_status_options()); 72 73 $requiredcompletionstatusid = $this->cm->customdata['customcompletionrules']['completionstatusrequired'] ?? 0; 74 $isanystatus = ($requiredcompletionstatusid == array_sum($statuses)); 75 76 // Check at least one track meets the required completion status value(s). 77 foreach ($tracks as $track) { 78 if (array_key_exists($track->value, $statuses) 79 && ($isanystatus || $statuses[$track->value] == $requiredcompletionstatusid)) { 80 $status = COMPLETION_COMPLETE; 81 break; 82 } 83 } 84 85 break; 86 87 case 'completionscorerequired': 88 $status = COMPLETION_INCOMPLETE; 89 $query = $basequery . 90 " AND e.element IN ( 91 'cmi.core.score.raw', 92 'cmi.score.raw' 93 )"; 94 95 $tracks = $DB->get_records_sql($query, [$this->cm->instance, $this->userid]); 96 97 $requiredscore = $this->cm->customdata['customcompletionrules']['completionscorerequired']; 98 99 // Check if any track meets or exceeds the minimum score required. 100 foreach ($tracks as $track) { 101 if (strlen($track->value) && (floatval($track->value) >= $requiredscore)) { 102 $status = COMPLETION_COMPLETE; 103 104 // No need to check any other tracks once condition is confirmed completed. 105 break; 106 } 107 } 108 109 break; 110 111 case 'completionstatusallscos': 112 // Assume complete unless we find a sco that is not complete. 113 $status = COMPLETION_COMPLETE; 114 $query = $basequery . 115 " AND e.element IN ( 116 'cmi.core.lesson_status', 117 'cmi.completion_status', 118 'cmi.success_status' 119 )"; 120 121 $tracks = $DB->get_records_sql($query, [$this->cm->instance, $this->userid]); 122 123 // Get available status list. 124 $statuses = array_flip(\scorm_status_options()); 125 126 // Make a list of all sco IDs. 127 $scoids = []; 128 foreach ($tracks as $track) { 129 if (array_key_exists($track->value, $statuses)) { 130 $scoids[] = $track->scoid; 131 } 132 } 133 134 // Iterate over all scos and ensure each has a lesson_status. 135 $scos = $DB->get_records('scorm_scoes', ['scorm' => $this->cm->instance, 'scormtype' => 'sco']); 136 137 foreach ($scos as $sco) { 138 // If we find a sco without a lesson status, this condition is not completed. 139 if (!in_array($sco->id, $scoids)) { 140 $status = COMPLETION_INCOMPLETE; 141 } 142 } 143 144 break; 145 146 default: 147 $status = COMPLETION_INCOMPLETE; 148 break; 149 } 150 151 // If not yet meeting the requirement and no attempts remain to complete it, mark it as failed. 152 if ($status === COMPLETION_INCOMPLETE) { 153 $scorm = $DB->get_record('scorm', ['id' => $this->cm->instance]); 154 $attemptcount = scorm_get_attempt_count($this->userid, $scorm); 155 156 if ($scorm->maxattempt > 0 && $attemptcount >= $scorm->maxattempt) { 157 $status = COMPLETION_COMPLETE_FAIL; 158 } 159 } 160 161 return $status; 162 } 163 164 /** 165 * Fetch the list of custom completion rules that this module defines. 166 * 167 * @return array 168 */ 169 public static function get_defined_custom_rules(): array { 170 return [ 171 'completionstatusrequired', 172 'completionscorerequired', 173 'completionstatusallscos', 174 ]; 175 } 176 177 /** 178 * Returns an associative array of the descriptions of custom completion rules. 179 * 180 * @return array 181 */ 182 public function get_custom_rule_descriptions(): array { 183 $scorerequired = $this->cm->customdata['customcompletionrules']['completionscorerequired'] ?? 0; 184 185 // Prepare completion status requirements string. 186 $statusstrings = \scorm_status_options(); 187 $completionstatusid = $this->cm->customdata['customcompletionrules']['completionstatusrequired'] ?? 0; 188 189 if (array_key_exists($completionstatusid, $statusstrings)) { 190 // Single status required. 191 $statusrequired = $statusstrings[$completionstatusid]; 192 } else { 193 // All statuses required. 194 $statusrequired = 'completedorpassed'; 195 } 196 197 return [ 198 'completionstatusrequired' => get_string("completiondetail:completionstatus{$statusrequired}", 'scorm'), 199 'completionscorerequired' => get_string('completiondetail:completionscore', 'scorm', $scorerequired), 200 'completionstatusallscos' => get_string('completiondetail:allscos', 'scorm'), 201 ]; 202 } 203 204 /** 205 * Returns an array of all completion rules, in the order they should be displayed to users. 206 * 207 * @return array 208 */ 209 public function get_sort_order(): array { 210 return [ 211 'completionview', 212 'completionstatusallscos', 213 'completionstatusrequired', 214 'completionusegrade', 215 'completionpassgrade', 216 'completionscorerequired', 217 ]; 218 } 219 } 220
title
Description
Body
title
Description
Body
title
Description
Body
title
Body