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 /** 18 * Contains the class for building the user's activity completion details. 19 * 20 * @package core_completion 21 * @copyright 2021 Jun Pataleta <jun@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 declare(strict_types = 1); 26 27 namespace core_completion; 28 29 use cm_info; 30 use completion_info; 31 32 /** 33 * Class for building the user's activity completion details. 34 * 35 * @package core_completion 36 * @copyright 2021 Jun Pataleta <jun@moodle.com> 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class cm_completion_details { 40 /** @var completion_info The completion info instance for this cm's course. */ 41 protected $completioninfo = null; 42 43 /** @var object The completion data. */ 44 protected $completiondata = null; 45 46 /** @var cm_info The course module information. */ 47 protected $cminfo = null; 48 49 /** @var int The user ID. */ 50 protected $userid = 0; 51 52 /** @var bool Whether to return automatic completion details. */ 53 protected $returndetails = true; 54 55 /** @var activity_custom_completion Activity custom completion object. */ 56 protected $cmcompletion = null; 57 58 /** 59 * Constructor. 60 * 61 * @param completion_info $completioninfo The completion info instance for this cm's course. 62 * @param cm_info $cminfo The course module information. 63 * @param int $userid The user ID. 64 * @param bool $returndetails Whether to return completion details or not. 65 */ 66 public function __construct(completion_info $completioninfo, cm_info $cminfo, int $userid, bool $returndetails = true) { 67 $this->completioninfo = $completioninfo; 68 // We need to pass wholecourse = true here for better performance. All the course's completion data for the current 69 // logged-in user will get in a single query instead of multiple queries and loaded to cache. 70 $this->completiondata = $completioninfo->get_data($cminfo, true, $userid); 71 $this->cminfo = $cminfo; 72 $this->userid = $userid; 73 $this->returndetails = $returndetails; 74 $cmcompletionclass = activity_custom_completion::get_cm_completion_class($this->cminfo->modname); 75 if ($cmcompletionclass) { 76 $this->cmcompletion = new $cmcompletionclass( 77 $this->cminfo, 78 $this->userid, 79 $completioninfo->get_core_completion_state($cminfo, $userid) 80 ); 81 } 82 } 83 84 /** 85 * Fetches the completion details for a user. 86 * 87 * @return array An array of completion details for a user containing the completion requirement's description and status. 88 * @throws \coding_exception 89 */ 90 public function get_details(): array { 91 if (!$this->is_automatic()) { 92 // No details need to be returned for modules that don't have automatic completion tracking enabled. 93 return []; 94 } 95 96 if (!$this->returndetails) { 97 // We don't need to return completion details. 98 return []; 99 } 100 101 $completiondata = $this->completiondata; 102 $hasoverride = !empty($this->overridden_by()); 103 104 $details = []; 105 106 // Completion rule: Student must view this activity. 107 if (!empty($this->cminfo->completionview)) { 108 if (!$hasoverride) { 109 $status = COMPLETION_INCOMPLETE; 110 if ($completiondata->viewed == COMPLETION_VIEWED) { 111 $status = COMPLETION_COMPLETE; 112 } 113 } else { 114 $status = $completiondata->completionstate; 115 } 116 117 $details['completionview'] = (object)[ 118 'status' => $status, 119 'description' => get_string('detail_desc:view', 'completion'), 120 ]; 121 } 122 123 // Completion rule: Student must receive a grade. 124 if (!is_null($this->cminfo->completiongradeitemnumber)) { 125 if (!$hasoverride) { 126 $status = $completiondata->completiongrade ?? COMPLETION_INCOMPLETE; 127 } else { 128 $status = $completiondata->completionstate; 129 } 130 131 $details['completionusegrade'] = (object)[ 132 'status' => $status, 133 'description' => get_string('detail_desc:receivegrade', 'completion'), 134 ]; 135 136 if (!is_null($this->cminfo->completionpassgrade) && $this->cminfo->completionpassgrade) { 137 $details['completionpassgrade'] = (object)[ 138 'status' => $completiondata->passgrade ?? COMPLETION_INCOMPLETE, 139 'description' => get_string('detail_desc:receivepassgrade', 'completion'), 140 ]; 141 } 142 } 143 144 if ($this->cmcompletion) { 145 if (isset($completiondata->customcompletion)) { 146 foreach ($completiondata->customcompletion as $rule => $status) { 147 $details[$rule] = (object)[ 148 'status' => !$hasoverride ? $status : $completiondata->completionstate, 149 'description' => $this->cmcompletion->get_custom_rule_description($rule), 150 ]; 151 } 152 153 $details = $this->sort_completion_details($details); 154 } 155 } 156 157 return $details; 158 } 159 160 /** 161 * Sort completion details in the order specified by the activity's custom completion implementation. 162 * 163 * @param array $details The completion details to be sorted. 164 * @return array 165 * @throws \coding_exception 166 */ 167 protected function sort_completion_details(array $details): array { 168 $sortorder = $this->cmcompletion->get_sort_order(); 169 $sorteddetails = []; 170 171 foreach ($sortorder as $sortedkey) { 172 if (isset($details[$sortedkey])) { 173 $sorteddetails[$sortedkey] = $details[$sortedkey]; 174 } 175 } 176 177 // Make sure the sorted list includes all of the conditions that were set. 178 if (count($sorteddetails) < count($details)) { 179 $exceptiontext = get_class($this->cmcompletion) .'::get_sort_order() is missing one or more completion conditions.' . 180 ' All custom and standard conditions that apply to this activity must be listed.'; 181 throw new \coding_exception($exceptiontext); 182 } 183 184 return $sorteddetails; 185 } 186 187 /** 188 * Fetches the overall completion state of this course module. 189 * 190 * @return int The overall completion state for this course module. 191 */ 192 public function get_overall_completion(): int { 193 return (int)$this->completiondata->completionstate; 194 } 195 196 /** 197 * Returns whether the overall completion state of this course module should be marked as complete or not. 198 * This is based on the completion settings of the course module, so when the course module requires a passing grade, 199 * it will only be marked as complete when the user has passed the course module. Otherwise, it will be marked as complete 200 * even when the user has failed the course module. 201 * 202 * @return bool True when the module can be marked as completed. 203 */ 204 public function is_overall_complete(): bool { 205 $completionstates = []; 206 if ($this->is_manual()) { 207 $completionstates = [COMPLETION_COMPLETE]; 208 } else if ($this->is_automatic()) { 209 // Successfull completion states depend on the completion settings. 210 if (isset($this->completiondata->passgrade)) { 211 // Passing grade is required. Don't mark it as complete when state is COMPLETION_COMPLETE_FAIL. 212 $completionstates = [COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS]; 213 } else { 214 // Any grade is required. Mark it as complete even when state is COMPLETION_COMPLETE_FAIL. 215 $completionstates = [COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS, COMPLETION_COMPLETE_FAIL]; 216 } 217 } 218 219 return in_array($this->get_overall_completion(), $completionstates); 220 } 221 222 /** 223 * Whether this activity module has completion enabled. 224 * 225 * @return bool 226 */ 227 public function has_completion(): bool { 228 return $this->completioninfo->is_enabled($this->cminfo) != COMPLETION_DISABLED; 229 } 230 231 /** 232 * Whether this activity module instance tracks completion automatically. 233 * 234 * @return bool 235 */ 236 public function is_automatic(): bool { 237 return $this->cminfo->completion == COMPLETION_TRACKING_AUTOMATIC; 238 } 239 240 /** 241 * Whether this activity module instance tracks completion manually. 242 * 243 * @return bool 244 */ 245 public function is_manual(): bool { 246 return $this->cminfo->completion == COMPLETION_TRACKING_MANUAL; 247 } 248 249 /** 250 * Fetches the user ID that has overridden the completion state of this activity for the user. 251 * 252 * @return int|null 253 */ 254 public function overridden_by(): ?int { 255 return isset($this->completiondata->overrideby) ? (int)$this->completiondata->overrideby : null; 256 } 257 258 /** 259 * Checks whether completion is being tracked for this user. 260 * 261 * @return bool 262 */ 263 public function is_tracked_user(): bool { 264 return $this->completioninfo->is_tracked_user($this->userid); 265 } 266 267 /** 268 * Determine whether to show the manual completion or not. 269 * 270 * @return bool 271 */ 272 public function show_manual_completion(): bool { 273 global $PAGE; 274 275 if (!$this->is_manual()) { 276 return false; 277 } 278 279 if ($PAGE->context->contextlevel == CONTEXT_MODULE) { 280 // Manual completion should always be shown on the activity page. 281 return true; 282 } else { 283 $course = $this->cminfo->get_course(); 284 if ($course->showcompletionconditions == COMPLETION_SHOW_CONDITIONS) { 285 return true; 286 } else if ($this->cmcompletion) { 287 return $this->cmcompletion->manual_completion_always_shown(); 288 } 289 } 290 291 return false; 292 } 293 294 /** 295 * Completion state timemodified 296 * 297 * @return int timestamp 298 */ 299 public function get_timemodified(): int { 300 return (int)$this->completiondata->timemodified; 301 } 302 303 /** 304 * Generates an instance of this class. 305 * 306 * @param cm_info $cminfo The course module info instance. 307 * @param int $userid The user ID that we're fetching completion details for. 308 * @param bool $returndetails Whether to return completion details or not. 309 * @return cm_completion_details 310 */ 311 public static function get_instance(cm_info $cminfo, int $userid, bool $returndetails = true): cm_completion_details { 312 $course = $cminfo->get_course(); 313 $completioninfo = new \completion_info($course); 314 return new self($completioninfo, $cminfo, $userid, $returndetails); 315 } 316 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body