See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 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 * This file contains the course_enrolment_manager class which is used to interface 19 * with the functions that exist in enrollib.php in relation to a single course. 20 * 21 * @package core_enrol 22 * @copyright 2010 Sam Hemelryk 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 use core_user\fields; 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 /** 31 * This class provides a targeted tied together means of interfacing the enrolment 32 * tasks together with a course. 33 * 34 * It is provided as a convenience more than anything else. 35 * 36 * @copyright 2010 Sam Hemelryk 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class course_enrolment_manager { 40 41 /** 42 * The course context 43 * @var context 44 */ 45 protected $context; 46 /** 47 * The course we are managing enrolments for 48 * @var stdClass 49 */ 50 protected $course = null; 51 /** 52 * Limits the focus of the manager to one enrolment plugin instance 53 * @var string 54 */ 55 protected $instancefilter = null; 56 /** 57 * Limits the focus of the manager to users with specified role 58 * @var int 59 */ 60 protected $rolefilter = 0; 61 /** 62 * Limits the focus of the manager to users who match search string 63 * @var string 64 */ 65 protected $searchfilter = ''; 66 /** 67 * Limits the focus of the manager to users in specified group 68 * @var int 69 */ 70 protected $groupfilter = 0; 71 /** 72 * Limits the focus of the manager to users who match status active/inactive 73 * @var int 74 */ 75 protected $statusfilter = -1; 76 77 /** 78 * The total number of users enrolled in the course 79 * Populated by course_enrolment_manager::get_total_users 80 * @var int 81 */ 82 protected $totalusers = null; 83 /** 84 * An array of users currently enrolled in the course 85 * Populated by course_enrolment_manager::get_users 86 * @var array 87 */ 88 protected $users = array(); 89 90 /** 91 * An array of users who have roles within this course but who have not 92 * been enrolled in the course 93 * @var array 94 */ 95 protected $otherusers = array(); 96 97 /** 98 * The total number of users who hold a role within the course but who 99 * arn't enrolled. 100 * @var int 101 */ 102 protected $totalotherusers = null; 103 104 /** 105 * The current moodle_page object 106 * @var moodle_page 107 */ 108 protected $moodlepage = null; 109 110 /**#@+ 111 * These variables are used to cache the information this class uses 112 * please never use these directly instead use their get_ counterparts. 113 * @access private 114 * @var array 115 */ 116 private $_instancessql = null; 117 private $_instances = null; 118 private $_inames = null; 119 private $_plugins = null; 120 private $_allplugins = null; 121 private $_roles = null; 122 private $_visibleroles = null; 123 private $_assignableroles = null; 124 private $_assignablerolesothers = null; 125 private $_groups = null; 126 /**#@-*/ 127 128 /** 129 * Constructs the course enrolment manager 130 * 131 * @param moodle_page $moodlepage 132 * @param stdClass $course 133 * @param string $instancefilter 134 * @param int $rolefilter If non-zero, filters to users with specified role 135 * @param string $searchfilter If non-blank, filters to users with search text 136 * @param int $groupfilter if non-zero, filter users with specified group 137 * @param int $statusfilter if not -1, filter users with active/inactive enrollment. 138 */ 139 public function __construct(moodle_page $moodlepage, $course, $instancefilter = null, 140 $rolefilter = 0, $searchfilter = '', $groupfilter = 0, $statusfilter = -1) { 141 $this->moodlepage = $moodlepage; 142 $this->context = context_course::instance($course->id); 143 $this->course = $course; 144 $this->instancefilter = $instancefilter; 145 $this->rolefilter = $rolefilter; 146 $this->searchfilter = $searchfilter; 147 $this->groupfilter = $groupfilter; 148 $this->statusfilter = $statusfilter; 149 } 150 151 /** 152 * Returns the current moodle page 153 * @return moodle_page 154 */ 155 public function get_moodlepage() { 156 return $this->moodlepage; 157 } 158 159 /** 160 * Returns the total number of enrolled users in the course. 161 * 162 * If a filter was specificed this will be the total number of users enrolled 163 * in this course by means of that instance. 164 * 165 * @global moodle_database $DB 166 * @return int 167 */ 168 public function get_total_users() { 169 global $DB; 170 if ($this->totalusers === null) { 171 list($instancessql, $params, $filter) = $this->get_instance_sql(); 172 list($filtersql, $moreparams) = $this->get_filter_sql(); 173 $params += $moreparams; 174 $sqltotal = "SELECT COUNT(DISTINCT u.id) 175 FROM {user} u 176 JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) 177 JOIN {enrol} e ON (e.id = ue.enrolid)"; 178 if ($this->groupfilter) { 179 $sqltotal .= " LEFT JOIN ({groups_members} gm JOIN {groups} g ON (g.id = gm.groupid)) 180 ON (u.id = gm.userid AND g.courseid = e.courseid)"; 181 } 182 $sqltotal .= "WHERE $filtersql"; 183 $this->totalusers = (int)$DB->count_records_sql($sqltotal, $params); 184 } 185 return $this->totalusers; 186 } 187 188 /** 189 * Returns the total number of enrolled users in the course. 190 * 191 * If a filter was specificed this will be the total number of users enrolled 192 * in this course by means of that instance. 193 * 194 * @global moodle_database $DB 195 * @return int 196 */ 197 public function get_total_other_users() { 198 global $DB; 199 if ($this->totalotherusers === null) { 200 list($ctxcondition, $params) = $DB->get_in_or_equal($this->context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'ctx'); 201 $params['courseid'] = $this->course->id; 202 $sql = "SELECT COUNT(DISTINCT u.id) 203 FROM {role_assignments} ra 204 JOIN {user} u ON u.id = ra.userid 205 JOIN {context} ctx ON ra.contextid = ctx.id 206 LEFT JOIN ( 207 SELECT ue.id, ue.userid 208 FROM {user_enrolments} ue 209 LEFT JOIN {enrol} e ON e.id=ue.enrolid 210 WHERE e.courseid = :courseid 211 ) ue ON ue.userid=u.id 212 WHERE ctx.id $ctxcondition AND 213 ue.id IS NULL"; 214 $this->totalotherusers = (int)$DB->count_records_sql($sql, $params); 215 } 216 return $this->totalotherusers; 217 } 218 219 /** 220 * Gets all of the users enrolled in this course. 221 * 222 * If a filter was specified this will be the users who were enrolled 223 * in this course by means of that instance. If role or search filters were 224 * specified then these will also be applied. 225 * 226 * @global moodle_database $DB 227 * @param string $sort 228 * @param string $direction ASC or DESC 229 * @param int $page First page should be 0 230 * @param int $perpage Defaults to 25 231 * @return array 232 */ 233 public function get_users($sort, $direction='ASC', $page=0, $perpage=25) { 234 global $DB; 235 if ($direction !== 'ASC') { 236 $direction = 'DESC'; 237 } 238 $key = md5("$sort-$direction-$page-$perpage"); 239 if (!array_key_exists($key, $this->users)) { 240 list($instancessql, $params, $filter) = $this->get_instance_sql(); 241 list($filtersql, $moreparams) = $this->get_filter_sql(); 242 $params += $moreparams; 243 $userfields = fields::for_identity($this->get_context())->with_userpic()->excluding('lastaccess'); 244 ['selects' => $fieldselect, 'joins' => $fieldjoin, 'params' => $fieldjoinparams] = 245 (array)$userfields->get_sql('u', true, '', '', false); 246 $params += $fieldjoinparams; 247 $sql = "SELECT DISTINCT $fieldselect, COALESCE(ul.timeaccess, 0) AS lastcourseaccess 248 FROM {user} u 249 JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql) 250 JOIN {enrol} e ON (e.id = ue.enrolid) 251 $fieldjoin 252 LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)"; 253 if ($this->groupfilter) { 254 $sql .= " LEFT JOIN ({groups_members} gm JOIN {groups} g ON (g.id = gm.groupid)) 255 ON (u.id = gm.userid AND g.courseid = e.courseid)"; 256 } 257 $sql .= "WHERE $filtersql 258 ORDER BY $sort $direction"; 259 $this->users[$key] = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage); 260 } 261 return $this->users[$key]; 262 } 263 264 /** 265 * Obtains WHERE clause to filter results by defined search and role filter 266 * (instance filter is handled separately in JOIN clause, see 267 * get_instance_sql). 268 * 269 * @return array Two-element array with SQL and params for WHERE clause 270 */ 271 protected function get_filter_sql() { 272 global $DB; 273 274 // Search condition. 275 // TODO Does not support custom user profile fields (MDL-70456). 276 $extrafields = fields::get_identity_fields($this->get_context(), false); 277 list($sql, $params) = users_search_sql($this->searchfilter, 'u', true, $extrafields); 278 279 // Role condition. 280 if ($this->rolefilter) { 281 // Get context SQL. 282 $contextids = $this->context->get_parent_context_ids(); 283 $contextids[] = $this->context->id; 284 list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED); 285 $params += $contextparams; 286 287 // Role check condition. 288 $sql .= " AND (SELECT COUNT(1) FROM {role_assignments} ra WHERE ra.userid = u.id " . 289 "AND ra.roleid = :roleid AND ra.contextid $contextsql) > 0"; 290 $params['roleid'] = $this->rolefilter; 291 } 292 293 // Group condition. 294 if ($this->groupfilter) { 295 if ($this->groupfilter < 0) { 296 // Show users who are not in any group. 297 $sql .= " AND gm.groupid IS NULL"; 298 } else { 299 $sql .= " AND gm.groupid = :groupid"; 300 $params['groupid'] = $this->groupfilter; 301 } 302 } 303 304 // Status condition. 305 if ($this->statusfilter === ENROL_USER_ACTIVE) { 306 $sql .= " AND ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 307 AND (ue.timeend = 0 OR ue.timeend > :now2)"; 308 $now = round(time(), -2); // rounding helps caching in DB 309 $params += array('enabled' => ENROL_INSTANCE_ENABLED, 310 'active' => ENROL_USER_ACTIVE, 311 'now1' => $now, 312 'now2' => $now); 313 } else if ($this->statusfilter === ENROL_USER_SUSPENDED) { 314 $sql .= " AND (ue.status = :inactive OR e.status = :disabled OR ue.timestart > :now1 315 OR (ue.timeend <> 0 AND ue.timeend < :now2))"; 316 $now = round(time(), -2); // rounding helps caching in DB 317 $params += array('disabled' => ENROL_INSTANCE_DISABLED, 318 'inactive' => ENROL_USER_SUSPENDED, 319 'now1' => $now, 320 'now2' => $now); 321 } 322 323 return array($sql, $params); 324 } 325 326 /** 327 * Gets and array of other users. 328 * 329 * Other users are users who have been assigned roles or inherited roles 330 * within this course but who have not been enrolled in the course 331 * 332 * @global moodle_database $DB 333 * @param string $sort 334 * @param string $direction 335 * @param int $page 336 * @param int $perpage 337 * @return array 338 */ 339 public function get_other_users($sort, $direction='ASC', $page=0, $perpage=25) { 340 global $DB; 341 if ($direction !== 'ASC') { 342 $direction = 'DESC'; 343 } 344 $key = md5("$sort-$direction-$page-$perpage"); 345 if (!array_key_exists($key, $this->otherusers)) { 346 list($ctxcondition, $params) = $DB->get_in_or_equal($this->context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'ctx'); 347 $params['courseid'] = $this->course->id; 348 $params['cid'] = $this->course->id; 349 $userfields = fields::for_identity($this->get_context())->with_userpic(); 350 ['selects' => $fieldselect, 'joins' => $fieldjoin, 'params' => $fieldjoinparams] = 351 (array)$userfields->get_sql('u', true); 352 $params += $fieldjoinparams; 353 $sql = "SELECT ra.id as raid, ra.contextid, ra.component, ctx.contextlevel, ra.roleid, 354 coalesce(u.lastaccess,0) AS lastaccess 355 $fieldselect 356 FROM {role_assignments} ra 357 JOIN {user} u ON u.id = ra.userid 358 JOIN {context} ctx ON ra.contextid = ctx.id 359 $fieldjoin 360 LEFT JOIN ( 361 SELECT ue.id, ue.userid 362 FROM {user_enrolments} ue 363 JOIN {enrol} e ON e.id = ue.enrolid 364 WHERE e.courseid = :courseid 365 ) ue ON ue.userid=u.id 366 WHERE ctx.id $ctxcondition AND 367 ue.id IS NULL 368 ORDER BY $sort $direction, ctx.depth DESC"; 369 $this->otherusers[$key] = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage); 370 } 371 return $this->otherusers[$key]; 372 } 373 374 /** 375 * Helper method used by {@link get_potential_users()} and {@link search_other_users()}. 376 * 377 * @param string $search the search term, if any. 378 * @param bool $searchanywhere Can the search term be anywhere, or must it be at the start. 379 * @return array with three elements: 380 * string list of fields to SELECT, 381 * string possible database joins for user fields 382 * string contents of SQL WHERE clause, 383 * array query params. Note that the SQL snippets use named parameters. 384 */ 385 protected function get_basic_search_conditions($search, $searchanywhere) { 386 global $DB, $CFG; 387 388 // Get custom user field SQL used for querying all the fields we need (identity, name, and 389 // user picture). 390 $userfields = fields::for_identity($this->context)->with_name()->with_userpic() 391 ->excluding('username', 'lastaccess', 'maildisplay'); 392 ['selects' => $fieldselects, 'joins' => $fieldjoins, 'params' => $params, 'mappings' => $mappings] = 393 (array)$userfields->get_sql('u', true, '', '', false); 394 395 // Searchable fields are only the identity and name ones (not userpic, and without exclusions). 396 $searchablefields = fields::for_identity($this->context)->with_name(); 397 $searchable = array_fill_keys($searchablefields->get_required_fields(), true); 398 if (array_key_exists('username', $searchable)) { 399 // Add the username into the mappings list from the other query, because it was excluded. 400 $mappings['username'] = 'u.username'; 401 } 402 403 // Add some additional sensible conditions 404 $tests = array("u.id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1'); 405 $params['guestid'] = $CFG->siteguest; 406 if (!empty($search)) { 407 // Include identity and name fields as conditions. 408 foreach ($mappings as $fieldname => $fieldsql) { 409 if (array_key_exists($fieldname, $searchable)) { 410 $conditions[] = $fieldsql; 411 } 412 } 413 $conditions[] = $DB->sql_fullname('u.firstname', 'u.lastname'); 414 if ($searchanywhere) { 415 $searchparam = '%' . $search . '%'; 416 } else { 417 $searchparam = $search . '%'; 418 } 419 $i = 0; 420 foreach ($conditions as $key => $condition) { 421 $conditions[$key] = $DB->sql_like($condition, ":con{$i}00", false); 422 $params["con{$i}00"] = $searchparam; 423 $i++; 424 } 425 $tests[] = '(' . implode(' OR ', $conditions) . ')'; 426 } 427 $wherecondition = implode(' AND ', $tests); 428 429 $selects = $fieldselects . ', u.username, u.lastaccess, u.maildisplay'; 430 return [$selects, $fieldjoins, $params, $wherecondition]; 431 } 432 433 /** 434 * Helper method used by {@link get_potential_users()} and {@link search_other_users()}. 435 * 436 * @param string $search the search string, if any. 437 * @param string $fields the first bit of the SQL when returning some users. 438 * @param string $countfields fhe first bit of the SQL when counting the users. 439 * @param string $sql the bulk of the SQL statement. 440 * @param array $params query parameters. 441 * @param int $page which page number of the results to show. 442 * @param int $perpage number of users per page. 443 * @param int $addedenrollment number of users added to enrollment. 444 * @param bool $returnexactcount Return the exact total users using count_record or not. 445 * @return array with two or three elements: 446 * int totalusers Number users matching the search. (This element only exist if $returnexactcount was set to true) 447 * array users List of user objects returned by the query. 448 * boolean moreusers True if there are still more users, otherwise is False. 449 * @throws dml_exception 450 */ 451 protected function execute_search_queries($search, $fields, $countfields, $sql, array $params, $page, $perpage, 452 $addedenrollment = 0, $returnexactcount = false) { 453 global $DB, $CFG; 454 455 list($sort, $sortparams) = users_order_by_sql('u', $search, $this->get_context()); 456 $order = ' ORDER BY ' . $sort; 457 458 $totalusers = 0; 459 $moreusers = false; 460 $results = []; 461 462 $availableusers = $DB->get_records_sql($fields . $sql . $order, 463 array_merge($params, $sortparams), ($page * $perpage) - $addedenrollment, $perpage + 1); 464 if ($availableusers) { 465 $totalusers = count($availableusers); 466 $moreusers = $totalusers > $perpage; 467 468 if ($moreusers) { 469 // We need to discard the last record. 470 array_pop($availableusers); 471 } 472 473 if ($returnexactcount && $moreusers) { 474 // There is more data. We need to do the exact count. 475 $totalusers = $DB->count_records_sql($countfields . $sql, $params); 476 } 477 } 478 479 $results['users'] = $availableusers; 480 $results['moreusers'] = $moreusers; 481 482 if ($returnexactcount) { 483 // Include totalusers in result if $returnexactcount flag is true. 484 $results['totalusers'] = $totalusers; 485 } 486 487 return $results; 488 } 489 490 /** 491 * Gets an array of the users that can be enrolled in this course. 492 * 493 * @global moodle_database $DB 494 * @param int $enrolid 495 * @param string $search 496 * @param bool $searchanywhere 497 * @param int $page Defaults to 0 498 * @param int $perpage Defaults to 25 499 * @param int $addedenrollment Defaults to 0 500 * @param bool $returnexactcount Return the exact total users using count_record or not. 501 * @return array with two or three elements: 502 * int totalusers Number users matching the search. (This element only exist if $returnexactcount was set to true) 503 * array users List of user objects returned by the query. 504 * boolean moreusers True if there are still more users, otherwise is False. 505 * @throws dml_exception 506 */ 507 public function get_potential_users($enrolid, $search = '', $searchanywhere = false, $page = 0, $perpage = 25, 508 $addedenrollment = 0, $returnexactcount = false) { 509 global $DB; 510 511 [$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere); 512 513 $fields = 'SELECT '.$ufields; 514 $countfields = 'SELECT COUNT(1)'; 515 $sql = " FROM {user} u 516 $joins 517 LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid) 518 WHERE $wherecondition 519 AND ue.id IS NULL"; 520 $params['enrolid'] = $enrolid; 521 522 return $this->execute_search_queries($search, $fields, $countfields, $sql, $params, $page, $perpage, $addedenrollment, 523 $returnexactcount); 524 } 525 526 /** 527 * Searches other users and returns paginated results 528 * 529 * @global moodle_database $DB 530 * @param string $search 531 * @param bool $searchanywhere 532 * @param int $page Starting at 0 533 * @param int $perpage 534 * @param bool $returnexactcount Return the exact total users using count_record or not. 535 * @return array with two or three elements: 536 * int totalusers Number users matching the search. (This element only exist if $returnexactcount was set to true) 537 * array users List of user objects returned by the query. 538 * boolean moreusers True if there are still more users, otherwise is False. 539 * @throws dml_exception 540 */ 541 public function search_other_users($search = '', $searchanywhere = false, $page = 0, $perpage = 25, $returnexactcount = false) { 542 global $DB, $CFG; 543 544 [$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere); 545 546 $fields = 'SELECT ' . $ufields; 547 $countfields = 'SELECT COUNT(u.id)'; 548 $sql = " FROM {user} u 549 $joins 550 LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid = :contextid) 551 WHERE $wherecondition 552 AND ra.id IS NULL"; 553 $params['contextid'] = $this->context->id; 554 555 return $this->execute_search_queries($search, $fields, $countfields, $sql, $params, $page, $perpage, 0, $returnexactcount); 556 } 557 558 /** 559 * Searches through the enrolled users in this course. 560 * 561 * @param string $search The search term. 562 * @param bool $searchanywhere Can the search term be anywhere, or must it be at the start. 563 * @param int $page Starting at 0. 564 * @param int $perpage Number of users returned per page. 565 * @param bool $returnexactcount Return the exact total users using count_record or not. 566 * @return array with two or three elements: 567 * int totalusers Number users matching the search. (This element only exist if $returnexactcount was set to true) 568 * array users List of user objects returned by the query. 569 * boolean moreusers True if there are still more users, otherwise is False. 570 */ 571 public function search_users(string $search = '', bool $searchanywhere = false, int $page = 0, int $perpage = 25, 572 bool $returnexactcount = false) { 573 global $USER; 574 575 [$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere); 576 577 $groupmode = groups_get_course_groupmode($this->course); 578 if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $this->context)) { 579 $groups = groups_get_all_groups($this->course->id, $USER->id, 0, 'g.id'); 580 $groupids = array_column($groups, 'id'); 581 } else { 582 $groupids = []; 583 } 584 585 [$enrolledsql, $enrolledparams] = get_enrolled_sql($this->context, '', $groupids); 586 587 $fields = 'SELECT ' . $ufields; 588 $countfields = 'SELECT COUNT(u.id)'; 589 $sql = " FROM {user} u 590 $joins 591 JOIN ($enrolledsql) je ON je.id = u.id 592 WHERE $wherecondition"; 593 594 $params = array_merge($params, $enrolledparams); 595 596 return $this->execute_search_queries($search, $fields, $countfields, $sql, $params, $page, $perpage, 0, $returnexactcount); 597 } 598 599 /** 600 * Gets an array containing some SQL to user for when selecting, params for 601 * that SQL, and the filter that was used in constructing the sql. 602 * 603 * @global moodle_database $DB 604 * @return string 605 */ 606 protected function get_instance_sql() { 607 global $DB; 608 if ($this->_instancessql === null) { 609 $instances = $this->get_enrolment_instances(); 610 $filter = $this->get_enrolment_filter(); 611 if ($filter && array_key_exists($filter, $instances)) { 612 $sql = " = :ifilter"; 613 $params = array('ifilter'=>$filter); 614 } else { 615 $filter = 0; 616 if ($instances) { 617 list($sql, $params) = $DB->get_in_or_equal(array_keys($this->get_enrolment_instances()), SQL_PARAMS_NAMED); 618 } else { 619 // no enabled instances, oops, we should probably say something 620 $sql = "= :never"; 621 $params = array('never'=>-1); 622 } 623 } 624 $this->instancefilter = $filter; 625 $this->_instancessql = array($sql, $params, $filter); 626 } 627 return $this->_instancessql; 628 } 629 630 /** 631 * Returns all of the enrolment instances for this course. 632 * 633 * @param bool $onlyenabled Whether to return data from enabled enrolment instance names only. 634 * @return array 635 */ 636 public function get_enrolment_instances($onlyenabled = false) { 637 if ($this->_instances === null) { 638 $this->_instances = enrol_get_instances($this->course->id, $onlyenabled); 639 } 640 return $this->_instances; 641 } 642 643 /** 644 * Returns the names for all of the enrolment instances for this course. 645 * 646 * @param bool $onlyenabled Whether to return data from enabled enrolment instance names only. 647 * @return array 648 */ 649 public function get_enrolment_instance_names($onlyenabled = false) { 650 if ($this->_inames === null) { 651 $instances = $this->get_enrolment_instances($onlyenabled); 652 $plugins = $this->get_enrolment_plugins(false); 653 foreach ($instances as $key=>$instance) { 654 if (!isset($plugins[$instance->enrol])) { 655 // weird, some broken stuff in plugin 656 unset($instances[$key]); 657 continue; 658 } 659 $this->_inames[$key] = $plugins[$instance->enrol]->get_instance_name($instance); 660 } 661 } 662 return $this->_inames; 663 } 664 665 /** 666 * Gets all of the enrolment plugins that are available for this course. 667 * 668 * @param bool $onlyenabled return only enabled enrol plugins 669 * @return array 670 */ 671 public function get_enrolment_plugins($onlyenabled = true) { 672 if ($this->_plugins === null) { 673 $this->_plugins = enrol_get_plugins(true); 674 } 675 676 if ($onlyenabled) { 677 return $this->_plugins; 678 } 679 680 if ($this->_allplugins === null) { 681 // Make sure we have the same objects in _allplugins and _plugins. 682 $this->_allplugins = $this->_plugins; 683 foreach (enrol_get_plugins(false) as $name=>$plugin) { 684 if (!isset($this->_allplugins[$name])) { 685 $this->_allplugins[$name] = $plugin; 686 } 687 } 688 } 689 690 return $this->_allplugins; 691 } 692 693 /** 694 * Gets all of the roles this course can contain. 695 * 696 * @return array 697 */ 698 public function get_all_roles() { 699 if ($this->_roles === null) { 700 $this->_roles = role_fix_names(get_all_roles($this->context), $this->context); 701 } 702 return $this->_roles; 703 } 704 705 /** 706 * Gets all of the roles this course can contain. 707 * 708 * @return array 709 */ 710 public function get_viewable_roles() { 711 if ($this->_visibleroles === null) { 712 $this->_visibleroles = get_viewable_roles($this->context); 713 } 714 return $this->_visibleroles; 715 } 716 717 /** 718 * Gets all of the assignable roles for this course. 719 * 720 * @return array 721 */ 722 public function get_assignable_roles($otherusers = false) { 723 if ($this->_assignableroles === null) { 724 $this->_assignableroles = get_assignable_roles($this->context, ROLENAME_ALIAS, false); // verifies unassign access control too 725 } 726 727 if ($otherusers) { 728 if (!is_array($this->_assignablerolesothers)) { 729 $this->_assignablerolesothers = array(); 730 list($courseviewroles, $ignored) = get_roles_with_cap_in_context($this->context, 'moodle/course:view'); 731 foreach ($this->_assignableroles as $roleid=>$role) { 732 if (isset($courseviewroles[$roleid])) { 733 $this->_assignablerolesothers[$roleid] = $role; 734 } 735 } 736 } 737 return $this->_assignablerolesothers; 738 } else { 739 return $this->_assignableroles; 740 } 741 } 742 743 /** 744 * Gets all of the assignable roles for this course, wrapped in an array to ensure 745 * role sort order is not lost during json deserialisation. 746 * 747 * @param boolean $otherusers whether to include the assignable roles for other users 748 * @return array 749 */ 750 public function get_assignable_roles_for_json($otherusers = false) { 751 $rolesarray = array(); 752 $assignable = $this->get_assignable_roles($otherusers); 753 foreach ($assignable as $id => $role) { 754 $rolesarray[] = array('id' => $id, 'name' => $role); 755 } 756 return $rolesarray; 757 } 758 759 /** 760 * Gets all of the groups for this course. 761 * 762 * @return array 763 */ 764 public function get_all_groups() { 765 if ($this->_groups === null) { 766 $this->_groups = groups_get_all_groups($this->course->id); 767 foreach ($this->_groups as $gid=>$group) { 768 $this->_groups[$gid]->name = format_string($group->name); 769 } 770 } 771 return $this->_groups; 772 } 773 774 /** 775 * Unenrols a user from the course given the users ue entry 776 * 777 * @global moodle_database $DB 778 * @param stdClass $ue 779 * @return bool 780 */ 781 public function unenrol_user($ue) { 782 global $DB; 783 list ($instance, $plugin) = $this->get_user_enrolment_components($ue); 784 if ($instance && $plugin && $plugin->allow_unenrol_user($instance, $ue) && has_capability("enrol/$instance->enrol:unenrol", $this->context)) { 785 $plugin->unenrol_user($instance, $ue->userid); 786 return true; 787 } 788 return false; 789 } 790 791 /** 792 * Given a user enrolment record this method returns the plugin and enrolment 793 * instance that relate to it. 794 * 795 * @param stdClass|int $userenrolment 796 * @return array array($instance, $plugin) 797 */ 798 public function get_user_enrolment_components($userenrolment) { 799 global $DB; 800 if (is_numeric($userenrolment)) { 801 $userenrolment = $DB->get_record('user_enrolments', array('id'=>(int)$userenrolment)); 802 } 803 $instances = $this->get_enrolment_instances(); 804 $plugins = $this->get_enrolment_plugins(false); 805 if (!$userenrolment || !isset($instances[$userenrolment->enrolid])) { 806 return array(false, false); 807 } 808 $instance = $instances[$userenrolment->enrolid]; 809 $plugin = $plugins[$instance->enrol]; 810 return array($instance, $plugin); 811 } 812 813 /** 814 * Removes an assigned role from a user. 815 * 816 * @global moodle_database $DB 817 * @param int $userid 818 * @param int $roleid 819 * @return bool 820 */ 821 public function unassign_role_from_user($userid, $roleid) { 822 global $DB; 823 // Admins may unassign any role, others only those they could assign. 824 if (!is_siteadmin() and !array_key_exists($roleid, $this->get_assignable_roles())) { 825 if (defined('AJAX_SCRIPT')) { 826 throw new moodle_exception('invalidrole'); 827 } 828 return false; 829 } 830 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); 831 $ras = $DB->get_records('role_assignments', array('contextid'=>$this->context->id, 'userid'=>$user->id, 'roleid'=>$roleid)); 832 foreach ($ras as $ra) { 833 if ($ra->component) { 834 if (strpos($ra->component, 'enrol_') !== 0) { 835 continue; 836 } 837 if (!$plugin = enrol_get_plugin(substr($ra->component, 6))) { 838 continue; 839 } 840 if ($plugin->roles_protected()) { 841 continue; 842 } 843 } 844 role_unassign($ra->roleid, $ra->userid, $ra->contextid, $ra->component, $ra->itemid); 845 } 846 return true; 847 } 848 849 /** 850 * Assigns a role to a user. 851 * 852 * @param int $roleid 853 * @param int $userid 854 * @return int|false 855 */ 856 public function assign_role_to_user($roleid, $userid) { 857 require_capability('moodle/role:assign', $this->context); 858 if (!array_key_exists($roleid, $this->get_assignable_roles())) { 859 if (defined('AJAX_SCRIPT')) { 860 throw new moodle_exception('invalidrole'); 861 } 862 return false; 863 } 864 return role_assign($roleid, $userid, $this->context->id, '', NULL); 865 } 866 867 /** 868 * Adds a user to a group 869 * 870 * @param stdClass $user 871 * @param int $groupid 872 * @return bool 873 */ 874 public function add_user_to_group($user, $groupid) { 875 require_capability('moodle/course:managegroups', $this->context); 876 $group = $this->get_group($groupid); 877 if (!$group) { 878 return false; 879 } 880 return groups_add_member($group->id, $user->id); 881 } 882 883 /** 884 * Removes a user from a group 885 * 886 * @global moodle_database $DB 887 * @param StdClass $user 888 * @param int $groupid 889 * @return bool 890 */ 891 public function remove_user_from_group($user, $groupid) { 892 global $DB; 893 require_capability('moodle/course:managegroups', $this->context); 894 $group = $this->get_group($groupid); 895 if (!groups_remove_member_allowed($group, $user)) { 896 return false; 897 } 898 if (!$group) { 899 return false; 900 } 901 return groups_remove_member($group, $user); 902 } 903 904 /** 905 * Gets the requested group 906 * 907 * @param int $groupid 908 * @return stdClass|int 909 */ 910 public function get_group($groupid) { 911 $groups = $this->get_all_groups(); 912 if (!array_key_exists($groupid, $groups)) { 913 return false; 914 } 915 return $groups[$groupid]; 916 } 917 918 /** 919 * Edits an enrolment 920 * 921 * @param stdClass $userenrolment 922 * @param stdClass $data 923 * @return bool 924 */ 925 public function edit_enrolment($userenrolment, $data) { 926 //Only allow editing if the user has the appropriate capability 927 //Already checked in /user/index.php but checking again in case this function is called from elsewhere 928 list($instance, $plugin) = $this->get_user_enrolment_components($userenrolment); 929 if ($instance && $plugin && $plugin->allow_manage($instance) && has_capability("enrol/$instance->enrol:manage", $this->context)) { 930 if (!isset($data->status)) { 931 $data->status = $userenrolment->status; 932 } 933 $plugin->update_user_enrol($instance, $userenrolment->userid, $data->status, $data->timestart, $data->timeend); 934 return true; 935 } 936 return false; 937 } 938 939 /** 940 * Returns the current enrolment filter that is being applied by this class 941 * @return string 942 */ 943 public function get_enrolment_filter() { 944 return $this->instancefilter; 945 } 946 947 /** 948 * Gets the roles assigned to this user that are applicable for this course. 949 * 950 * @param int $userid 951 * @return array 952 */ 953 public function get_user_roles($userid) { 954 $roles = array(); 955 $ras = get_user_roles($this->context, $userid, true, 'c.contextlevel DESC, r.sortorder ASC'); 956 $plugins = $this->get_enrolment_plugins(false); 957 foreach ($ras as $ra) { 958 if ($ra->contextid != $this->context->id) { 959 if (!array_key_exists($ra->roleid, $roles)) { 960 $roles[$ra->roleid] = null; 961 } 962 // higher ras, course always takes precedence 963 continue; 964 } 965 if (array_key_exists($ra->roleid, $roles) && $roles[$ra->roleid] === false) { 966 continue; 967 } 968 $changeable = true; 969 if ($ra->component) { 970 $changeable = false; 971 if (strpos($ra->component, 'enrol_') === 0) { 972 $plugin = substr($ra->component, 6); 973 if (isset($plugins[$plugin])) { 974 $changeable = !$plugins[$plugin]->roles_protected(); 975 } 976 } 977 } 978 979 $roles[$ra->roleid] = $changeable; 980 } 981 return $roles; 982 } 983 984 /** 985 * Gets the enrolments this user has in the course - including all suspended plugins and instances. 986 * 987 * @global moodle_database $DB 988 * @param int $userid 989 * @return array 990 */ 991 public function get_user_enrolments($userid) { 992 global $DB; 993 list($instancessql, $params, $filter) = $this->get_instance_sql(); 994 $params['userid'] = $userid; 995 $userenrolments = $DB->get_records_select('user_enrolments', "enrolid $instancessql AND userid = :userid", $params); 996 $instances = $this->get_enrolment_instances(); 997 $plugins = $this->get_enrolment_plugins(false); 998 $inames = $this->get_enrolment_instance_names(); 999 foreach ($userenrolments as &$ue) { 1000 $ue->enrolmentinstance = $instances[$ue->enrolid]; 1001 $ue->enrolmentplugin = $plugins[$ue->enrolmentinstance->enrol]; 1002 $ue->enrolmentinstancename = $inames[$ue->enrolmentinstance->id]; 1003 } 1004 return $userenrolments; 1005 } 1006 1007 /** 1008 * Gets the groups this user belongs to 1009 * 1010 * @param int $userid 1011 * @return array 1012 */ 1013 public function get_user_groups($userid) { 1014 return groups_get_all_groups($this->course->id, $userid, 0, 'g.id'); 1015 } 1016 1017 /** 1018 * Retursn an array of params that would go into the URL to return to this 1019 * exact page. 1020 * 1021 * @return array 1022 */ 1023 public function get_url_params() { 1024 $args = array( 1025 'id' => $this->course->id 1026 ); 1027 if (!empty($this->instancefilter)) { 1028 $args['ifilter'] = $this->instancefilter; 1029 } 1030 if (!empty($this->rolefilter)) { 1031 $args['role'] = $this->rolefilter; 1032 } 1033 if ($this->searchfilter !== '') { 1034 $args['search'] = $this->searchfilter; 1035 } 1036 if (!empty($this->groupfilter)) { 1037 $args['filtergroup'] = $this->groupfilter; 1038 } 1039 if ($this->statusfilter !== -1) { 1040 $args['status'] = $this->statusfilter; 1041 } 1042 return $args; 1043 } 1044 1045 /** 1046 * Returns the course this object is managing enrolments for 1047 * 1048 * @return stdClass 1049 */ 1050 public function get_course() { 1051 return $this->course; 1052 } 1053 1054 /** 1055 * Returns the course context 1056 * 1057 * @return context 1058 */ 1059 public function get_context() { 1060 return $this->context; 1061 } 1062 1063 /** 1064 * Gets an array of other users in this course ready for display. 1065 * 1066 * Other users are users who have been assigned or inherited roles within this 1067 * course but have not been enrolled. 1068 * 1069 * @param core_enrol_renderer $renderer 1070 * @param moodle_url $pageurl 1071 * @param string $sort 1072 * @param string $direction ASC | DESC 1073 * @param int $page Starting from 0 1074 * @param int $perpage 1075 * @return array 1076 */ 1077 public function get_other_users_for_display(core_enrol_renderer $renderer, moodle_url $pageurl, $sort, $direction, $page, $perpage) { 1078 1079 $userroles = $this->get_other_users($sort, $direction, $page, $perpage); 1080 $roles = $this->get_all_roles(); 1081 $plugins = $this->get_enrolment_plugins(false); 1082 1083 $context = $this->get_context(); 1084 $now = time(); 1085 // TODO Does not support custom user profile fields (MDL-70456). 1086 $extrafields = fields::get_identity_fields($context, false); 1087 1088 $users = array(); 1089 foreach ($userroles as $userrole) { 1090 $contextid = $userrole->contextid; 1091 unset($userrole->contextid); // This would collide with user avatar. 1092 if (!array_key_exists($userrole->id, $users)) { 1093 $users[$userrole->id] = $this->prepare_user_for_display($userrole, $extrafields, $now); 1094 } 1095 $a = new stdClass; 1096 $a->role = $roles[$userrole->roleid]->localname; 1097 if ($contextid == $this->context->id) { 1098 $changeable = true; 1099 if ($userrole->component) { 1100 $changeable = false; 1101 if (strpos($userrole->component, 'enrol_') === 0) { 1102 $plugin = substr($userrole->component, 6); 1103 if (isset($plugins[$plugin])) { 1104 $changeable = !$plugins[$plugin]->roles_protected(); 1105 } 1106 } 1107 } 1108 $roletext = get_string('rolefromthiscourse', 'enrol', $a); 1109 } else { 1110 $changeable = false; 1111 switch ($userrole->contextlevel) { 1112 case CONTEXT_COURSE : 1113 // Meta course 1114 $roletext = get_string('rolefrommetacourse', 'enrol', $a); 1115 break; 1116 case CONTEXT_COURSECAT : 1117 $roletext = get_string('rolefromcategory', 'enrol', $a); 1118 break; 1119 case CONTEXT_SYSTEM: 1120 default: 1121 $roletext = get_string('rolefromsystem', 'enrol', $a); 1122 break; 1123 } 1124 } 1125 if (!isset($users[$userrole->id]['roles'])) { 1126 $users[$userrole->id]['roles'] = array(); 1127 } 1128 $users[$userrole->id]['roles'][$userrole->roleid] = array( 1129 'text' => $roletext, 1130 'unchangeable' => !$changeable 1131 ); 1132 } 1133 return $users; 1134 } 1135 1136 /** 1137 * Gets an array of users for display, this includes minimal user information 1138 * as well as minimal information on the users roles, groups, and enrolments. 1139 * 1140 * @param core_enrol_renderer $renderer 1141 * @param moodle_url $pageurl 1142 * @param int $sort 1143 * @param string $direction ASC or DESC 1144 * @param int $page 1145 * @param int $perpage 1146 * @return array 1147 */ 1148 public function get_users_for_display(course_enrolment_manager $manager, $sort, $direction, $page, $perpage) { 1149 $pageurl = $manager->get_moodlepage()->url; 1150 $users = $this->get_users($sort, $direction, $page, $perpage); 1151 1152 $now = time(); 1153 $straddgroup = get_string('addgroup', 'group'); 1154 $strunenrol = get_string('unenrol', 'enrol'); 1155 $stredit = get_string('edit'); 1156 1157 $visibleroles = $this->get_viewable_roles(); 1158 $assignable = $this->get_assignable_roles(); 1159 $allgroups = $this->get_all_groups(); 1160 $context = $this->get_context(); 1161 $canmanagegroups = has_capability('moodle/course:managegroups', $context); 1162 1163 $url = new moodle_url($pageurl, $this->get_url_params()); 1164 // TODO Does not support custom user profile fields (MDL-70456). 1165 $extrafields = fields::get_identity_fields($context, false); 1166 1167 $enabledplugins = $this->get_enrolment_plugins(true); 1168 1169 $userdetails = array(); 1170 foreach ($users as $user) { 1171 $details = $this->prepare_user_for_display($user, $extrafields, $now); 1172 1173 // Roles 1174 $details['roles'] = array(); 1175 foreach ($this->get_user_roles($user->id) as $rid=>$rassignable) { 1176 $unchangeable = !$rassignable; 1177 if (!is_siteadmin() and !isset($assignable[$rid])) { 1178 $unchangeable = true; 1179 } 1180 1181 if (isset($visibleroles[$rid])) { 1182 $label = $visibleroles[$rid]; 1183 } else { 1184 $label = get_string('novisibleroles', 'role'); 1185 $unchangeable = true; 1186 } 1187 1188 $details['roles'][$rid] = array('text' => $label, 'unchangeable' => $unchangeable); 1189 } 1190 1191 // Users 1192 $usergroups = $this->get_user_groups($user->id); 1193 $details['groups'] = array(); 1194 foreach($usergroups as $gid=>$unused) { 1195 $details['groups'][$gid] = $allgroups[$gid]->name; 1196 } 1197 1198 // Enrolments 1199 $details['enrolments'] = array(); 1200 foreach ($this->get_user_enrolments($user->id) as $ue) { 1201 if (!isset($enabledplugins[$ue->enrolmentinstance->enrol])) { 1202 $details['enrolments'][$ue->id] = array( 1203 'text' => $ue->enrolmentinstancename, 1204 'period' => null, 1205 'dimmed' => true, 1206 'actions' => array() 1207 ); 1208 continue; 1209 } else if ($ue->timestart and $ue->timeend) { 1210 $period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend))); 1211 $periodoutside = ($ue->timestart && $ue->timeend && ($now < $ue->timestart || $now > $ue->timeend)); 1212 } else if ($ue->timestart) { 1213 $period = get_string('periodstart', 'enrol', userdate($ue->timestart)); 1214 $periodoutside = ($ue->timestart && $now < $ue->timestart); 1215 } else if ($ue->timeend) { 1216 $period = get_string('periodend', 'enrol', userdate($ue->timeend)); 1217 $periodoutside = ($ue->timeend && $now > $ue->timeend); 1218 } else { 1219 // If there is no start or end show when user was enrolled. 1220 $period = get_string('periodnone', 'enrol', userdate($ue->timecreated)); 1221 $periodoutside = false; 1222 } 1223 $details['enrolments'][$ue->id] = array( 1224 'text' => $ue->enrolmentinstancename, 1225 'period' => $period, 1226 'dimmed' => ($periodoutside or $ue->status != ENROL_USER_ACTIVE or $ue->enrolmentinstance->status != ENROL_INSTANCE_ENABLED), 1227 'actions' => $ue->enrolmentplugin->get_user_enrolment_actions($manager, $ue) 1228 ); 1229 } 1230 $userdetails[$user->id] = $details; 1231 } 1232 return $userdetails; 1233 } 1234 1235 /** 1236 * Prepare a user record for display 1237 * 1238 * This function is called by both {@link get_users_for_display} and {@link get_other_users_for_display} to correctly 1239 * prepare user fields for display 1240 * 1241 * Please note that this function does not check capability for moodle/coures:viewhiddenuserfields 1242 * 1243 * @param object $user The user record 1244 * @param array $extrafields The list of fields as returned from \core_user\fields::get_identity_fields used to determine which 1245 * additional fields may be displayed 1246 * @param int $now The time used for lastaccess calculation 1247 * @return array The fields to be displayed including userid, courseid, picture, firstname, lastcourseaccess, lastaccess and any 1248 * additional fields from $extrafields 1249 */ 1250 private function prepare_user_for_display($user, $extrafields, $now) { 1251 $details = array( 1252 'userid' => $user->id, 1253 'courseid' => $this->get_course()->id, 1254 'picture' => new user_picture($user), 1255 'userfullnamedisplay' => fullname($user, has_capability('moodle/site:viewfullnames', $this->get_context())), 1256 'lastaccess' => get_string('never'), 1257 'lastcourseaccess' => get_string('never'), 1258 ); 1259 1260 foreach ($extrafields as $field) { 1261 $details[$field] = s($user->{$field}); 1262 } 1263 1264 // Last time user has accessed the site. 1265 if (!empty($user->lastaccess)) { 1266 $details['lastaccess'] = format_time($now - $user->lastaccess); 1267 } 1268 1269 // Last time user has accessed the course. 1270 if (!empty($user->lastcourseaccess)) { 1271 $details['lastcourseaccess'] = format_time($now - $user->lastcourseaccess); 1272 } 1273 return $details; 1274 } 1275 1276 public function get_manual_enrol_buttons() { 1277 $plugins = $this->get_enrolment_plugins(true); // Skip disabled plugins. 1278 $buttons = array(); 1279 foreach ($plugins as $plugin) { 1280 $newbutton = $plugin->get_manual_enrol_button($this); 1281 if (is_array($newbutton)) { 1282 $buttons += $newbutton; 1283 } else if ($newbutton instanceof enrol_user_button) { 1284 $buttons[] = $newbutton; 1285 } 1286 } 1287 return $buttons; 1288 } 1289 1290 public function has_instance($enrolpluginname) { 1291 // Make sure manual enrolments instance exists 1292 foreach ($this->get_enrolment_instances() as $instance) { 1293 if ($instance->enrol == $enrolpluginname) { 1294 return true; 1295 } 1296 } 1297 return false; 1298 } 1299 1300 /** 1301 * Returns the enrolment plugin that the course manager was being filtered to. 1302 * 1303 * If no filter was being applied then this function returns false. 1304 * 1305 * @return enrol_plugin 1306 */ 1307 public function get_filtered_enrolment_plugin() { 1308 $instances = $this->get_enrolment_instances(); 1309 $plugins = $this->get_enrolment_plugins(false); 1310 1311 if (empty($this->instancefilter) || !array_key_exists($this->instancefilter, $instances)) { 1312 return false; 1313 } 1314 1315 $instance = $instances[$this->instancefilter]; 1316 return $plugins[$instance->enrol]; 1317 } 1318 1319 /** 1320 * Returns and array of users + enrolment details. 1321 * 1322 * Given an array of user id's this function returns and array of user enrolments for those users 1323 * as well as enough user information to display the users name and picture for each enrolment. 1324 * 1325 * @global moodle_database $DB 1326 * @param array $userids 1327 * @return array 1328 */ 1329 public function get_users_enrolments(array $userids) { 1330 global $DB; 1331 1332 $instances = $this->get_enrolment_instances(); 1333 $plugins = $this->get_enrolment_plugins(false); 1334 1335 if (!empty($this->instancefilter)) { 1336 $instancesql = ' = :instanceid'; 1337 $instanceparams = array('instanceid' => $this->instancefilter); 1338 } else { 1339 list($instancesql, $instanceparams) = $DB->get_in_or_equal(array_keys($instances), SQL_PARAMS_NAMED, 'instanceid0000'); 1340 } 1341 1342 $userfieldsapi = \core_user\fields::for_userpic(); 1343 $userfields = $userfieldsapi->get_sql('u', false, '', '', false)->selects; 1344 list($idsql, $idparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'userid0000'); 1345 1346 list($sort, $sortparams) = users_order_by_sql('u'); 1347 1348 $sql = "SELECT ue.id AS ueid, ue.status, ue.enrolid, ue.userid, ue.timestart, ue.timeend, ue.modifierid, ue.timecreated, ue.timemodified, $userfields 1349 FROM {user_enrolments} ue 1350 LEFT JOIN {user} u ON u.id = ue.userid 1351 WHERE ue.enrolid $instancesql AND 1352 u.id $idsql 1353 ORDER BY $sort"; 1354 1355 $rs = $DB->get_recordset_sql($sql, $idparams + $instanceparams + $sortparams); 1356 $users = array(); 1357 foreach ($rs as $ue) { 1358 $user = user_picture::unalias($ue); 1359 $ue->id = $ue->ueid; 1360 unset($ue->ueid); 1361 if (!array_key_exists($user->id, $users)) { 1362 $user->enrolments = array(); 1363 $users[$user->id] = $user; 1364 } 1365 $ue->enrolmentinstance = $instances[$ue->enrolid]; 1366 $ue->enrolmentplugin = $plugins[$ue->enrolmentinstance->enrol]; 1367 $users[$user->id]->enrolments[$ue->id] = $ue; 1368 } 1369 $rs->close(); 1370 return $users; 1371 } 1372 } 1373 1374 /** 1375 * A button that is used to enrol users in a course 1376 * 1377 * @copyright 2010 Sam Hemelryk 1378 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1379 */ 1380 class enrol_user_button extends single_button { 1381 1382 /** 1383 * An array containing JS YUI modules required by this button 1384 * @var array 1385 */ 1386 protected $jsyuimodules = array(); 1387 1388 /** 1389 * An array containing JS initialisation calls required by this button 1390 * @var array 1391 */ 1392 protected $jsinitcalls = array(); 1393 1394 /** 1395 * An array strings required by JS for this button 1396 * @var array 1397 */ 1398 protected $jsstrings = array(); 1399 1400 /** 1401 * Initialises the new enrol_user_button 1402 * 1403 * @staticvar int $count The number of enrol user buttons already created 1404 * @param moodle_url $url 1405 * @param string $label The text to display in the button 1406 * @param string $method Either post or get 1407 */ 1408 public function __construct(moodle_url $url, $label, $method = 'post') { 1409 static $count = 0; 1410 $count ++; 1411 parent::__construct($url, $label, $method); 1412 $this->class = 'singlebutton enrolusersbutton'; 1413 $this->formid = 'enrolusersbutton-'.$count; 1414 } 1415 1416 /** 1417 * Adds a YUI module call that will be added to the page when the button is used. 1418 * 1419 * @param string|array $modules One or more modules to require 1420 * @param string $function The JS function to call 1421 * @param array $arguments An array of arguments to pass to the function 1422 * @param string $galleryversion Deprecated: The gallery version to use 1423 * @param bool $ondomready If true the call is postponed until the DOM is finished loading 1424 */ 1425 public function require_yui_module($modules, $function, array $arguments = null, $galleryversion = null, $ondomready = false) { 1426 if ($galleryversion != null) { 1427 debugging('The galleryversion parameter to yui_module has been deprecated since Moodle 2.3.', DEBUG_DEVELOPER); 1428 } 1429 1430 $js = new stdClass; 1431 $js->modules = (array)$modules; 1432 $js->function = $function; 1433 $js->arguments = $arguments; 1434 $js->ondomready = $ondomready; 1435 $this->jsyuimodules[] = $js; 1436 } 1437 1438 /** 1439 * Adds a JS initialisation call to the page when the button is used. 1440 * 1441 * @param string $function The function to call 1442 * @param array $extraarguments An array of arguments to pass to the function 1443 * @param bool $ondomready If true the call is postponed until the DOM is finished loading 1444 * @param array $module A module definition 1445 */ 1446 public function require_js_init_call($function, array $extraarguments = null, $ondomready = false, array $module = null) { 1447 $js = new stdClass; 1448 $js->function = $function; 1449 $js->extraarguments = $extraarguments; 1450 $js->ondomready = $ondomready; 1451 $js->module = $module; 1452 $this->jsinitcalls[] = $js; 1453 } 1454 1455 /** 1456 * Requires strings for JS that will be loaded when the button is used. 1457 * 1458 * @param type $identifiers 1459 * @param string $component 1460 * @param mixed $a 1461 */ 1462 public function strings_for_js($identifiers, $component = 'moodle', $a = null) { 1463 $string = new stdClass; 1464 $string->identifiers = (array)$identifiers; 1465 $string->component = $component; 1466 $string->a = $a; 1467 $this->jsstrings[] = $string; 1468 } 1469 1470 /** 1471 * Initialises the JS that is required by this button 1472 * 1473 * @param moodle_page $page 1474 */ 1475 public function initialise_js(moodle_page $page) { 1476 foreach ($this->jsyuimodules as $js) { 1477 $page->requires->yui_module($js->modules, $js->function, $js->arguments, null, $js->ondomready); 1478 } 1479 foreach ($this->jsinitcalls as $js) { 1480 $page->requires->js_init_call($js->function, $js->extraarguments, $js->ondomready, $js->module); 1481 } 1482 foreach ($this->jsstrings as $string) { 1483 $page->requires->strings_for_js($string->identifiers, $string->component, $string->a); 1484 } 1485 } 1486 } 1487 1488 /** 1489 * User enrolment action 1490 * 1491 * This class is used to manage a renderable ue action such as editing an user enrolment or deleting 1492 * a user enrolment. 1493 * 1494 * @copyright 2011 Sam Hemelryk 1495 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1496 */ 1497 class user_enrolment_action implements renderable { 1498 1499 /** 1500 * The icon to display for the action 1501 * @var pix_icon 1502 */ 1503 protected $icon; 1504 1505 /** 1506 * The title for the action 1507 * @var string 1508 */ 1509 protected $title; 1510 1511 /** 1512 * The URL to the action 1513 * @var moodle_url 1514 */ 1515 protected $url; 1516 1517 /** 1518 * An array of HTML attributes 1519 * @var array 1520 */ 1521 protected $attributes = array(); 1522 1523 /** 1524 * Constructor 1525 * @param pix_icon $icon 1526 * @param string $title 1527 * @param moodle_url $url 1528 * @param array $attributes 1529 */ 1530 public function __construct(pix_icon $icon, $title, $url, array $attributes = null) { 1531 $this->icon = $icon; 1532 $this->title = $title; 1533 $this->url = new moodle_url($url); 1534 if (!empty($attributes)) { 1535 $this->attributes = $attributes; 1536 } 1537 $this->attributes['title'] = $title; 1538 } 1539 1540 /** 1541 * Returns the icon for this action 1542 * @return pix_icon 1543 */ 1544 public function get_icon() { 1545 return $this->icon; 1546 } 1547 1548 /** 1549 * Returns the title for this action 1550 * @return string 1551 */ 1552 public function get_title() { 1553 return $this->title; 1554 } 1555 1556 /** 1557 * Returns the URL for this action 1558 * @return moodle_url 1559 */ 1560 public function get_url() { 1561 return $this->url; 1562 } 1563 1564 /** 1565 * Returns the attributes to use for this action 1566 * @return array 1567 */ 1568 public function get_attributes() { 1569 return $this->attributes; 1570 } 1571 } 1572 1573 class enrol_ajax_exception extends moodle_exception { 1574 /** 1575 * Constructor 1576 * @param string $errorcode The name of the string from error.php to print 1577 * @param string $module name of module 1578 * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page. 1579 * @param object $a Extra words and phrases that might be required in the error string 1580 * @param string $debuginfo optional debugging information 1581 */ 1582 public function __construct($errorcode, $link = '', $a = NULL, $debuginfo = null) { 1583 parent::__construct($errorcode, 'enrol', $link, $a, $debuginfo); 1584 } 1585 } 1586 1587 /** 1588 * This class is used to manage a bulk operations for enrolment plugins. 1589 * 1590 * @copyright 2011 Sam Hemelryk 1591 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1592 */ 1593 abstract class enrol_bulk_enrolment_operation { 1594 1595 /** 1596 * The course enrolment manager 1597 * @var course_enrolment_manager 1598 */ 1599 protected $manager; 1600 1601 /** 1602 * The enrolment plugin to which this operation belongs 1603 * @var enrol_plugin 1604 */ 1605 protected $plugin; 1606 1607 /** 1608 * Contructor 1609 * @param course_enrolment_manager $manager 1610 * @param stdClass $plugin 1611 */ 1612 public function __construct(course_enrolment_manager $manager, enrol_plugin $plugin = null) { 1613 $this->manager = $manager; 1614 $this->plugin = $plugin; 1615 } 1616 1617 /** 1618 * Returns a moodleform used for this operation, or false if no form is required and the action 1619 * should be immediatly processed. 1620 * 1621 * @param moodle_url|string $defaultaction 1622 * @param mixed $defaultcustomdata 1623 * @return enrol_bulk_enrolment_change_form|moodleform|false 1624 */ 1625 public function get_form($defaultaction = null, $defaultcustomdata = null) { 1626 return false; 1627 } 1628 1629 /** 1630 * Returns the title to use for this bulk operation 1631 * 1632 * @return string 1633 */ 1634 abstract public function get_title(); 1635 1636 /** 1637 * Returns the identifier for this bulk operation. 1638 * This should be the same identifier used by the plugins function when returning 1639 * all of its bulk operations. 1640 * 1641 * @return string 1642 */ 1643 abstract public function get_identifier(); 1644 1645 /** 1646 * Processes the bulk operation on the given users 1647 * 1648 * @param course_enrolment_manager $manager 1649 * @param array $users 1650 * @param stdClass $properties 1651 */ 1652 abstract public function process(course_enrolment_manager $manager, array $users, stdClass $properties); 1653 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body