2115b15de84511a78f5eaf9688a5f746ac420525
[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, ul.timeaccess AS lastseen
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 u.$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             $sql = "SELECT ra.id as raid, ra.contextid, ra.component, ctx.contextlevel, ra.roleid, u.*, ue.lastseen
338                     FROM {role_assignments} ra
339                     JOIN {user} u ON u.id = ra.userid
340                     JOIN {context} ctx ON ra.contextid = ctx.id
341                LEFT JOIN (
342                        SELECT ue.id, ue.userid, ul.timeaccess AS lastseen
343                          FROM {user_enrolments} ue
344                     LEFT JOIN {enrol} e ON e.id=ue.enrolid
345                     LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = ue.userid)
346                         WHERE e.courseid = :courseid
347                        ) ue ON ue.userid=u.id
348                    WHERE ctx.id $ctxcondition AND
349                          ue.id IS NULL
350                 ORDER BY u.$sort $direction, ctx.depth DESC";
351             $this->otherusers[$key] = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage);
352         }
353         return $this->otherusers[$key];
354     }
356     /**
357      * Helper method used by {@link get_potential_users()} and {@link search_other_users()}.
358      *
359      * @param string $search the search term, if any.
360      * @param bool $searchanywhere Can the search term be anywhere, or must it be at the start.
361      * @return array with three elements:
362      *     string list of fields to SELECT,
363      *     string contents of SQL WHERE clause,
364      *     array query params. Note that the SQL snippets use named parameters.
365      */
366     protected function get_basic_search_conditions($search, $searchanywhere) {
367         global $DB, $CFG;
369         // Add some additional sensible conditions
370         $tests = array("u.id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1');
371         $params = array('guestid' => $CFG->siteguest);
372         if (!empty($search)) {
373             $conditions = get_extra_user_fields($this->get_context());
374             $conditions[] = 'u.firstname';
375             $conditions[] = 'u.lastname';
376             $conditions[] = $DB->sql_fullname('u.firstname', 'u.lastname');
377             if ($searchanywhere) {
378                 $searchparam = '%' . $search . '%';
379             } else {
380                 $searchparam = $search . '%';
381             }
382             $i = 0;
383             foreach ($conditions as $key => $condition) {
384                 $conditions[$key] = $DB->sql_like($condition, ":con{$i}00", false);
385                 $params["con{$i}00"] = $searchparam;
386                 $i++;
387             }
388             $tests[] = '(' . implode(' OR ', $conditions) . ')';
389         }
390         $wherecondition = implode(' AND ', $tests);
392         $extrafields = get_extra_user_fields($this->get_context(), array('username', 'lastaccess'));
393         $extrafields[] = 'username';
394         $extrafields[] = 'lastaccess';
395         $ufields = user_picture::fields('u', $extrafields);
397         return array($ufields, $params, $wherecondition);
398     }
400     /**
401      * Helper method used by {@link get_potential_users()} and {@link search_other_users()}.
402      *
403      * @param string $search the search string, if any.
404      * @param string $fields the first bit of the SQL when returning some users.
405      * @param string $countfields fhe first bit of the SQL when counting the users.
406      * @param string $sql the bulk of the SQL statement.
407      * @param array $params query parameters.
408      * @param int $page which page number of the results to show.
409      * @param int $perpage number of users per page.
410      * @param int $addedenrollment number of users added to enrollment.
411      * @return array with two elememts:
412      *      int total number of users matching the search.
413      *      array of user objects returned by the query.
414      */
415     protected function execute_search_queries($search, $fields, $countfields, $sql, array $params, $page, $perpage, $addedenrollment=0) {
416         global $DB, $CFG;
418         list($sort, $sortparams) = users_order_by_sql('u', $search, $this->get_context());
419         $order = ' ORDER BY ' . $sort;
421         $totalusers = $DB->count_records_sql($countfields . $sql, $params);
422         $availableusers = $DB->get_records_sql($fields . $sql . $order,
423                 array_merge($params, $sortparams), ($page*$perpage) - $addedenrollment, $perpage);
425         return array('totalusers' => $totalusers, 'users' => $availableusers);
426     }
428     /**
429      * Gets an array of the users that can be enrolled in this course.
430      *
431      * @global moodle_database $DB
432      * @param int $enrolid
433      * @param string $search
434      * @param bool $searchanywhere
435      * @param int $page Defaults to 0
436      * @param int $perpage Defaults to 25
437      * @param int $addedenrollment Defaults to 0
438      * @return array Array(totalusers => int, users => array)
439      */
440     public function get_potential_users($enrolid, $search='', $searchanywhere=false, $page=0, $perpage=25, $addedenrollment=0) {
441         global $DB;
443         list($ufields, $params, $wherecondition) = $this->get_basic_search_conditions($search, $searchanywhere);
445         $fields      = 'SELECT '.$ufields;
446         $countfields = 'SELECT COUNT(1)';
447         $sql = " FROM {user} u
448             LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
449                 WHERE $wherecondition
450                       AND ue.id IS NULL";
451         $params['enrolid'] = $enrolid;
453         return $this->execute_search_queries($search, $fields, $countfields, $sql, $params, $page, $perpage, $addedenrollment);
454     }
456     /**
457      * Searches other users and returns paginated results
458      *
459      * @global moodle_database $DB
460      * @param string $search
461      * @param bool $searchanywhere
462      * @param int $page Starting at 0
463      * @param int $perpage
464      * @return array
465      */
466     public function search_other_users($search='', $searchanywhere=false, $page=0, $perpage=25) {
467         global $DB, $CFG;
469         list($ufields, $params, $wherecondition) = $this->get_basic_search_conditions($search, $searchanywhere);
471         $fields      = 'SELECT ' . $ufields;
472         $countfields = 'SELECT COUNT(u.id)';
473         $sql   = " FROM {user} u
474               LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid = :contextid)
475                   WHERE $wherecondition
476                     AND ra.id IS NULL";
477         $params['contextid'] = $this->context->id;
479         return $this->execute_search_queries($search, $fields, $countfields, $sql, $params, $page, $perpage);
480     }
482     /**
483      * Gets an array containing some SQL to user for when selecting, params for
484      * that SQL, and the filter that was used in constructing the sql.
485      *
486      * @global moodle_database $DB
487      * @return string
488      */
489     protected function get_instance_sql() {
490         global $DB;
491         if ($this->_instancessql === null) {
492             $instances = $this->get_enrolment_instances();
493             $filter = $this->get_enrolment_filter();
494             if ($filter && array_key_exists($filter, $instances)) {
495                 $sql = " = :ifilter";
496                 $params = array('ifilter'=>$filter);
497             } else {
498                 $filter = 0;
499                 if ($instances) {
500                     list($sql, $params) = $DB->get_in_or_equal(array_keys($this->get_enrolment_instances()), SQL_PARAMS_NAMED);
501                 } else {
502                     // no enabled instances, oops, we should probably say something
503                     $sql = "= :never";
504                     $params = array('never'=>-1);
505                 }
506             }
507             $this->instancefilter = $filter;
508             $this->_instancessql = array($sql, $params, $filter);
509         }
510         return $this->_instancessql;
511     }
513     /**
514      * Returns all of the enrolment instances for this course.
515      *
516      * NOTE: since 2.4 it includes instances of disabled plugins too.
517      *
518      * @return array
519      */
520     public function get_enrolment_instances() {
521         if ($this->_instances === null) {
522             $this->_instances = enrol_get_instances($this->course->id, false);
523         }
524         return $this->_instances;
525     }
527     /**
528      * Returns the names for all of the enrolment instances for this course.
529      *
530      * NOTE: since 2.4 it includes instances of disabled plugins too.
531      *
532      * @return array
533      */
534     public function get_enrolment_instance_names() {
535         if ($this->_inames === null) {
536             $instances = $this->get_enrolment_instances();
537             $plugins = $this->get_enrolment_plugins(false);
538             foreach ($instances as $key=>$instance) {
539                 if (!isset($plugins[$instance->enrol])) {
540                     // weird, some broken stuff in plugin
541                     unset($instances[$key]);
542                     continue;
543                 }
544                 $this->_inames[$key] = $plugins[$instance->enrol]->get_instance_name($instance);
545             }
546         }
547         return $this->_inames;
548     }
550     /**
551      * Gets all of the enrolment plugins that are active for this course.
552      *
553      * @param bool $onlyenabled return only enabled enrol plugins
554      * @return array
555      */
556     public function get_enrolment_plugins($onlyenabled = true) {
557         if ($this->_plugins === null) {
558             $this->_plugins = enrol_get_plugins(true);
559         }
561         if ($onlyenabled) {
562             return $this->_plugins;
563         }
565         if ($this->_allplugins === null) {
566             // Make sure we have the same objects in _allplugins and _plugins.
567             $this->_allplugins = $this->_plugins;
568             foreach (enrol_get_plugins(false) as $name=>$plugin) {
569                 if (!isset($this->_allplugins[$name])) {
570                     $this->_allplugins[$name] = $plugin;
571                 }
572             }
573         }
575         return $this->_allplugins;
576     }
578     /**
579      * Gets all of the roles this course can contain.
580      *
581      * @return array
582      */
583     public function get_all_roles() {
584         if ($this->_roles === null) {
585             $this->_roles = role_fix_names(get_all_roles($this->context), $this->context);
586         }
587         return $this->_roles;
588     }
590     /**
591      * Gets all of the assignable roles for this course.
592      *
593      * @return array
594      */
595     public function get_assignable_roles($otherusers = false) {
596         if ($this->_assignableroles === null) {
597             $this->_assignableroles = get_assignable_roles($this->context, ROLENAME_ALIAS, false); // verifies unassign access control too
598         }
600         if ($otherusers) {
601             if (!is_array($this->_assignablerolesothers)) {
602                 $this->_assignablerolesothers = array();
603                 list($courseviewroles, $ignored) = get_roles_with_cap_in_context($this->context, 'moodle/course:view');
604                 foreach ($this->_assignableroles as $roleid=>$role) {
605                     if (isset($courseviewroles[$roleid])) {
606                         $this->_assignablerolesothers[$roleid] = $role;
607                     }
608                 }
609             }
610             return $this->_assignablerolesothers;
611         } else {
612             return $this->_assignableroles;
613         }
614     }
616     /**
617      * Gets all of the groups for this course.
618      *
619      * @return array
620      */
621     public function get_all_groups() {
622         if ($this->_groups === null) {
623             $this->_groups = groups_get_all_groups($this->course->id);
624             foreach ($this->_groups as $gid=>$group) {
625                 $this->_groups[$gid]->name = format_string($group->name);
626             }
627         }
628         return $this->_groups;
629     }
631     /**
632      * Unenrols a user from the course given the users ue entry
633      *
634      * @global moodle_database $DB
635      * @param stdClass $ue
636      * @return bool
637      */
638     public function unenrol_user($ue) {
639         global $DB;
640         list ($instance, $plugin) = $this->get_user_enrolment_components($ue);
641         if ($instance && $plugin && $plugin->allow_unenrol_user($instance, $ue) && has_capability("enrol/$instance->enrol:unenrol", $this->context)) {
642             $plugin->unenrol_user($instance, $ue->userid);
643             return true;
644         }
645         return false;
646     }
648     /**
649      * Given a user enrolment record this method returns the plugin and enrolment
650      * instance that relate to it.
651      *
652      * @param stdClass|int $userenrolment
653      * @return array array($instance, $plugin)
654      */
655     public function get_user_enrolment_components($userenrolment) {
656         global $DB;
657         if (is_numeric($userenrolment)) {
658             $userenrolment = $DB->get_record('user_enrolments', array('id'=>(int)$userenrolment));
659         }
660         $instances = $this->get_enrolment_instances();
661         $plugins = $this->get_enrolment_plugins(false);
662         if (!$userenrolment || !isset($instances[$userenrolment->enrolid])) {
663             return array(false, false);
664         }
665         $instance = $instances[$userenrolment->enrolid];
666         $plugin = $plugins[$instance->enrol];
667         return array($instance, $plugin);
668     }
670     /**
671      * Removes an assigned role from a user.
672      *
673      * @global moodle_database $DB
674      * @param int $userid
675      * @param int $roleid
676      * @return bool
677      */
678     public function unassign_role_from_user($userid, $roleid) {
679         global $DB;
680         // Admins may unassign any role, others only those they could assign.
681         if (!is_siteadmin() and !array_key_exists($roleid, $this->get_assignable_roles())) {
682             if (defined('AJAX_SCRIPT')) {
683                 throw new moodle_exception('invalidrole');
684             }
685             return false;
686         }
687         $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
688         $ras = $DB->get_records('role_assignments', array('contextid'=>$this->context->id, 'userid'=>$user->id, 'roleid'=>$roleid));
689         foreach ($ras as $ra) {
690             if ($ra->component) {
691                 if (strpos($ra->component, 'enrol_') !== 0) {
692                     continue;
693                 }
694                 if (!$plugin = enrol_get_plugin(substr($ra->component, 6))) {
695                     continue;
696                 }
697                 if ($plugin->roles_protected()) {
698                     continue;
699                 }
700             }
701             role_unassign($ra->roleid, $ra->userid, $ra->contextid, $ra->component, $ra->itemid);
702         }
703         return true;
704     }
706     /**
707      * Assigns a role to a user.
708      *
709      * @param int $roleid
710      * @param int $userid
711      * @return int|false
712      */
713     public function assign_role_to_user($roleid, $userid) {
714         require_capability('moodle/role:assign', $this->context);
715         if (!array_key_exists($roleid, $this->get_assignable_roles())) {
716             if (defined('AJAX_SCRIPT')) {
717                 throw new moodle_exception('invalidrole');
718             }
719             return false;
720         }
721         return role_assign($roleid, $userid, $this->context->id, '', NULL);
722     }
724     /**
725      * Adds a user to a group
726      *
727      * @param stdClass $user
728      * @param int $groupid
729      * @return bool
730      */
731     public function add_user_to_group($user, $groupid) {
732         require_capability('moodle/course:managegroups', $this->context);
733         $group = $this->get_group($groupid);
734         if (!$group) {
735             return false;
736         }
737         return groups_add_member($group->id, $user->id);
738     }
740     /**
741      * Removes a user from a group
742      *
743      * @global moodle_database $DB
744      * @param StdClass $user
745      * @param int $groupid
746      * @return bool
747      */
748     public function remove_user_from_group($user, $groupid) {
749         global $DB;
750         require_capability('moodle/course:managegroups', $this->context);
751         $group = $this->get_group($groupid);
752         if (!groups_remove_member_allowed($group, $user)) {
753             return false;
754         }
755         if (!$group) {
756             return false;
757         }
758         return groups_remove_member($group, $user);
759     }
761     /**
762      * Gets the requested group
763      *
764      * @param int $groupid
765      * @return stdClass|int
766      */
767     public function get_group($groupid) {
768         $groups = $this->get_all_groups();
769         if (!array_key_exists($groupid, $groups)) {
770             return false;
771         }
772         return $groups[$groupid];
773     }
775     /**
776      * Edits an enrolment
777      *
778      * @param stdClass $userenrolment
779      * @param stdClass $data
780      * @return bool
781      */
782     public function edit_enrolment($userenrolment, $data) {
783         //Only allow editing if the user has the appropriate capability
784         //Already checked in /enrol/users.php but checking again in case this function is called from elsewhere
785         list($instance, $plugin) = $this->get_user_enrolment_components($userenrolment);
786         if ($instance && $plugin && $plugin->allow_manage($instance) && has_capability("enrol/$instance->enrol:manage", $this->context)) {
787             if (!isset($data->status)) {
788                 $data->status = $userenrolment->status;
789             }
790             $plugin->update_user_enrol($instance, $userenrolment->userid, $data->status, $data->timestart, $data->timeend);
791             return true;
792         }
793         return false;
794     }
796     /**
797      * Returns the current enrolment filter that is being applied by this class
798      * @return string
799      */
800     public function get_enrolment_filter() {
801         return $this->instancefilter;
802     }
804     /**
805      * Gets the roles assigned to this user that are applicable for this course.
806      *
807      * @param int $userid
808      * @return array
809      */
810     public function get_user_roles($userid) {
811         $roles = array();
812         $ras = get_user_roles($this->context, $userid, true, 'c.contextlevel DESC, r.sortorder ASC');
813         $plugins = $this->get_enrolment_plugins(false);
814         foreach ($ras as $ra) {
815             if ($ra->contextid != $this->context->id) {
816                 if (!array_key_exists($ra->roleid, $roles)) {
817                     $roles[$ra->roleid] = null;
818                 }
819                 // higher ras, course always takes precedence
820                 continue;
821             }
822             if (array_key_exists($ra->roleid, $roles) && $roles[$ra->roleid] === false) {
823                 continue;
824             }
825             $changeable = true;
826             if ($ra->component) {
827                 $changeable = false;
828                 if (strpos($ra->component, 'enrol_') === 0) {
829                     $plugin = substr($ra->component, 6);
830                     if (isset($plugins[$plugin])) {
831                         $changeable = !$plugins[$plugin]->roles_protected();
832                     }
833                 }
834             }
836             $roles[$ra->roleid] = $changeable;
837         }
838         return $roles;
839     }
841     /**
842      * Gets the enrolments this user has in the course - including all suspended plugins and instances.
843      *
844      * @global moodle_database $DB
845      * @param int $userid
846      * @return array
847      */
848     public function get_user_enrolments($userid) {
849         global $DB;
850         list($instancessql, $params, $filter) = $this->get_instance_sql();
851         $params['userid'] = $userid;
852         $userenrolments = $DB->get_records_select('user_enrolments', "enrolid $instancessql AND userid = :userid", $params);
853         $instances = $this->get_enrolment_instances();
854         $plugins = $this->get_enrolment_plugins(false);
855         $inames = $this->get_enrolment_instance_names();
856         foreach ($userenrolments as &$ue) {
857             $ue->enrolmentinstance     = $instances[$ue->enrolid];
858             $ue->enrolmentplugin       = $plugins[$ue->enrolmentinstance->enrol];
859             $ue->enrolmentinstancename = $inames[$ue->enrolmentinstance->id];
860         }
861         return $userenrolments;
862     }
864     /**
865      * Gets the groups this user belongs to
866      *
867      * @param int $userid
868      * @return array
869      */
870     public function get_user_groups($userid) {
871         return groups_get_all_groups($this->course->id, $userid, 0, 'g.id');
872     }
874     /**
875      * Retursn an array of params that would go into the URL to return to this
876      * exact page.
877      *
878      * @return array
879      */
880     public function get_url_params() {
881         $args = array(
882             'id' => $this->course->id
883         );
884         if (!empty($this->instancefilter)) {
885             $args['ifilter'] = $this->instancefilter;
886         }
887         if (!empty($this->rolefilter)) {
888             $args['role'] = $this->rolefilter;
889         }
890         if ($this->searchfilter !== '') {
891             $args['search'] = $this->searchfilter;
892         }
893         if (!empty($this->groupfilter)) {
894             $args['filtergroup'] = $this->groupfilter;
895         }
896         if ($this->statusfilter !== -1) {
897             $args['status'] = $this->statusfilter;
898         }
899         return $args;
900     }
902     /**
903      * Returns the course this object is managing enrolments for
904      *
905      * @return stdClass
906      */
907     public function get_course() {
908         return $this->course;
909     }
911     /**
912      * Returns the course context
913      *
914      * @return stdClass
915      */
916     public function get_context() {
917         return $this->context;
918     }
920     /**
921      * Gets an array of other users in this course ready for display.
922      *
923      * Other users are users who have been assigned or inherited roles within this
924      * course but have not been enrolled.
925      *
926      * @param core_enrol_renderer $renderer
927      * @param moodle_url $pageurl
928      * @param string $sort
929      * @param string $direction ASC | DESC
930      * @param int $page Starting from 0
931      * @param int $perpage
932      * @return array
933      */
934     public function get_other_users_for_display(core_enrol_renderer $renderer, moodle_url $pageurl, $sort, $direction, $page, $perpage) {
936         $userroles = $this->get_other_users($sort, $direction, $page, $perpage);
937         $roles = $this->get_all_roles();
938         $plugins = $this->get_enrolment_plugins(false);
940         $context    = $this->get_context();
941         $now = time();
942         $extrafields = get_extra_user_fields($context);
944         $users = array();
945         foreach ($userroles as $userrole) {
946             $contextid = $userrole->contextid;
947             unset($userrole->contextid); // This would collide with user avatar.
948             if (!array_key_exists($userrole->id, $users)) {
949                 $users[$userrole->id] = $this->prepare_user_for_display($userrole, $extrafields, $now);
950             }
951             $a = new stdClass;
952             $a->role = $roles[$userrole->roleid]->localname;
953             if ($contextid == $this->context->id) {
954                 $changeable = true;
955                 if ($userrole->component) {
956                     $changeable = false;
957                     if (strpos($userrole->component, 'enrol_') === 0) {
958                         $plugin = substr($userrole->component, 6);
959                         if (isset($plugins[$plugin])) {
960                             $changeable = !$plugins[$plugin]->roles_protected();
961                         }
962                     }
963                 }
964                 $roletext = get_string('rolefromthiscourse', 'enrol', $a);
965             } else {
966                 $changeable = false;
967                 switch ($userrole->contextlevel) {
968                     case CONTEXT_COURSE :
969                         // Meta course
970                         $roletext = get_string('rolefrommetacourse', 'enrol', $a);
971                         break;
972                     case CONTEXT_COURSECAT :
973                         $roletext = get_string('rolefromcategory', 'enrol', $a);
974                         break;
975                     case CONTEXT_SYSTEM:
976                     default:
977                         $roletext = get_string('rolefromsystem', 'enrol', $a);
978                         break;
979                 }
980             }
981             if (!isset($users[$userrole->id]['roles'])) {
982                 $users[$userrole->id]['roles'] = array();
983             }
984             $users[$userrole->id]['roles'][$userrole->roleid] = array(
985                 'text' => $roletext,
986                 'unchangeable' => !$changeable
987             );
988         }
989         return $users;
990     }
992     /**
993      * Gets an array of users for display, this includes minimal user information
994      * as well as minimal information on the users roles, groups, and enrolments.
995      *
996      * @param core_enrol_renderer $renderer
997      * @param moodle_url $pageurl
998      * @param int $sort
999      * @param string $direction ASC or DESC
1000      * @param int $page
1001      * @param int $perpage
1002      * @return array
1003      */
1004     public function get_users_for_display(course_enrolment_manager $manager, $sort, $direction, $page, $perpage) {
1005         $pageurl = $manager->get_moodlepage()->url;
1006         $users = $this->get_users($sort, $direction, $page, $perpage);
1008         $now = time();
1009         $straddgroup = get_string('addgroup', 'group');
1010         $strunenrol = get_string('unenrol', 'enrol');
1011         $stredit = get_string('edit');
1013         $allroles   = $this->get_all_roles();
1014         $assignable = $this->get_assignable_roles();
1015         $allgroups  = $this->get_all_groups();
1016         $context    = $this->get_context();
1017         $canmanagegroups = has_capability('moodle/course:managegroups', $context);
1019         $url = new moodle_url($pageurl, $this->get_url_params());
1020         $extrafields = get_extra_user_fields($context);
1022         $enabledplugins = $this->get_enrolment_plugins(true);
1024         $userdetails = array();
1025         foreach ($users as $user) {
1026             $details = $this->prepare_user_for_display($user, $extrafields, $now);
1028             // Roles
1029             $details['roles'] = array();
1030             foreach ($this->get_user_roles($user->id) as $rid=>$rassignable) {
1031                 $unchangeable = !$rassignable;
1032                 if (!is_siteadmin() and !isset($assignable[$rid])) {
1033                     $unchangeable = true;
1034                 }
1035                 $details['roles'][$rid] = array('text'=>$allroles[$rid]->localname, 'unchangeable'=>$unchangeable);
1036             }
1038             // Users
1039             $usergroups = $this->get_user_groups($user->id);
1040             $details['groups'] = array();
1041             foreach($usergroups as $gid=>$unused) {
1042                 $details['groups'][$gid] = $allgroups[$gid]->name;
1043             }
1045             // Enrolments
1046             $details['enrolments'] = array();
1047             foreach ($this->get_user_enrolments($user->id) as $ue) {
1048                 if (!isset($enabledplugins[$ue->enrolmentinstance->enrol])) {
1049                     $details['enrolments'][$ue->id] = array(
1050                         'text' => $ue->enrolmentinstancename,
1051                         'period' => null,
1052                         'dimmed' =>  true,
1053                         'actions' => array()
1054                     );
1055                     continue;
1056                 } else if ($ue->timestart and $ue->timeend) {
1057                     $period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend)));
1058                     $periodoutside = ($ue->timestart && $ue->timeend && ($now < $ue->timestart || $now > $ue->timeend));
1059                 } else if ($ue->timestart) {
1060                     $period = get_string('periodstart', 'enrol', userdate($ue->timestart));
1061                     $periodoutside = ($ue->timestart && $now < $ue->timestart);
1062                 } else if ($ue->timeend) {
1063                     $period = get_string('periodend', 'enrol', userdate($ue->timeend));
1064                     $periodoutside = ($ue->timeend && $now > $ue->timeend);
1065                 } else {
1066                     // If there is no start or end show when user was enrolled.
1067                     $period = get_string('periodnone', 'enrol', userdate($ue->timecreated));
1068                     $periodoutside = false;
1069                 }
1070                 $details['enrolments'][$ue->id] = array(
1071                     'text' => $ue->enrolmentinstancename,
1072                     'period' => $period,
1073                     'dimmed' =>  ($periodoutside or $ue->status != ENROL_USER_ACTIVE or $ue->enrolmentinstance->status != ENROL_INSTANCE_ENABLED),
1074                     'actions' => $ue->enrolmentplugin->get_user_enrolment_actions($manager, $ue)
1075                 );
1076             }
1077             $userdetails[$user->id] = $details;
1078         }
1079         return $userdetails;
1080     }
1082     /**
1083      * Prepare a user record for display
1084      *
1085      * This function is called by both {@link get_users_for_display} and {@link get_other_users_for_display} to correctly
1086      * prepare user fields for display
1087      *
1088      * Please note that this function does not check capability for moodle/coures:viewhiddenuserfields
1089      *
1090      * @param object $user The user record
1091      * @param array $extrafields The list of fields as returned from get_extra_user_fields used to determine which
1092      * additional fields may be displayed
1093      * @param int $now The time used for lastaccess calculation
1094      * @return array The fields to be displayed including userid, courseid, picture, firstname, lastseen and any
1095      * additional fields from $extrafields
1096      */
1097     private function prepare_user_for_display($user, $extrafields, $now) {
1098         $details = array(
1099             'userid'           => $user->id,
1100             'courseid'         => $this->get_course()->id,
1101             'picture'          => new user_picture($user),
1102             'firstname'        => fullname($user, has_capability('moodle/site:viewfullnames', $this->get_context())),
1103             'lastseen'         => get_string('never'),
1104             'lastcourseaccess' => get_string('never'),
1105         );
1106         foreach ($extrafields as $field) {
1107             $details[$field] = $user->{$field};
1108         }
1110         // Last time user has accessed the site.
1111         if ($user->lastaccess) {
1112             $details['lastseen'] = format_time($now - $user->lastaccess);
1113         }
1115         // Last time user has accessed the course.
1116         if ($user->lastseen) {
1117             $details['lastcourseaccess'] = format_time($now - $user->lastseen);
1118         }
1119         return $details;
1120     }
1122     public function get_manual_enrol_buttons() {
1123         $plugins = $this->get_enrolment_plugins(true); // Skip disabled plugins.
1124         $buttons = array();
1125         foreach ($plugins as $plugin) {
1126             $newbutton = $plugin->get_manual_enrol_button($this);
1127             if (is_array($newbutton)) {
1128                 $buttons += $newbutton;
1129             } else if ($newbutton instanceof enrol_user_button) {
1130                 $buttons[] = $newbutton;
1131             }
1132         }
1133         return $buttons;
1134     }
1136     public function has_instance($enrolpluginname) {
1137         // Make sure manual enrolments instance exists
1138         foreach ($this->get_enrolment_instances() as $instance) {
1139             if ($instance->enrol == $enrolpluginname) {
1140                 return true;
1141             }
1142         }
1143         return false;
1144     }
1146     /**
1147      * Returns the enrolment plugin that the course manager was being filtered to.
1148      *
1149      * If no filter was being applied then this function returns false.
1150      *
1151      * @return enrol_plugin
1152      */
1153     public function get_filtered_enrolment_plugin() {
1154         $instances = $this->get_enrolment_instances();
1155         $plugins = $this->get_enrolment_plugins(false);
1157         if (empty($this->instancefilter) || !array_key_exists($this->instancefilter, $instances)) {
1158             return false;
1159         }
1161         $instance = $instances[$this->instancefilter];
1162         return $plugins[$instance->enrol];
1163     }
1165     /**
1166      * Returns and array of users + enrolment details.
1167      *
1168      * Given an array of user id's this function returns and array of user enrolments for those users
1169      * as well as enough user information to display the users name and picture for each enrolment.
1170      *
1171      * @global moodle_database $DB
1172      * @param array $userids
1173      * @return array
1174      */
1175     public function get_users_enrolments(array $userids) {
1176         global $DB;
1178         $instances = $this->get_enrolment_instances();
1179         $plugins = $this->get_enrolment_plugins(false);
1181         if  (!empty($this->instancefilter)) {
1182             $instancesql = ' = :instanceid';
1183             $instanceparams = array('instanceid' => $this->instancefilter);
1184         } else {
1185             list($instancesql, $instanceparams) = $DB->get_in_or_equal(array_keys($instances), SQL_PARAMS_NAMED, 'instanceid0000');
1186         }
1188         $userfields = user_picture::fields('u');
1189         list($idsql, $idparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'userid0000');
1191         list($sort, $sortparams) = users_order_by_sql('u');
1193         $sql = "SELECT ue.id AS ueid, ue.status, ue.enrolid, ue.userid, ue.timestart, ue.timeend, ue.modifierid, ue.timecreated, ue.timemodified, $userfields
1194                   FROM {user_enrolments} ue
1195              LEFT JOIN {user} u ON u.id = ue.userid
1196                  WHERE ue.enrolid $instancesql AND
1197                        u.id $idsql
1198               ORDER BY $sort";
1200         $rs = $DB->get_recordset_sql($sql, $idparams + $instanceparams + $sortparams);
1201         $users = array();
1202         foreach ($rs as $ue) {
1203             $user = user_picture::unalias($ue);
1204             $ue->id = $ue->ueid;
1205             unset($ue->ueid);
1206             if (!array_key_exists($user->id, $users)) {
1207                 $user->enrolments = array();
1208                 $users[$user->id] = $user;
1209             }
1210             $ue->enrolmentinstance = $instances[$ue->enrolid];
1211             $ue->enrolmentplugin = $plugins[$ue->enrolmentinstance->enrol];
1212             $users[$user->id]->enrolments[$ue->id] = $ue;
1213         }
1214         $rs->close();
1215         return $users;
1216     }
1219 /**
1220  * A button that is used to enrol users in a course
1221  *
1222  * @copyright 2010 Sam Hemelryk
1223  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1224  */
1225 class enrol_user_button extends single_button {
1227     /**
1228      * An array containing JS YUI modules required by this button
1229      * @var array
1230      */
1231     protected $jsyuimodules = array();
1233     /**
1234      * An array containing JS initialisation calls required by this button
1235      * @var array
1236      */
1237     protected $jsinitcalls = array();
1239     /**
1240      * An array strings required by JS for this button
1241      * @var array
1242      */
1243     protected $jsstrings = array();
1245     /**
1246      * Initialises the new enrol_user_button
1247      *
1248      * @staticvar int $count The number of enrol user buttons already created
1249      * @param moodle_url $url
1250      * @param string $label The text to display in the button
1251      * @param string $method Either post or get
1252      */
1253     public function __construct(moodle_url $url, $label, $method = 'post') {
1254         static $count = 0;
1255         $count ++;
1256         parent::__construct($url, $label, $method);
1257         $this->class = 'singlebutton enrolusersbutton';
1258         $this->formid = 'enrolusersbutton-'.$count;
1259     }
1261     /**
1262      * Adds a YUI module call that will be added to the page when the button is used.
1263      *
1264      * @param string|array $modules One or more modules to require
1265      * @param string $function The JS function to call
1266      * @param array $arguments An array of arguments to pass to the function
1267      * @param string $galleryversion Deprecated: The gallery version to use
1268      * @param bool $ondomready If true the call is postponed until the DOM is finished loading
1269      */
1270     public function require_yui_module($modules, $function, array $arguments = null, $galleryversion = null, $ondomready = false) {
1271         if ($galleryversion != null) {
1272             debugging('The galleryversion parameter to yui_module has been deprecated since Moodle 2.3.', DEBUG_DEVELOPER);
1273         }
1275         $js = new stdClass;
1276         $js->modules = (array)$modules;
1277         $js->function = $function;
1278         $js->arguments = $arguments;
1279         $js->ondomready = $ondomready;
1280         $this->jsyuimodules[] = $js;
1281     }
1283     /**
1284      * Adds a JS initialisation call to the page when the button is used.
1285      *
1286      * @param string $function The function to call
1287      * @param array $extraarguments An array of arguments to pass to the function
1288      * @param bool $ondomready If true the call is postponed until the DOM is finished loading
1289      * @param array $module A module definition
1290      */
1291     public function require_js_init_call($function, array $extraarguments = null, $ondomready = false, array $module = null) {
1292         $js = new stdClass;
1293         $js->function = $function;
1294         $js->extraarguments = $extraarguments;
1295         $js->ondomready = $ondomready;
1296         $js->module = $module;
1297         $this->jsinitcalls[] = $js;
1298     }
1300     /**
1301      * Requires strings for JS that will be loaded when the button is used.
1302      *
1303      * @param type $identifiers
1304      * @param string $component
1305      * @param mixed $a
1306      */
1307     public function strings_for_js($identifiers, $component = 'moodle', $a = null) {
1308         $string = new stdClass;
1309         $string->identifiers = (array)$identifiers;
1310         $string->component = $component;
1311         $string->a = $a;
1312         $this->jsstrings[] = $string;
1313     }
1315     /**
1316      * Initialises the JS that is required by this button
1317      *
1318      * @param moodle_page $page
1319      */
1320     public function initialise_js(moodle_page $page) {
1321         foreach ($this->jsyuimodules as $js) {
1322             $page->requires->yui_module($js->modules, $js->function, $js->arguments, null, $js->ondomready);
1323         }
1324         foreach ($this->jsinitcalls as $js) {
1325             $page->requires->js_init_call($js->function, $js->extraarguments, $js->ondomready, $js->module);
1326         }
1327         foreach ($this->jsstrings as $string) {
1328             $page->requires->strings_for_js($string->identifiers, $string->component, $string->a);
1329         }
1330     }
1333 /**
1334  * User enrolment action
1335  *
1336  * This class is used to manage a renderable ue action such as editing an user enrolment or deleting
1337  * a user enrolment.
1338  *
1339  * @copyright  2011 Sam Hemelryk
1340  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1341  */
1342 class user_enrolment_action implements renderable {
1344     /**
1345      * The icon to display for the action
1346      * @var pix_icon
1347      */
1348     protected $icon;
1350     /**
1351      * The title for the action
1352      * @var string
1353      */
1354     protected $title;
1356     /**
1357      * The URL to the action
1358      * @var moodle_url
1359      */
1360     protected $url;
1362     /**
1363      * An array of HTML attributes
1364      * @var array
1365      */
1366     protected $attributes = array();
1368     /**
1369      * Constructor
1370      * @param pix_icon $icon
1371      * @param string $title
1372      * @param moodle_url $url
1373      * @param array $attributes
1374      */
1375     public function __construct(pix_icon $icon, $title, $url, array $attributes = null) {
1376         $this->icon = $icon;
1377         $this->title = $title;
1378         $this->url = new moodle_url($url);
1379         if (!empty($attributes)) {
1380             $this->attributes = $attributes;
1381         }
1382         $this->attributes['title'] = $title;
1383     }
1385     /**
1386      * Returns the icon for this action
1387      * @return pix_icon
1388      */
1389     public function get_icon() {
1390         return $this->icon;
1391     }
1393     /**
1394      * Returns the title for this action
1395      * @return string
1396      */
1397     public function get_title() {
1398         return $this->title;
1399     }
1401     /**
1402      * Returns the URL for this action
1403      * @return moodle_url
1404      */
1405     public function get_url() {
1406         return $this->url;
1407     }
1409     /**
1410      * Returns the attributes to use for this action
1411      * @return array
1412      */
1413     public function get_attributes() {
1414         return $this->attributes;
1415     }
1418 class enrol_ajax_exception extends moodle_exception {
1419     /**
1420      * Constructor
1421      * @param string $errorcode The name of the string from error.php to print
1422      * @param string $module name of module
1423      * @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.
1424      * @param object $a Extra words and phrases that might be required in the error string
1425      * @param string $debuginfo optional debugging information
1426      */
1427     public function __construct($errorcode, $link = '', $a = NULL, $debuginfo = null) {
1428         parent::__construct($errorcode, 'enrol', $link, $a, $debuginfo);
1429     }
1432 /**
1433  * This class is used to manage a bulk operations for enrolment plugins.
1434  *
1435  * @copyright 2011 Sam Hemelryk
1436  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1437  */
1438 abstract class enrol_bulk_enrolment_operation {
1440     /**
1441      * The course enrolment manager
1442      * @var course_enrolment_manager
1443      */
1444     protected $manager;
1446     /**
1447      * The enrolment plugin to which this operation belongs
1448      * @var enrol_plugin
1449      */
1450     protected $plugin;
1452     /**
1453      * Contructor
1454      * @param course_enrolment_manager $manager
1455      * @param stdClass $plugin
1456      */
1457     public function __construct(course_enrolment_manager $manager, enrol_plugin $plugin = null) {
1458         $this->manager = $manager;
1459         $this->plugin = $plugin;
1460     }
1462     /**
1463      * Returns a moodleform used for this operation, or false if no form is required and the action
1464      * should be immediatly processed.
1465      *
1466      * @param moodle_url|string $defaultaction
1467      * @param mixed $defaultcustomdata
1468      * @return enrol_bulk_enrolment_change_form|moodleform|false
1469      */
1470     public function get_form($defaultaction = null, $defaultcustomdata = null) {
1471         return false;
1472     }
1474     /**
1475      * Returns the title to use for this bulk operation
1476      *
1477      * @return string
1478      */
1479     abstract public function get_title();
1481     /**
1482      * Returns the identifier for this bulk operation.
1483      * This should be the same identifier used by the plugins function when returning
1484      * all of its bulk operations.
1485      *
1486      * @return string
1487      */
1488     abstract public function get_identifier();
1490     /**
1491      * Processes the bulk operation on the given users
1492      *
1493      * @param course_enrolment_manager $manager
1494      * @param array $users
1495      * @param stdClass $properties
1496      */
1497     abstract public function process(course_enrolment_manager $manager, array $users, stdClass $properties);