Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 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($this->cminfo, $this->userid); 77 } 78 } 79 80 /** 81 * Fetches the completion details for a user. 82 * 83 * @return array An array of completion details for a user containing the completion requirement's description and status. 84 * @throws \coding_exception 85 */ 86 public function get_details(): array { 87 if (!$this->is_automatic()) { 88 // No details need to be returned for modules that don't have automatic completion tracking enabled. 89 return []; 90 } 91 92 if (!$this->returndetails) { 93 // We don't need to return completion details. 94 return []; 95 } 96 97 $completiondata = $this->completiondata; 98 $hasoverride = !empty($this->overridden_by()); 99 100 $details = []; 101 102 // Completion rule: Student must view this activity. 103 if (!empty($this->cminfo->completionview)) { 104 if (!$hasoverride) { 105 $status = COMPLETION_INCOMPLETE; 106 if ($completiondata->viewed == COMPLETION_VIEWED) { 107 $status = COMPLETION_COMPLETE; 108 } 109 } else { 110 $status = $completiondata->completionstate; 111 } 112 113 $details['completionview'] = (object)[ 114 'status' => $status, 115 'description' => get_string('detail_desc:view', 'completion'), 116 ]; 117 } 118 119 // Completion rule: Student must receive a grade. 120 if (!is_null($this->cminfo->completiongradeitemnumber)) { 121 if (!$hasoverride) { 122 $status = $completiondata->completiongrade ?? COMPLETION_INCOMPLETE; 123 } else { 124 $status = $completiondata->completionstate; 125 } 126 127 $details['completionusegrade'] = (object)[ 128 'status' => $status, 129 'description' => get_string('detail_desc:receivegrade', 'completion'), 130 ]; 131 } 132 133 if ($this->cmcompletion) { 134 if (isset($completiondata->customcompletion)) { 135 foreach ($completiondata->customcompletion as $rule => $status) { 136 $details[$rule] = (object)[ 137 'status' => !$hasoverride ? $status : $completiondata->completionstate, 138 'description' => $this->cmcompletion->get_custom_rule_description($rule), 139 ]; 140 } 141 142 $details = $this->sort_completion_details($details); 143 } 144 } else { 145 if (function_exists($this->cminfo->modname . '_get_completion_state')) { 146 // If the plugin does not have the custom completion implementation but implements the get_completion_state() callback, 147 // fallback to displaying the overall completion state of the activity. 148 $details = [ 149 'plugincompletionstate' => (object)[ 150 'status' => $this->get_overall_completion(), 151 'description' => get_string('completeactivity', 'completion') 152 ] 153 ]; 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 * Whether this activity module has completion enabled. 198 * 199 * @return bool 200 */ 201 public function has_completion(): bool { 202 return $this->completioninfo->is_enabled($this->cminfo) != COMPLETION_DISABLED; 203 } 204 205 /** 206 * Whether this activity module instance tracks completion automatically. 207 * 208 * @return bool 209 */ 210 public function is_automatic(): bool { 211 return $this->cminfo->completion == COMPLETION_TRACKING_AUTOMATIC; 212 } 213 214 /** 215 * Fetches the user ID that has overridden the completion state of this activity for the user. 216 * 217 * @return int|null 218 */ 219 public function overridden_by(): ?int { 220 return isset($this->completiondata->overrideby) ? (int)$this->completiondata->overrideby : null; 221 } 222 223 /** 224 * Checks whether completion is being tracked for this user. 225 * 226 * @return bool 227 */ 228 public function is_tracked_user(): bool { 229 return $this->completioninfo->is_tracked_user($this->userid); 230 } 231 232 /** 233 * Determine whether to show the manual completion or not. 234 * 235 * @return bool 236 */ 237 public function show_manual_completion(): bool { 238 global $PAGE; 239 240 if ($PAGE->context->contextlevel == CONTEXT_MODULE) { 241 // Manual completion should always be shown on the activity page. 242 return true; 243 } else { 244 $course = $this->cminfo->get_course(); 245 if ($course->showcompletionconditions == COMPLETION_SHOW_CONDITIONS) { 246 return true; 247 } else if ($this->cmcompletion) { 248 return $this->cmcompletion->manual_completion_always_shown(); 249 } 250 } 251 252 return false; 253 } 254 255 /** 256 * Completion state timemodified 257 * 258 * @return int timestamp 259 */ 260 public function get_timemodified(): int { 261 return (int)$this->completiondata->timemodified; 262 } 263 264 /** 265 * Generates an instance of this class. 266 * 267 * @param cm_info $cminfo The course module info instance. 268 * @param int $userid The user ID that we're fetching completion details for. 269 * @param bool $returndetails Whether to return completion details or not. 270 * @return cm_completion_details 271 */ 272 public static function get_instance(cm_info $cminfo, int $userid, bool $returndetails = true): cm_completion_details { 273 $course = $cminfo->get_course(); 274 $completioninfo = new \completion_info($course); 275 return new self($completioninfo, $cminfo, $userid, $returndetails); 276 } 277 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body