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