86ef59f8a98f7a8f11d3c85cc856807ada3472e5
[moodle.git] / lib / enrollib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This library includes the basic parts of enrol api.
20  * It is available on each page.
21  *
22  * @package    core
23  * @subpackage enrol
24  * @copyright  2010 Petr Skoda {@link http://skodak.org}
25  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
28 defined('MOODLE_INTERNAL') || die();
30 /** Course enrol instance enabled. (used in enrol->status) */
31 define('ENROL_INSTANCE_ENABLED', 0);
33 /** Course enrol instance disabled, user may enter course if other enrol instance enabled. (used in enrol->status)*/
34 define('ENROL_INSTANCE_DISABLED', 1);
36 /** User is active participant (used in user_enrolments->status)*/
37 define('ENROL_USER_ACTIVE', 0);
39 /** User participation in course is suspended (used in user_enrolments->status) */
40 define('ENROL_USER_SUSPENDED', 1);
42 /** Enrol info is cached for this number of seconds in require_login() */
43 define('ENROL_REQUIRE_LOGIN_CACHE_PERIOD', 1800);
45 /** When user disappears from external source, the enrolment is completely removed */
46 define('ENROL_EXT_REMOVED_UNENROL', 0);
48 /** When user disappears from external source, the enrolment is kept as is - one way sync */
49 define('ENROL_EXT_REMOVED_KEEP', 1);
51 /** enrol plugin feature describing requested restore type */
52 define('ENROL_RESTORE_TYPE', 'enrolrestore');
53 /** User custom backup/restore class  stored in backup/moodle2/ subdirectory */
54 define('ENROL_RESTORE_CLASS', 'class');
55 /** Restore all custom fields from enrol table without any changes and all user_enrolments records */
56 define('ENROL_RESTORE_EXACT', 'exact');
57 /** Restore enrol record like ENROL_RESTORE_EXACT, but no user enrolments */
58 define('ENROL_RESTORE_NOUSERS', 'nousers');
60 /**
61  * When user disappears from external source, user enrolment is suspended, roles are kept as is.
62  * In some cases user needs a role with some capability to be visible in UI - suc has in gradebook,
63  * assignments, etc.
64  */
65 define('ENROL_EXT_REMOVED_SUSPEND', 2);
67 /**
68  * When user disappears from external source, the enrolment is suspended and roles assigned
69  * by enrol instance are removed. Please note that user may "disappear" from gradebook and other areas.
70  * */
71 define('ENROL_EXT_REMOVED_SUSPENDNOROLES', 3);
73 /**
74  * Returns instances of enrol plugins
75  * @param bool $enable return enabled only
76  * @return array of enrol plugins name=>instance
77  */
78 function enrol_get_plugins($enabled) {
79     global $CFG;
81     $result = array();
83     if ($enabled) {
84         // sorted by enabled plugin order
85         $enabled = explode(',', $CFG->enrol_plugins_enabled);
86         $plugins = array();
87         foreach ($enabled as $plugin) {
88             $plugins[$plugin] = "$CFG->dirroot/enrol/$plugin";
89         }
90     } else {
91         // sorted alphabetically
92         $plugins = get_plugin_list('enrol');
93         ksort($plugins);
94     }
96     foreach ($plugins as $plugin=>$location) {
97         if (!file_exists("$location/lib.php")) {
98             continue;
99         }
100         include_once("$location/lib.php");
101         $class = "enrol_{$plugin}_plugin";
102         if (!class_exists($class)) {
103             continue;
104         }
106         $result[$plugin] = new $class();
107     }
109     return $result;
112 /**
113  * Returns instance of enrol plugin
114  * @param  string $name name of enrol plugin ('manual', 'guest', ...)
115  * @return enrol_plugin
116  */
117 function enrol_get_plugin($name) {
118     global $CFG;
120     $name = clean_param($name, PARAM_PLUGIN);
122     if (empty($name)) {
123         // ignore malformed or missing plugin names completely
124         return null;
125     }
127     $location = "$CFG->dirroot/enrol/$name";
129     if (!file_exists("$location/lib.php")) {
130         return null;
131     }
132     include_once("$location/lib.php");
133     $class = "enrol_{$name}_plugin";
134     if (!class_exists($class)) {
135         return null;
136     }
138     return new $class();
141 /**
142  * Returns enrolment instances in given course.
143  * @param int $courseid
144  * @param bool $enabled
145  * @return array of enrol instances
146  */
147 function enrol_get_instances($courseid, $enabled) {
148     global $DB, $CFG;
150     if (!$enabled) {
151         return $DB->get_records('enrol', array('courseid'=>$courseid), 'sortorder,id');
152     }
154     $result = $DB->get_records('enrol', array('courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id');
156     $enabled = explode(',', $CFG->enrol_plugins_enabled);
157     foreach ($result as $key=>$instance) {
158         if (!in_array($instance->enrol, $enabled)) {
159             unset($result[$key]);
160             continue;
161         }
162         if (!file_exists("$CFG->dirroot/enrol/$instance->enrol/lib.php")) {
163             // broken plugin
164             unset($result[$key]);
165             continue;
166         }
167     }
169     return $result;
172 /**
173  * Checks if a given plugin is in the list of enabled enrolment plugins.
174  *
175  * @param string $enrol Enrolment plugin name
176  * @return boolean Whether the plugin is enabled
177  */
178 function enrol_is_enabled($enrol) {
179     global $CFG;
181     if (empty($CFG->enrol_plugins_enabled)) {
182         return false;
183     }
184     return in_array($enrol, explode(',', $CFG->enrol_plugins_enabled));
187 /**
188  * Check all the login enrolment information for the given user object
189  * by querying the enrolment plugins
190  *
191  * @param object $user
192  * @return void
193  */
194 function enrol_check_plugins($user) {
195     global $CFG;
197     if (empty($user->id) or isguestuser($user)) {
198         // shortcut - there is no enrolment work for guests and not-logged-in users
199         return;
200     }
202     if (is_siteadmin()) {
203         // no sync for admin user, please use admin accounts only for admin tasks like the unix root user!
204         // if plugin fails on sync admins need to be able to log in
205         return;
206     }
208     static $inprogress = array();  // To prevent this function being called more than once in an invocation
210     if (!empty($inprogress[$user->id])) {
211         return;
212     }
214     $inprogress[$user->id] = true;  // Set the flag
216     $enabled = enrol_get_plugins(true);
218     foreach($enabled as $enrol) {
219         $enrol->sync_user_enrolments($user);
220     }
222     unset($inprogress[$user->id]);  // Unset the flag
225 /**
226  * Do these two students share any course?
227  *
228  * The courses has to be visible and enrolments has to be active,
229  * timestart and timeend restrictions are ignored.
230  *
231  * @param stdClass|int $user1
232  * @param stdClass|int $user2
233  * @return bool
234  */
235 function enrol_sharing_course($user1, $user2) {
236     global $DB, $CFG;
238     $user1 = !empty($user1->id) ? $user1->id : $user1;
239     $user2 = !empty($user2->id) ? $user2->id : $user2;
241     if (empty($user1) or empty($user2)) {
242         return false;
243     }
245     if (!$plugins = explode(',', $CFG->enrol_plugins_enabled)) {
246         return false;
247     }
249     list($plugins, $params) = $DB->get_in_or_equal($plugins, SQL_PARAMS_NAMED, 'ee');
250     $params['enabled'] = ENROL_INSTANCE_ENABLED;
251     $params['active1'] = ENROL_USER_ACTIVE;
252     $params['active2'] = ENROL_USER_ACTIVE;
253     $params['user1']   = $user1;
254     $params['user2']   = $user2;
256     $sql = "SELECT DISTINCT 'x'
257               FROM {enrol} e
258               JOIN {user_enrolments} ue1 ON (ue1.enrolid = e.id AND ue1.status = :active1 AND ue1.userid = :user1)
259               JOIN {user_enrolments} ue2 ON (ue2.enrolid = e.id AND ue2.status = :active2 AND ue2.userid = :user2)
260               JOIN {course} c ON (c.id = e.courseid AND c.visible = 1)
261              WHERE e.status = :enabled AND e.enrol $plugins";
263     return $DB->record_exists_sql($sql, $params);
266 /**
267  * This function adds necessary enrol plugins UI into the course edit form.
268  *
269  * @param MoodleQuickForm $mform
270  * @param object $data course edit form data
271  * @param object $context context of existing course or parent category if course does not exist
272  * @return void
273  */
274 function enrol_course_edit_form(MoodleQuickForm $mform, $data, $context) {
275     $plugins = enrol_get_plugins(true);
276     if (!empty($data->id)) {
277         $instances = enrol_get_instances($data->id, false);
278         foreach ($instances as $instance) {
279             if (!isset($plugins[$instance->enrol])) {
280                 continue;
281             }
282             $plugin = $plugins[$instance->enrol];
283             $plugin->course_edit_form($instance, $mform, $data, $context);
284         }
285     } else {
286         foreach ($plugins as $plugin) {
287             $plugin->course_edit_form(NULL, $mform, $data, $context);
288         }
289     }
292 /**
293  * Validate course edit form data
294  *
295  * @param array $data raw form data
296  * @param object $context context of existing course or parent category if course does not exist
297  * @return array errors array
298  */
299 function enrol_course_edit_validation(array $data, $context) {
300     $errors = array();
301     $plugins = enrol_get_plugins(true);
303     if (!empty($data['id'])) {
304         $instances = enrol_get_instances($data['id'], false);
305         foreach ($instances as $instance) {
306             if (!isset($plugins[$instance->enrol])) {
307                 continue;
308             }
309             $plugin = $plugins[$instance->enrol];
310             $errors = array_merge($errors, $plugin->course_edit_validation($instance, $data, $context));
311         }
312     } else {
313         foreach ($plugins as $plugin) {
314             $errors = array_merge($errors, $plugin->course_edit_validation(NULL, $data, $context));
315         }
316     }
318     return $errors;
321 /**
322  * Update enrol instances after course edit form submission
323  * @param bool $inserted true means new course added, false course already existed
324  * @param object $course
325  * @param object $data form data
326  * @return void
327  */
328 function enrol_course_updated($inserted, $course, $data) {
329     global $DB, $CFG;
331     $plugins = enrol_get_plugins(true);
333     foreach ($plugins as $plugin) {
334         $plugin->course_updated($inserted, $course, $data);
335     }
338 /**
339  * Add navigation nodes
340  * @param navigation_node $coursenode
341  * @param object $course
342  * @return void
343  */
344 function enrol_add_course_navigation(navigation_node $coursenode, $course) {
345     global $CFG;
347     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
349     $instances = enrol_get_instances($course->id, true);
350     $plugins   = enrol_get_plugins(true);
352     // we do not want to break all course pages if there is some borked enrol plugin, right?
353     foreach ($instances as $k=>$instance) {
354         if (!isset($plugins[$instance->enrol])) {
355             unset($instances[$k]);
356         }
357     }
359     $usersnode = $coursenode->add(get_string('users'), null, navigation_node::TYPE_CONTAINER, null, 'users');
361     if ($course->id != SITEID) {
362         // list all participants - allows assigning roles, groups, etc.
363         if (has_capability('moodle/course:enrolreview', $coursecontext)) {
364             $url = new moodle_url('/enrol/users.php', array('id'=>$course->id));
365             $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'review', new pix_icon('i/users', ''));
366         }
368         // manage enrol plugin instances
369         if (has_capability('moodle/course:enrolconfig', $coursecontext) or has_capability('moodle/course:enrolreview', $coursecontext)) {
370             $url = new moodle_url('/enrol/instances.php', array('id'=>$course->id));
371         } else {
372             $url = NULL;
373         }
374         $instancesnode = $usersnode->add(get_string('enrolmentinstances', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'manageinstances');
376         // each instance decides how to configure itself or how many other nav items are exposed
377         foreach ($instances as $instance) {
378             if (!isset($plugins[$instance->enrol])) {
379                 continue;
380             }
381             $plugins[$instance->enrol]->add_course_navigation($instancesnode, $instance);
382         }
384         if (!$url) {
385             $instancesnode->trim_if_empty();
386         }
387     }
389     // Manage groups in this course or even frontpage
390     if (($course->groupmode || !$course->groupmodeforce) && has_capability('moodle/course:managegroups', $coursecontext)) {
391         $url = new moodle_url('/group/index.php', array('id'=>$course->id));
392         $usersnode->add(get_string('groups'), $url, navigation_node::TYPE_SETTING, null, 'groups', new pix_icon('i/group', ''));
393     }
395      if (has_any_capability(array( 'moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:review'), $coursecontext)) {
396         // Override roles
397         if (has_capability('moodle/role:review', $coursecontext)) {
398             $url = new moodle_url('/admin/roles/permissions.php', array('contextid'=>$coursecontext->id));
399         } else {
400             $url = NULL;
401         }
402         $permissionsnode = $usersnode->add(get_string('permissions', 'role'), $url, navigation_node::TYPE_SETTING, null, 'override');
404         // Add assign or override roles if allowed
405         if ($course->id == SITEID or (!empty($CFG->adminsassignrolesincourse) and is_siteadmin())) {
406             if (has_capability('moodle/role:assign', $coursecontext)) {
407                 $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$coursecontext->id));
408                 $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/roles', ''));
409             }
410         }
411         // Check role permissions
412         if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:assign'), $coursecontext)) {
413             $url = new moodle_url('/admin/roles/check.php', array('contextid'=>$coursecontext->id));
414             $permissionsnode->add(get_string('checkpermissions', 'role'), $url, navigation_node::TYPE_SETTING, null, 'permissions', new pix_icon('i/checkpermissions', ''));
415         }
416      }
418      // Deal somehow with users that are not enrolled but still got a role somehow
419     if ($course->id != SITEID) {
420         //TODO, create some new UI for role assignments at course level
421         if (has_capability('moodle/role:assign', $coursecontext)) {
422             $url = new moodle_url('/enrol/otherusers.php', array('id'=>$course->id));
423             $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/roles', ''));
424         }
425     }
427     // just in case nothing was actually added
428     $usersnode->trim_if_empty();
430     if ($course->id != SITEID) {
431         // Unenrol link
432         if (is_enrolled($coursecontext)) {
433             foreach ($instances as $instance) {
434                 if (!isset($plugins[$instance->enrol])) {
435                     continue;
436                 }
437                 $plugin = $plugins[$instance->enrol];
438                 if ($unenrollink = $plugin->get_unenrolself_link($instance)) {
439                     $shortname = format_string($course->shortname, true, array('context' => $coursecontext));
440                     $coursenode->add(get_string('unenrolme', 'core_enrol', $shortname), $unenrollink, navigation_node::TYPE_SETTING, null, 'unenrolself', new pix_icon('i/user', ''));
441                     break;
442                     //TODO. deal with multiple unenrol links - not likely case, but still...
443                 }
444             }
445         } else {
446             if (is_viewing($coursecontext)) {
447                 // better not show any enrol link, this is intended for managers and inspectors
448             } else {
449                 foreach ($instances as $instance) {
450                     if (!isset($plugins[$instance->enrol])) {
451                         continue;
452                     }
453                     $plugin = $plugins[$instance->enrol];
454                     if ($plugin->show_enrolme_link($instance)) {
455                         $url = new moodle_url('/enrol/index.php', array('id'=>$course->id));
456                         $shortname = format_string($course->shortname, true, array('context' => $coursecontext));
457                         $coursenode->add(get_string('enrolme', 'core_enrol', $shortname), $url, navigation_node::TYPE_SETTING, null, 'enrolself', new pix_icon('i/user', ''));
458                         break;
459                     }
460                 }
461             }
462         }
463     }
466 /**
467  * Returns list of courses current $USER is enrolled in and can access
468  *
469  * - $fields is an array of field names to ADD
470  *   so name the fields you really need, which will
471  *   be added and uniq'd
472  *
473  * @param string|array $fields
474  * @param string $sort
475  * @param int $limit max number of courses
476  * @return array
477  */
478 function enrol_get_my_courses($fields = NULL, $sort = 'visible DESC,sortorder ASC', $limit = 0) {
479     global $DB, $USER;
481     // Guest account does not have any courses
482     if (isguestuser() or !isloggedin()) {
483         return(array());
484     }
486     $basefields = array('id', 'category', 'sortorder',
487                         'shortname', 'fullname', 'idnumber',
488                         'startdate', 'visible',
489                         'groupmode', 'groupmodeforce');
491     if (empty($fields)) {
492         $fields = $basefields;
493     } else if (is_string($fields)) {
494         // turn the fields from a string to an array
495         $fields = explode(',', $fields);
496         $fields = array_map('trim', $fields);
497         $fields = array_unique(array_merge($basefields, $fields));
498     } else if (is_array($fields)) {
499         $fields = array_unique(array_merge($basefields, $fields));
500     } else {
501         throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()');
502     }
503     if (in_array('*', $fields)) {
504         $fields = array('*');
505     }
507     $orderby = "";
508     $sort    = trim($sort);
509     if (!empty($sort)) {
510         $rawsorts = explode(',', $sort);
511         $sorts = array();
512         foreach ($rawsorts as $rawsort) {
513             $rawsort = trim($rawsort);
514             if (strpos($rawsort, 'c.') === 0) {
515                 $rawsort = substr($rawsort, 2);
516             }
517             $sorts[] = trim($rawsort);
518         }
519         $sort = 'c.'.implode(',c.', $sorts);
520         $orderby = "ORDER BY $sort";
521     }
523     $wheres = array("c.id <> :siteid");
524     $params = array('siteid'=>SITEID);
526     if (isset($USER->loginascontext) and $USER->loginascontext->contextlevel == CONTEXT_COURSE) {
527         // list _only_ this course - anything else is asking for trouble...
528         $wheres[] = "courseid = :loginas";
529         $params['loginas'] = $USER->loginascontext->instanceid;
530     }
532     $coursefields = 'c.' .join(',c.', $fields);
533     list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
534     $wheres = implode(" AND ", $wheres);
536     //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there
537     $sql = "SELECT $coursefields $ccselect
538               FROM {course} c
539               JOIN (SELECT DISTINCT e.courseid
540                       FROM {enrol} e
541                       JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)
542                      WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)
543                    ) en ON (en.courseid = c.id)
544            $ccjoin
545              WHERE $wheres
546           $orderby";
547     $params['userid']  = $USER->id;
548     $params['active']  = ENROL_USER_ACTIVE;
549     $params['enabled'] = ENROL_INSTANCE_ENABLED;
550     $params['now1']    = round(time(), -2); // improves db caching
551     $params['now2']    = $params['now1'];
553     $courses = $DB->get_records_sql($sql, $params, 0, $limit);
555     // preload contexts and check visibility
556     foreach ($courses as $id=>$course) {
557         context_instance_preload($course);
558         if (!$course->visible) {
559             if (!$context = get_context_instance(CONTEXT_COURSE, $id)) {
560                 unset($courses[$id]);
561                 continue;
562             }
563             if (!has_capability('moodle/course:viewhiddencourses', $context)) {
564                 unset($courses[$id]);
565                 continue;
566             }
567         }
568         $courses[$id] = $course;
569     }
571     //wow! Is that really all? :-D
573     return $courses;
576 /**
577  * Returns course enrolment information icons.
578  *
579  * @param object $course
580  * @param array $instances enrol instances of this course, improves performance
581  * @return array of pix_icon
582  */
583 function enrol_get_course_info_icons($course, array $instances = NULL) {
584     $icons = array();
585     if (is_null($instances)) {
586         $instances = enrol_get_instances($course->id, true);
587     }
588     $plugins = enrol_get_plugins(true);
589     foreach ($plugins as $name => $plugin) {
590         $pis = array();
591         foreach ($instances as $instance) {
592             if ($instance->status != ENROL_INSTANCE_ENABLED or $instance->courseid != $course->id) {
593                 debugging('Invalid instances parameter submitted in enrol_get_info_icons()');
594                 continue;
595             }
596             if ($instance->enrol == $name) {
597                 $pis[$instance->id] = $instance;
598             }
599         }
600         if ($pis) {
601             $icons = array_merge($icons, $plugin->get_info_icons($pis));
602         }
603     }
604     return $icons;
607 /**
608  * Returns course enrolment detailed information.
609  *
610  * @param object $course
611  * @return array of html fragments - can be used to construct lists
612  */
613 function enrol_get_course_description_texts($course) {
614     $lines = array();
615     $instances = enrol_get_instances($course->id, true);
616     $plugins = enrol_get_plugins(true);
617     foreach ($instances as $instance) {
618         if (!isset($plugins[$instance->enrol])) {
619             //weird
620             continue;
621         }
622         $plugin = $plugins[$instance->enrol];
623         $text = $plugin->get_description_text($instance);
624         if ($text !== NULL) {
625             $lines[] = $text;
626         }
627     }
628     return $lines;
631 /**
632  * Returns list of courses user is enrolled into.
633  *
634  * - $fields is an array of fieldnames to ADD
635  *   so name the fields you really need, which will
636  *   be added and uniq'd
637  *
638  * @param int $userid
639  * @param bool $onlyactive return only active enrolments in courses user may see
640  * @param string|array $fields
641  * @param string $sort
642  * @return array
643  */
644 function enrol_get_users_courses($userid, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') {
645     global $DB;
647     // Guest account does not have any courses
648     if (isguestuser($userid) or empty($userid)) {
649         return(array());
650     }
652     $basefields = array('id', 'category', 'sortorder',
653                         'shortname', 'fullname', 'idnumber',
654                         'startdate', 'visible',
655                         'groupmode', 'groupmodeforce');
657     if (empty($fields)) {
658         $fields = $basefields;
659     } else if (is_string($fields)) {
660         // turn the fields from a string to an array
661         $fields = explode(',', $fields);
662         $fields = array_map('trim', $fields);
663         $fields = array_unique(array_merge($basefields, $fields));
664     } else if (is_array($fields)) {
665         $fields = array_unique(array_merge($basefields, $fields));
666     } else {
667         throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()');
668     }
669     if (in_array('*', $fields)) {
670         $fields = array('*');
671     }
673     $orderby = "";
674     $sort    = trim($sort);
675     if (!empty($sort)) {
676         $rawsorts = explode(',', $sort);
677         $sorts = array();
678         foreach ($rawsorts as $rawsort) {
679             $rawsort = trim($rawsort);
680             if (strpos($rawsort, 'c.') === 0) {
681                 $rawsort = substr($rawsort, 2);
682             }
683             $sorts[] = trim($rawsort);
684         }
685         $sort = 'c.'.implode(',c.', $sorts);
686         $orderby = "ORDER BY $sort";
687     }
689     $params = array('siteid'=>SITEID);
691     if ($onlyactive) {
692         $subwhere = "WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)";
693         $params['now1']    = round(time(), -2); // improves db caching
694         $params['now2']    = $params['now1'];
695         $params['active']  = ENROL_USER_ACTIVE;
696         $params['enabled'] = ENROL_INSTANCE_ENABLED;
697     } else {
698         $subwhere = "";
699     }
701     $coursefields = 'c.' .join(',c.', $fields);
702     list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
704     //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there
705     $sql = "SELECT $coursefields $ccselect
706               FROM {course} c
707               JOIN (SELECT DISTINCT e.courseid
708                       FROM {enrol} e
709                       JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)
710                  $subwhere
711                    ) en ON (en.courseid = c.id)
712            $ccjoin
713              WHERE c.id <> :siteid
714           $orderby";
715     $params['userid']  = $userid;
717     $courses = $DB->get_records_sql($sql, $params);
719     // preload contexts and check visibility
720     foreach ($courses as $id=>$course) {
721         context_instance_preload($course);
722         if ($onlyactive) {
723             if (!$course->visible) {
724                 if (!$context = get_context_instance(CONTEXT_COURSE, $id)) {
725                     unset($courses[$id]);
726                     continue;
727                 }
728                 if (!has_capability('moodle/course:viewhiddencourses', $context, $userid)) {
729                     unset($courses[$id]);
730                     continue;
731                 }
732             }
733         }
734         $courses[$id] = $course;
735     }
737     //wow! Is that really all? :-D
739     return $courses;
743 /**
744  * Called when user is about to be deleted.
745  * @param object $user
746  * @return void
747  */
748 function enrol_user_delete($user) {
749     global $DB;
751     $plugins = enrol_get_plugins(true);
752     foreach ($plugins as $plugin) {
753         $plugin->user_delete($user);
754     }
756     // force cleanup of all broken enrolments
757     $DB->delete_records('user_enrolments', array('userid'=>$user->id));
760 /**
761  * Called when course is about to be deleted.
762  * @param stdClass $object
763  * @return void
764  */
765 function enrol_course_delete($course) {
766     global $DB;
768     $instances = enrol_get_instances($course->id, false);
769     $plugins = enrol_get_plugins(true);
770     foreach ($instances as $instance) {
771         if (isset($plugins[$instance->enrol])) {
772             $plugins[$instance->enrol]->delete_instance($instance);
773         }
774         // low level delete in case plugin did not do it
775         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
776         $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>'enrol_'.$instance->enrol));
777         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
778         $DB->delete_records('enrol', array('id'=>$instance->id));
779     }
782 /**
783  * Try to enrol user via default internal auth plugin.
784  *
785  * For now this is always using the manual enrol plugin...
786  *
787  * @param $courseid
788  * @param $userid
789  * @param $roleid
790  * @param $timestart
791  * @param $timeend
792  * @return bool success
793  */
794 function enrol_try_internal_enrol($courseid, $userid, $roleid = null, $timestart = 0, $timeend = 0) {
795     global $DB;
797     //note: this is hardcoded to manual plugin for now
799     if (!enrol_is_enabled('manual')) {
800         return false;
801     }
803     if (!$enrol = enrol_get_plugin('manual')) {
804         return false;
805     }
806     if (!$instances = $DB->get_records('enrol', array('enrol'=>'manual', 'courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id ASC')) {
807         return false;
808     }
809     $instance = reset($instances);
811     $enrol->enrol_user($instance, $userid, $roleid, $timestart, $timeend);
813     return true;
816 /**
817  * Is there a chance users might self enrol
818  * @param int $courseid
819  * @return bool
820  */
821 function enrol_selfenrol_available($courseid) {
822     $result = false;
824     $plugins = enrol_get_plugins(true);
825     $enrolinstances = enrol_get_instances($courseid, true);
826     foreach($enrolinstances as $instance) {
827         if (!isset($plugins[$instance->enrol])) {
828             continue;
829         }
830         if ($instance->enrol === 'guest') {
831             // blacklist known temporary guest plugins
832             continue;
833         }
834         if ($plugins[$instance->enrol]->show_enrolme_link($instance)) {
835             $result = true;
836             break;
837         }
838     }
840     return $result;
843 /**
844  * All enrol plugins should be based on this class,
845  * this is also the main source of documentation.
846  */
847 abstract class enrol_plugin {
848     protected $config = null;
850     /**
851      * Returns name of this enrol plugin
852      * @return string
853      */
854     public function get_name() {
855         // second word in class is always enrol name, sorry, no fancy plugin names with _
856         $words = explode('_', get_class($this));
857         return $words[1];
858     }
860     /**
861      * Returns localised name of enrol instance
862      *
863      * @param object $instance (null is accepted too)
864      * @return string
865      */
866     public function get_instance_name($instance) {
867         if (empty($instance->name)) {
868             $enrol = $this->get_name();
869             return get_string('pluginname', 'enrol_'.$enrol);
870         } else {
871             $context = get_context_instance(CONTEXT_COURSE, $instance->courseid);
872             return format_string($instance->name, true, array('context'=>$context));
873         }
874     }
876     /**
877      * Returns optional enrolment information icons.
878      *
879      * This is used in course list for quick overview of enrolment options.
880      *
881      * We are not using single instance parameter because sometimes
882      * we might want to prevent icon repetition when multiple instances
883      * of one type exist. One instance may also produce several icons.
884      *
885      * @param array $instances all enrol instances of this type in one course
886      * @return array of pix_icon
887      */
888     public function get_info_icons(array $instances) {
889         return array();
890     }
892     /**
893      * Returns optional enrolment instance description text.
894      *
895      * This is used in detailed course information.
896      *
897      *
898      * @param object $instance
899      * @return string short html text
900      */
901     public function get_description_text($instance) {
902         return null;
903     }
905     /**
906      * Makes sure config is loaded and cached.
907      * @return void
908      */
909     protected function load_config() {
910         if (!isset($this->config)) {
911             $name = $this->get_name();
912             if (!$config = get_config("enrol_$name")) {
913                 $config = new stdClass();
914             }
915             $this->config = $config;
916         }
917     }
919     /**
920      * Returns plugin config value
921      * @param  string $name
922      * @param  string $default value if config does not exist yet
923      * @return string value or default
924      */
925     public function get_config($name, $default = NULL) {
926         $this->load_config();
927         return isset($this->config->$name) ? $this->config->$name : $default;
928     }
930     /**
931      * Sets plugin config value
932      * @param  string $name name of config
933      * @param  string $value string config value, null means delete
934      * @return string value
935      */
936     public function set_config($name, $value) {
937         $pluginname = $this->get_name();
938         $this->load_config();
939         if ($value === NULL) {
940             unset($this->config->$name);
941         } else {
942             $this->config->$name = $value;
943         }
944         set_config($name, $value, "enrol_$pluginname");
945     }
947     /**
948      * Does this plugin assign protected roles are can they be manually removed?
949      * @return bool - false means anybody may tweak roles, it does not use itemid and component when assigning roles
950      */
951     public function roles_protected() {
952         return true;
953     }
955     /**
956      * Does this plugin allow manual enrolments?
957      *
958      * @param stdClass $instance course enrol instance
959      * All plugins allowing this must implement 'enrol/xxx:enrol' capability
960      *
961      * @return bool - true means user with 'enrol/xxx:enrol' may enrol others freely, trues means nobody may add more enrolments manually
962      */
963     public function allow_enrol(stdClass $instance) {
964         return false;
965     }
967     /**
968      * Does this plugin allow manual unenrolments?
969      *
970      * @param stdClass $instance course enrol instance
971      * All plugins allowing this must implement 'enrol/xxx:unenrol' capability
972      *
973      * @return bool - true means user with 'enrol/xxx:unenrol' may unenrol others freely, trues means nobody may touch user_enrolments
974      */
975     public function allow_unenrol(stdClass $instance) {
976         return false;
977     }
979     /**
980      * Does this plugin allow manual changes in user_enrolments table?
981      *
982      * All plugins allowing this must implement 'enrol/xxx:manage' capability
983      *
984      * @param stdClass $instance course enrol instance
985      * @return bool - true means it is possible to change enrol period and status in user_enrolments table
986      */
987     public function allow_manage(stdClass $instance) {
988         return false;
989     }
991     /**
992      * Does this plugin support some way to user to self enrol?
993      *
994      * @param stdClass $instance course enrol instance
995      *
996      * @return bool - true means show "Enrol me in this course" link in course UI
997      */
998     public function show_enrolme_link(stdClass $instance) {
999         return false;
1000     }
1002     /**
1003      * Attempt to automatically enrol current user in course without any interaction,
1004      * calling code has to make sure the plugin and instance are active.
1005      *
1006      * This should return either a timestamp in the future or false.
1007      *
1008      * @param stdClass $instance course enrol instance
1009      * @param stdClass $user record
1010      * @return bool|int false means not enrolled, integer means timeend
1011      */
1012     public function try_autoenrol(stdClass $instance) {
1013         global $USER;
1015         return false;
1016     }
1018     /**
1019      * Attempt to automatically gain temporary guest access to course,
1020      * calling code has to make sure the plugin and instance are active.
1021      *
1022      * This should return either a timestamp in the future or false.
1023      *
1024      * @param stdClass $instance course enrol instance
1025      * @param stdClass $user record
1026      * @return bool|int false means no guest access, integer means timeend
1027      */
1028     public function try_guestaccess(stdClass $instance) {
1029         global $USER;
1031         return false;
1032     }
1034     /**
1035      * Enrol user into course via enrol instance.
1036      *
1037      * @param stdClass $instance
1038      * @param int $userid
1039      * @param int $roleid optional role id
1040      * @param int $timestart 0 means unknown
1041      * @param int $timeend 0 means forever
1042      * @param int $status default to ENROL_USER_ACTIVE for new enrolments, no change by default in updates
1043      * @return void
1044      */
1045     public function enrol_user(stdClass $instance, $userid, $roleid = NULL, $timestart = 0, $timeend = 0, $status = NULL) {
1046         global $DB, $USER, $CFG; // CFG necessary!!!
1048         if ($instance->courseid == SITEID) {
1049             throw new coding_exception('invalid attempt to enrol into frontpage course!');
1050         }
1052         $name = $this->get_name();
1053         $courseid = $instance->courseid;
1055         if ($instance->enrol !== $name) {
1056             throw new coding_exception('invalid enrol instance!');
1057         }
1058         $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST);
1060         $inserted = false;
1061         if ($ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
1062             //only update if timestart or timeend or status are different.
1063             if ($ue->timestart != $timestart or $ue->timeend != $timeend or (!is_null($status) and $ue->status != $status)) {
1064                 $ue->timestart    = $timestart;
1065                 $ue->timeend      = $timeend;
1066                 if (!is_null($status)) {
1067                     $ue->status   = $status;
1068                 }
1069                 $ue->modifierid   = $USER->id;
1070                 $ue->timemodified = time();
1071                 $DB->update_record('user_enrolments', $ue);
1072             }
1073         } else {
1074             $ue = new stdClass();
1075             $ue->enrolid      = $instance->id;
1076             $ue->status       = is_null($status) ? ENROL_USER_ACTIVE : $status;
1077             $ue->userid       = $userid;
1078             $ue->timestart    = $timestart;
1079             $ue->timeend      = $timeend;
1080             $ue->modifierid   = $USER->id;
1081             $ue->timecreated  = time();
1082             $ue->timemodified = $ue->timecreated;
1083             $ue->id = $DB->insert_record('user_enrolments', $ue);
1085             $inserted = true;
1086         }
1088         if ($roleid) {
1089             if ($this->roles_protected()) {
1090                 role_assign($roleid, $userid, $context->id, 'enrol_'.$name, $instance->id);
1091             } else {
1092                 role_assign($roleid, $userid, $context->id);
1093             }
1094         }
1096         if ($inserted) {
1097             // add extra info and trigger event
1098             $ue->courseid  = $courseid;
1099             $ue->enrol     = $name;
1100             events_trigger('user_enrolled', $ue);
1101         }
1103         // reset primitive require_login() caching
1104         if ($userid == $USER->id) {
1105             if (isset($USER->enrol['enrolled'][$courseid])) {
1106                 unset($USER->enrol['enrolled'][$courseid]);
1107             }
1108             if (isset($USER->enrol['tempguest'][$courseid])) {
1109                 unset($USER->enrol['tempguest'][$courseid]);
1110                 $USER->access = remove_temp_roles($context, $USER->access);
1111             }
1112         }
1113     }
1115     /**
1116      * Store user_enrolments changes and trigger event.
1117      *
1118      * @param object $ue
1119      * @param int $user id
1120      * @param int $status
1121      * @param int $timestart
1122      * @param int $timeend
1123      * @return void
1124      */
1125     public function update_user_enrol(stdClass $instance, $userid, $status = NULL, $timestart = NULL, $timeend = NULL) {
1126         global $DB, $USER;
1128         $name = $this->get_name();
1130         if ($instance->enrol !== $name) {
1131             throw new coding_exception('invalid enrol instance!');
1132         }
1134         if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
1135             // weird, user not enrolled
1136             return;
1137         }
1139         $modified = false;
1140         if (isset($status) and $ue->status != $status) {
1141             $ue->status = $status;
1142             $modified = true;
1143         }
1144         if (isset($timestart) and $ue->timestart != $timestart) {
1145             $ue->timestart = $timestart;
1146             $modified = true;
1147         }
1148         if (isset($timeend) and $ue->timeend != $timeend) {
1149             $ue->timeend = $timeend;
1150             $modified = true;
1151         }
1153         if (!$modified) {
1154             // no change
1155             return;
1156         }
1158         $ue->modifierid = $USER->id;
1159         $DB->update_record('user_enrolments', $ue);
1161         // trigger event
1162         $ue->courseid  = $instance->courseid;
1163         $ue->enrol     = $instance->name;
1164         events_trigger('user_unenrol_modified', $ue);
1165     }
1167     /**
1168      * Unenrol user from course,
1169      * the last unenrolment removes all remaining roles.
1170      *
1171      * @param stdClass $instance
1172      * @param int $userid
1173      * @return void
1174      */
1175     public function unenrol_user(stdClass $instance, $userid) {
1176         global $CFG, $USER, $DB;
1178         $name = $this->get_name();
1179         $courseid = $instance->courseid;
1181         if ($instance->enrol !== $name) {
1182             throw new coding_exception('invalid enrol instance!');
1183         }
1184         $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST);
1186         if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
1187             // weird, user not enrolled
1188             return;
1189         }
1191         role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id));
1192         $DB->delete_records('user_enrolments', array('id'=>$ue->id));
1194         // add extra info and trigger event
1195         $ue->courseid  = $courseid;
1196         $ue->enrol     = $name;
1198         $sql = "SELECT 'x'
1199                   FROM {user_enrolments} ue
1200                   JOIN {enrol} e ON (e.id = ue.enrolid)
1201                   WHERE ue.userid = :userid AND e.courseid = :courseid";
1202         if ($DB->record_exists_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid))) {
1203             $ue->lastenrol = false;
1204             events_trigger('user_unenrolled', $ue);
1205             // user still has some enrolments, no big cleanup yet
1206         } else {
1207             // the big cleanup IS necessary!
1209             require_once("$CFG->dirroot/group/lib.php");
1210             require_once("$CFG->libdir/gradelib.php");
1212             // remove all remaining roles
1213             role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id), true, false);
1215             //clean up ALL invisible user data from course if this is the last enrolment - groups, grades, etc.
1216             groups_delete_group_members($courseid, $userid);
1218             grade_user_unenrol($courseid, $userid);
1220             $DB->delete_records('user_lastaccess', array('userid'=>$userid, 'courseid'=>$courseid));
1222             $ue->lastenrol = true; // means user not enrolled any more
1223             events_trigger('user_unenrolled', $ue);
1224         }
1225         // reset primitive require_login() caching
1226         if ($userid == $USER->id) {
1227             if (isset($USER->enrol['enrolled'][$courseid])) {
1228                 unset($USER->enrol['enrolled'][$courseid]);
1229             }
1230             if (isset($USER->enrol['tempguest'][$courseid])) {
1231                 unset($USER->enrol['tempguest'][$courseid]);
1232                 $USER->access = remove_temp_roles($context, $USER->access);
1233             }
1234         }
1235     }
1237     /**
1238      * Forces synchronisation of user enrolments.
1239      *
1240      * This is important especially for external enrol plugins,
1241      * this function is called for all enabled enrol plugins
1242      * right after every user login.
1243      *
1244      * @param object $user user record
1245      * @return void
1246      */
1247     public function sync_user_enrolments($user) {
1248         // override if necessary
1249     }
1251     /**
1252      * Returns link to page which may be used to add new instance of enrolment plugin in course.
1253      * @param int $courseid
1254      * @return moodle_url page url
1255      */
1256     public function get_newinstance_link($courseid) {
1257         // override for most plugins, check if instance already exists in cases only one instance is supported
1258         return NULL;
1259     }
1261     /**
1262      * Is it possible to delete enrol instance via standard UI?
1263      *
1264      * @param object $instance
1265      * @return bool
1266      */
1267     public function instance_deleteable($instance) {
1268         return true;
1269     }
1271     /**
1272      * Returns link to manual enrol UI if exists.
1273      * Does the access control tests automatically.
1274      *
1275      * @param object $instance
1276      * @return moodle_url
1277      */
1278     public function get_manual_enrol_link($instance) {
1279         return NULL;
1280     }
1282     /**
1283      * Returns list of unenrol links for all enrol instances in course.
1284      *
1285      * @param int $instance
1286      * @return moodle_url or NULL if self unenrolment not supported
1287      */
1288     public function get_unenrolself_link($instance) {
1289         global $USER, $CFG, $DB;
1291         $name = $this->get_name();
1292         if ($instance->enrol !== $name) {
1293             throw new coding_exception('invalid enrol instance!');
1294         }
1296         if ($instance->courseid == SITEID) {
1297             return NULL;
1298         }
1300         if (!enrol_is_enabled($name)) {
1301             return NULL;
1302         }
1304         if ($instance->status != ENROL_INSTANCE_ENABLED) {
1305             return NULL;
1306         }
1308         if (!file_exists("$CFG->dirroot/enrol/$name/unenrolself.php")) {
1309             return NULL;
1310         }
1312         $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST);
1314         if (!has_capability("enrol/$name:unenrolself", $context)) {
1315             return NULL;
1316         }
1318         if (!$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$USER->id, 'status'=>ENROL_USER_ACTIVE))) {
1319             return NULL;
1320         }
1322         return new moodle_url("/enrol/$name/unenrolself.php", array('enrolid'=>$instance->id));;
1323     }
1325     /**
1326      * Adds enrol instance UI to course edit form
1327      *
1328      * @param object $instance enrol instance or null if does not exist yet
1329      * @param MoodleQuickForm $mform
1330      * @param object $data
1331      * @param object $context context of existing course or parent category if course does not exist
1332      * @return void
1333      */
1334     public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) {
1335         // override - usually at least enable/disable switch, has to add own form header
1336     }
1338     /**
1339      * Validates course edit form data
1340      *
1341      * @param object $instance enrol instance or null if does not exist yet
1342      * @param array $data
1343      * @param object $context context of existing course or parent category if course does not exist
1344      * @return array errors array
1345      */
1346     public function course_edit_validation($instance, array $data, $context) {
1347         return array();
1348     }
1350     /**
1351      * Called after updating/inserting course.
1352      *
1353      * @param bool $inserted true if course just inserted
1354      * @param object $course
1355      * @param object $data form data
1356      * @return void
1357      */
1358     public function course_updated($inserted, $course, $data) {
1359         if ($inserted) {
1360             if ($this->get_config('defaultenrol')) {
1361                 $this->add_default_instance($course);
1362             }
1363         }
1364     }
1366     /**
1367      * Add new instance of enrol plugin.
1368      * @param object $course
1369      * @param array instance fields
1370      * @return int id of new instance, null if can not be created
1371      */
1372     public function add_instance($course, array $fields = NULL) {
1373         global $DB;
1375         if ($course->id == SITEID) {
1376             throw new coding_exception('Invalid request to add enrol instance to frontpage.');
1377         }
1379         $instance = new stdClass();
1380         $instance->enrol          = $this->get_name();
1381         $instance->status         = ENROL_INSTANCE_ENABLED;
1382         $instance->courseid       = $course->id;
1383         $instance->enrolstartdate = 0;
1384         $instance->enrolenddate   = 0;
1385         $instance->timemodified   = time();
1386         $instance->timecreated    = $instance->timemodified;
1387         $instance->sortorder      = $DB->get_field('enrol', 'COALESCE(MAX(sortorder), -1) + 1', array('courseid'=>$course->id));
1389         $fields = (array)$fields;
1390         unset($fields['enrol']);
1391         unset($fields['courseid']);
1392         unset($fields['sortorder']);
1393         foreach($fields as $field=>$value) {
1394             $instance->$field = $value;
1395         }
1397         return $DB->insert_record('enrol', $instance);
1398     }
1400     /**
1401      * Add new instance of enrol plugin with default settings,
1402      * called when adding new instance manually or when adding new course.
1403      *
1404      * Not all plugins support this.
1405      *
1406      * @param object $course
1407      * @return int id of new instance or null if no default supported
1408      */
1409     public function add_default_instance($course) {
1410         return null;
1411     }
1413     /**
1414      * Delete course enrol plugin instance, unenrol all users.
1415      * @param object $instance
1416      * @return void
1417      */
1418     public function delete_instance($instance) {
1419         global $DB;
1421         $name = $this->get_name();
1422         if ($instance->enrol !== $name) {
1423             throw new coding_exception('invalid enrol instance!');
1424         }
1426         //first unenrol all users
1427         $participants = $DB->get_recordset('user_enrolments', array('enrolid'=>$instance->id));
1428         foreach ($participants as $participant) {
1429             $this->unenrol_user($instance, $participant->userid);
1430         }
1431         $participants->close();
1433         // now clean up all remainders that were not removed correctly
1434         $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>$name));
1435         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
1437         // finally drop the enrol row
1438         $DB->delete_records('enrol', array('id'=>$instance->id));
1439     }
1441     /**
1442      * Creates course enrol form, checks if form submitted
1443      * and enrols user if necessary. It can also redirect.
1444      *
1445      * @param stdClass $instance
1446      * @return string html text, usually a form in a text box
1447      */
1448     public function enrol_page_hook(stdClass $instance) {
1449         return null;
1450     }
1452     /**
1453      * Adds navigation links into course admin block.
1454      *
1455      * By defaults looks for manage links only.
1456      *
1457      * @param navigation_node $instancesnode
1458      * @param object $instance
1459      * @return void
1460      */
1461     public function add_course_navigation($instancesnode, stdClass $instance) {
1462         // usually adds manage users
1463     }
1465     /**
1466      * Returns edit icons for the page with list of instances
1467      * @param stdClass $instance
1468      * @return array
1469      */
1470     public function get_action_icons(stdClass $instance) {
1471         return array();
1472     }
1474     /**
1475      * Reads version.php and determines if it is necessary
1476      * to execute the cron job now.
1477      * @return bool
1478      */
1479     public function is_cron_required() {
1480         global $CFG;
1482         $name = $this->get_name();
1483         $versionfile = "$CFG->dirroot/enrol/$name/version.php";
1484         $plugin = new stdClass();
1485         include($versionfile);
1486         if (empty($plugin->cron)) {
1487             return false;
1488         }
1489         $lastexecuted = $this->get_config('lastcron', 0);
1490         if ($lastexecuted + $plugin->cron < time()) {
1491             return true;
1492         } else {
1493             return false;
1494         }
1495     }
1497     /**
1498      * Called for all enabled enrol plugins that returned true from is_cron_required().
1499      * @return void
1500      */
1501     public function cron() {
1502     }
1504     /**
1505      * Called when user is about to be deleted
1506      * @param object $user
1507      * @return void
1508      */
1509     public function user_delete($user) {
1510         global $DB;
1512         $sql = "SELECT e.*
1513                   FROM {enrol} e
1514                   JOIN {user_enrolments} ue ON (ue.enrolid = e.id)
1515                  WHERE e.enrol = :name AND ue.userid = :userid";
1516         $params = array('name'=>$this->get_name(), 'userid'=>$user->id);
1518         $rs = $DB->get_recordset_sql($sql, $params);
1519         foreach($rs as $instance) {
1520             $this->unenrol_user($instance, $user->id);
1521         }
1522         $rs->close();
1523     }
1525     /**
1526      * Returns an enrol_user_button that takes the user to a page where they are able to
1527      * enrol users into the managers course through this plugin.
1528      *
1529      * Optional: If the plugin supports manual enrolments it can choose to override this
1530      * otherwise it shouldn't
1531      *
1532      * @param course_enrolment_manager $manager
1533      * @return enrol_user_button|false
1534      */
1535     public function get_manual_enrol_button(course_enrolment_manager $manager) {
1536         return false;
1537     }
1539     /**
1540      * Gets an array of the user enrolment actions
1541      *
1542      * @param course_enrolment_manager $manager
1543      * @param stdClass $ue
1544      * @return array An array of user_enrolment_actions
1545      */
1546     public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) {
1547         return array();
1548     }
1550     /**
1551      * Returns true if the plugin has one or more bulk operations that can be performed on
1552      * user enrolments.
1553      *
1554      * @return bool
1555      */
1556     public function has_bulk_operations() {
1557        return false;
1558     }
1560     /**
1561      * Return an array of enrol_bulk_enrolment_operation objects that define
1562      * the bulk actions that can be performed on user enrolments by the plugin.
1563      *
1564      * @return array
1565      */
1566     public function get_bulk_operations() {
1567         return array();
1568     }