Differences Between: [Versions 311 and 402] [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 } else { 156 if (function_exists($this->cminfo->modname . '_get_completion_state')) { 157 // If the plugin does not have the custom completion implementation but implements the get_completion_state() callback, 158 // fallback to displaying the overall completion state of the activity. 159 $details = [ 160 'plugincompletionstate' => (object)[ 161 'status' => $this->get_overall_completion(), 162 'description' => get_string('completeactivity', 'completion') 163 ] 164 ]; 165 } 166 } 167 168 return $details; 169 } 170 171 /** 172 * Sort completion details in the order specified by the activity's custom completion implementation. 173 * 174 * @param array $details The completion details to be sorted. 175 * @return array 176 * @throws \coding_exception 177 */ 178 protected function sort_completion_details(array $details): array { 179 $sortorder = $this->cmcompletion->get_sort_order(); 180 $sorteddetails = []; 181 182 foreach ($sortorder as $sortedkey) { 183 if (isset($details[$sortedkey])) { 184 $sorteddetails[$sortedkey] = $details[$sortedkey]; 185 } 186 } 187 188 // Make sure the sorted list includes all of the conditions that were set. 189 if (count($sorteddetails) < count($details)) { 190 $exceptiontext = get_class($this->cmcompletion) .'::get_sort_order() is missing one or more completion conditions.' . 191 ' All custom and standard conditions that apply to this activity must be listed.'; 192 throw new \coding_exception($exceptiontext); 193 } 194 195 return $sorteddetails; 196 } 197 198 /** 199 * Fetches the overall completion state of this course module. 200 * 201 * @return int The overall completion state for this course module. 202 */ 203 public function get_overall_completion(): int { 204 return (int)$this->completiondata->completionstate; 205 } 206 207 /** 208 * Whether this activity module has completion enabled. 209 * 210 * @return bool 211 */ 212 public function has_completion(): bool { 213 return $this->completioninfo->is_enabled($this->cminfo) != COMPLETION_DISABLED; 214 } 215 216 /** 217 * Whether this activity module instance tracks completion automatically. 218 * 219 * @return bool 220 */ 221 public function is_automatic(): bool { 222 return $this->cminfo->completion == COMPLETION_TRACKING_AUTOMATIC; 223 } 224 225 /** 226 * Fetches the user ID that has overridden the completion state of this activity for the user. 227 * 228 * @return int|null 229 */ 230 public function overridden_by(): ?int { 231 return isset($this->completiondata->overrideby) ? (int)$this->completiondata->overrideby : null; 232 } 233 234 /** 235 * Checks whether completion is being tracked for this user. 236 * 237 * @return bool 238 */ 239 public function is_tracked_user(): bool { 240 return $this->completioninfo->is_tracked_user($this->userid); 241 } 242 243 /** 244 * Determine whether to show the manual completion or not. 245 * 246 * @return bool 247 */ 248 public function show_manual_completion(): bool { 249 global $PAGE; 250 251 if ($PAGE->context->contextlevel == CONTEXT_MODULE) { 252 // Manual completion should always be shown on the activity page. 253 return true; 254 } else { 255 $course = $this->cminfo->get_course(); 256 if ($course->showcompletionconditions == COMPLETION_SHOW_CONDITIONS) { 257 return true; 258 } else if ($this->cmcompletion) { 259 return $this->cmcompletion->manual_completion_always_shown(); 260 } 261 } 262 263 return false; 264 } 265 266 /** 267 * Completion state timemodified 268 * 269 * @return int timestamp 270 */ 271 public function get_timemodified(): int { 272 return (int)$this->completiondata->timemodified; 273 } 274 275 /** 276 * Generates an instance of this class. 277 * 278 * @param cm_info $cminfo The course module info instance. 279 * @param int $userid The user ID that we're fetching completion details for. 280 * @param bool $returndetails Whether to return completion details or not. 281 * @return cm_completion_details 282 */ 283 public static function get_instance(cm_info $cminfo, int $userid, bool $returndetails = true): cm_completion_details { 284 $course = $cminfo->get_course(); 285 $completioninfo = new \completion_info($course); 286 return new self($completioninfo, $cminfo, $userid, $returndetails); 287 } 288 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body