Differences Between: [Versions 310 and 311] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 used for the displaying the participants table. 19 * 20 * @package core_user 21 * @copyright 2017 Mark Nelson <markn@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 declare(strict_types=1); 25 26 namespace core_user\table; 27 28 use DateTime; 29 use context; 30 use core_table\dynamic as dynamic_table; 31 use core_table\local\filter\filterset; 32 use core_user\output\status_field; 33 use core_user\table\participants_search; 34 use moodle_url; 35 36 defined('MOODLE_INTERNAL') || die; 37 38 global $CFG; 39 40 require_once($CFG->libdir . '/tablelib.php'); 41 require_once($CFG->dirroot . '/user/lib.php'); 42 43 /** 44 * Class for the displaying the participants table. 45 * 46 * @package core_user 47 * @copyright 2017 Mark Nelson <markn@moodle.com> 48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 49 */ 50 class participants extends \table_sql implements dynamic_table { 51 52 /** 53 * @var int $courseid The course id 54 */ 55 protected $courseid; 56 57 /** 58 * @var string[] The list of countries. 59 */ 60 protected $countries; 61 62 /** 63 * @var \stdClass[] The list of groups with membership info for the course. 64 */ 65 protected $groups; 66 67 /** 68 * @var string[] Extra fields to display. 69 */ 70 protected $extrafields; 71 72 /** 73 * @var \stdClass $course The course details. 74 */ 75 protected $course; 76 77 /** 78 * @var context $context The course context. 79 */ 80 protected $context; 81 82 /** 83 * @var \stdClass[] List of roles indexed by roleid. 84 */ 85 protected $allroles; 86 87 /** 88 * @var \stdClass[] List of roles indexed by roleid. 89 */ 90 protected $allroleassignments; 91 92 /** 93 * @var \stdClass[] Assignable roles in this course. 94 */ 95 protected $assignableroles; 96 97 /** 98 * @var \stdClass[] Profile roles in this course. 99 */ 100 protected $profileroles; 101 102 /** 103 * @var filterset Filterset describing which participants to include. 104 */ 105 protected $filterset; 106 107 /** @var \stdClass[] $viewableroles */ 108 private $viewableroles; 109 110 /** @var moodle_url $baseurl The base URL for the report. */ 111 public $baseurl; 112 113 /** 114 * Render the participants table. 115 * 116 * @param int $pagesize Size of page for paginated displayed table. 117 * @param bool $useinitialsbar Whether to use the initials bar which will only be used if there is a fullname column defined. 118 * @param string $downloadhelpbutton 119 */ 120 public function out($pagesize, $useinitialsbar, $downloadhelpbutton = '') { 121 global $CFG, $OUTPUT, $PAGE; 122 123 // Define the headers and columns. 124 $headers = []; 125 $columns = []; 126 127 $bulkoperations = has_capability('moodle/course:bulkmessaging', $this->context); 128 if ($bulkoperations) { 129 $mastercheckbox = new \core\output\checkbox_toggleall('participants-table', true, [ 130 'id' => 'select-all-participants', 131 'name' => 'select-all-participants', 132 'label' => get_string('selectall'), 133 'labelclasses' => 'sr-only', 134 'classes' => 'm-1', 135 'checked' => false, 136 ]); 137 $headers[] = $OUTPUT->render($mastercheckbox); 138 $columns[] = 'select'; 139 } 140 141 $headers[] = get_string('fullname'); 142 $columns[] = 'fullname'; 143 144 $extrafields = \core_user\fields::get_identity_fields($this->context); 145 foreach ($extrafields as $field) { 146 $headers[] = \core_user\fields::get_display_name($field); 147 $columns[] = $field; 148 } 149 150 $headers[] = get_string('roles'); 151 $columns[] = 'roles'; 152 153 // Get the list of fields we have to hide. 154 $hiddenfields = array(); 155 if (!has_capability('moodle/course:viewhiddenuserfields', $this->context)) { 156 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); 157 } 158 159 // Add column for groups if the user can view them. 160 $canseegroups = !isset($hiddenfields['groups']); 161 if ($canseegroups) { 162 $headers[] = get_string('groups'); 163 $columns[] = 'groups'; 164 } 165 166 // Do not show the columns if it exists in the hiddenfields array. 167 if (!isset($hiddenfields['lastaccess'])) { 168 if ($this->courseid == SITEID) { 169 $headers[] = get_string('lastsiteaccess'); 170 } else { 171 $headers[] = get_string('lastcourseaccess'); 172 } 173 $columns[] = 'lastaccess'; 174 } 175 176 $canreviewenrol = has_capability('moodle/course:enrolreview', $this->context); 177 if ($canreviewenrol && $this->courseid != SITEID) { 178 $columns[] = 'status'; 179 $headers[] = get_string('participationstatus', 'enrol'); 180 $this->no_sorting('status'); 181 }; 182 183 $this->define_columns($columns); 184 $this->define_headers($headers); 185 186 // The name column is a header. 187 $this->define_header_column('fullname'); 188 189 // Make this table sorted by last name by default. 190 $this->sortable(true, 'lastname'); 191 192 $this->no_sorting('select'); 193 $this->no_sorting('roles'); 194 if ($canseegroups) { 195 $this->no_sorting('groups'); 196 } 197 198 $this->set_default_per_page(20); 199 200 $this->set_attribute('id', 'participants'); 201 202 $this->countries = get_string_manager()->get_list_of_countries(true); 203 $this->extrafields = $extrafields; 204 if ($canseegroups) { 205 $this->groups = groups_get_all_groups($this->courseid, 0, 0, 'g.*', true); 206 } 207 208 // If user has capability to review enrol, show them both role names. 209 $allrolesnamedisplay = ($canreviewenrol ? ROLENAME_BOTH : ROLENAME_ALIAS); 210 $this->allroles = role_fix_names(get_all_roles($this->context), $this->context, $allrolesnamedisplay); 211 $this->assignableroles = get_assignable_roles($this->context, ROLENAME_BOTH, false); 212 $this->profileroles = get_profile_roles($this->context); 213 $this->viewableroles = get_viewable_roles($this->context); 214 215 parent::out($pagesize, $useinitialsbar, $downloadhelpbutton); 216 217 if (has_capability('moodle/course:enrolreview', $this->context)) { 218 $params = [ 219 'contextid' => $this->context->id, 220 'uniqueid' => $this->uniqueid, 221 ]; 222 $PAGE->requires->js_call_amd('core_user/status_field', 'init', [$params]); 223 } 224 } 225 226 /** 227 * Generate the select column. 228 * 229 * @param \stdClass $data 230 * @return string 231 */ 232 public function col_select($data) { 233 global $OUTPUT; 234 235 $checkbox = new \core\output\checkbox_toggleall('participants-table', false, [ 236 'classes' => 'usercheckbox m-1', 237 'id' => 'user' . $data->id, 238 'name' => 'user' . $data->id, 239 'checked' => false, 240 'label' => get_string('selectitem', 'moodle', fullname($data)), 241 'labelclasses' => 'accesshide', 242 ]); 243 244 return $OUTPUT->render($checkbox); 245 } 246 247 /** 248 * Generate the fullname column. 249 * 250 * @param \stdClass $data 251 * @return string 252 */ 253 public function col_fullname($data) { 254 global $OUTPUT; 255 256 return $OUTPUT->user_picture($data, array('size' => 35, 'courseid' => $this->course->id, 'includefullname' => true)); 257 } 258 259 /** 260 * User roles column. 261 * 262 * @param \stdClass $data 263 * @return string 264 */ 265 public function col_roles($data) { 266 global $OUTPUT; 267 268 $roles = isset($this->allroleassignments[$data->id]) ? $this->allroleassignments[$data->id] : []; 269 $editable = new \core_user\output\user_roles_editable($this->course, 270 $this->context, 271 $data, 272 $this->allroles, 273 $this->assignableroles, 274 $this->profileroles, 275 $roles, 276 $this->viewableroles); 277 278 return $OUTPUT->render_from_template('core/inplace_editable', $editable->export_for_template($OUTPUT)); 279 } 280 281 /** 282 * Generate the groups column. 283 * 284 * @param \stdClass $data 285 * @return string 286 */ 287 public function col_groups($data) { 288 global $OUTPUT; 289 290 $usergroups = []; 291 foreach ($this->groups as $coursegroup) { 292 if (isset($coursegroup->members[$data->id])) { 293 $usergroups[] = $coursegroup->id; 294 } 295 } 296 $editable = new \core_group\output\user_groups_editable($this->course, $this->context, $data, $this->groups, $usergroups); 297 return $OUTPUT->render_from_template('core/inplace_editable', $editable->export_for_template($OUTPUT)); 298 } 299 300 /** 301 * Generate the country column. 302 * 303 * @param \stdClass $data 304 * @return string 305 */ 306 public function col_country($data) { 307 if (!empty($this->countries[$data->country])) { 308 return $this->countries[$data->country]; 309 } 310 return ''; 311 } 312 313 /** 314 * Generate the last access column. 315 * 316 * @param \stdClass $data 317 * @return string 318 */ 319 public function col_lastaccess($data) { 320 if ($data->lastaccess) { 321 return format_time(time() - $data->lastaccess); 322 } 323 324 return get_string('never'); 325 } 326 327 /** 328 * Generate the status column. 329 * 330 * @param \stdClass $data The data object. 331 * @return string 332 */ 333 public function col_status($data) { 334 global $CFG, $OUTPUT, $PAGE; 335 336 $enrolstatusoutput = ''; 337 $canreviewenrol = has_capability('moodle/course:enrolreview', $this->context); 338 if ($canreviewenrol) { 339 $canviewfullnames = has_capability('moodle/site:viewfullnames', $this->context); 340 $fullname = fullname($data, $canviewfullnames); 341 $coursename = format_string($this->course->fullname, true, array('context' => $this->context)); 342 require_once($CFG->dirroot . '/enrol/locallib.php'); 343 $manager = new \course_enrolment_manager($PAGE, $this->course); 344 $userenrolments = $manager->get_user_enrolments($data->id); 345 foreach ($userenrolments as $ue) { 346 $timestart = $ue->timestart; 347 $timeend = $ue->timeend; 348 $timeenrolled = $ue->timecreated; 349 $actions = $ue->enrolmentplugin->get_user_enrolment_actions($manager, $ue); 350 $instancename = $ue->enrolmentinstancename; 351 352 // Default status field label and value. 353 $status = get_string('participationactive', 'enrol'); 354 $statusval = status_field::STATUS_ACTIVE; 355 switch ($ue->status) { 356 case ENROL_USER_ACTIVE: 357 $currentdate = new DateTime(); 358 $now = $currentdate->getTimestamp(); 359 $isexpired = $timestart > $now || ($timeend > 0 && $timeend < $now); 360 $enrolmentdisabled = $ue->enrolmentinstance->status == ENROL_INSTANCE_DISABLED; 361 // If user enrolment status has not yet started/already ended or the enrolment instance is disabled. 362 if ($isexpired || $enrolmentdisabled) { 363 $status = get_string('participationnotcurrent', 'enrol'); 364 $statusval = status_field::STATUS_NOT_CURRENT; 365 } 366 break; 367 case ENROL_USER_SUSPENDED: 368 $status = get_string('participationsuspended', 'enrol'); 369 $statusval = status_field::STATUS_SUSPENDED; 370 break; 371 } 372 373 $statusfield = new status_field($instancename, $coursename, $fullname, $status, $timestart, $timeend, 374 $actions, $timeenrolled); 375 $statusfielddata = $statusfield->set_status($statusval)->export_for_template($OUTPUT); 376 $enrolstatusoutput .= $OUTPUT->render_from_template('core_user/status_field', $statusfielddata); 377 } 378 } 379 return $enrolstatusoutput; 380 } 381 382 /** 383 * This function is used for the extra user fields. 384 * 385 * These are being dynamically added to the table so there are no functions 'col_<userfieldname>' as 386 * the list has the potential to increase in the future and we don't want to have to remember to add 387 * a new method to this class. We also don't want to pollute this class with unnecessary methods. 388 * 389 * @param string $colname The column name 390 * @param \stdClass $data 391 * @return string 392 */ 393 public function other_cols($colname, $data) { 394 // Do not process if it is not a part of the extra fields. 395 if (!in_array($colname, $this->extrafields)) { 396 return ''; 397 } 398 399 return s($data->{$colname}); 400 } 401 402 /** 403 * Query the database for results to display in the table. 404 * 405 * @param int $pagesize size of page for paginated displayed table. 406 * @param bool $useinitialsbar do you want to use the initials bar. 407 */ 408 public function query_db($pagesize, $useinitialsbar = true) { 409 list($twhere, $tparams) = $this->get_sql_where(); 410 $psearch = new participants_search($this->course, $this->context, $this->filterset); 411 412 $total = $psearch->get_total_participants_count($twhere, $tparams); 413 414 $this->pagesize($pagesize, $total); 415 416 $sort = $this->get_sql_sort(); 417 if ($sort) { 418 $sort = 'ORDER BY ' . $sort; 419 } 420 421 $rawdata = $psearch->get_participants($twhere, $tparams, $sort, $this->get_page_start(), $this->get_page_size()); 422 423 $this->rawdata = []; 424 foreach ($rawdata as $user) { 425 $this->rawdata[$user->id] = $user; 426 } 427 $rawdata->close(); 428 429 if ($this->rawdata) { 430 $this->allroleassignments = get_users_roles($this->context, array_keys($this->rawdata), 431 true, 'c.contextlevel DESC, r.sortorder ASC'); 432 } else { 433 $this->allroleassignments = []; 434 } 435 436 // Set initial bars. 437 if ($useinitialsbar) { 438 $this->initialbars(true); 439 } 440 } 441 442 /** 443 * Override the table show_hide_link to not show for select column. 444 * 445 * @param string $column the column name, index into various names. 446 * @param int $index numerical index of the column. 447 * @return string HTML fragment. 448 */ 449 protected function show_hide_link($column, $index) { 450 if ($index > 0) { 451 return parent::show_hide_link($column, $index); 452 } 453 return ''; 454 } 455 456 /** 457 * Set filters and build table structure. 458 * 459 * @param filterset $filterset The filterset object to get the filters from. 460 */ 461 public function set_filterset(filterset $filterset): void { 462 // Get the context. 463 $this->courseid = $filterset->get_filter('courseid')->current(); 464 $this->course = get_course($this->courseid); 465 $this->context = \context_course::instance($this->courseid, MUST_EXIST); 466 467 // Process the filterset. 468 parent::set_filterset($filterset); 469 } 470 471 /** 472 * Guess the base url for the participants table. 473 */ 474 public function guess_base_url(): void { 475 $this->baseurl = new moodle_url('/user/index.php', ['id' => $this->courseid]); 476 } 477 478 /** 479 * Get the context of the current table. 480 * 481 * Note: This function should not be called until after the filterset has been provided. 482 * 483 * @return context 484 */ 485 public function get_context(): context { 486 return $this->context; 487 } 488 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body