Commit | Line | Data |
---|---|---|
df997f84 PS |
1 | <?php |
2 | ||
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/>. | |
17 | ||
18 | /** | |
19 | * This library includes the basic parts of enrol api. | |
20 | * It is available on each page. | |
21 | * | |
22 | * @package moodlecore | |
23 | * @copyright 2010 Petr Skoda {@link http://skodak.org} | |
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
25 | */ | |
26 | ||
27 | ||
28 | /** Course enrol instance enabled. (used in enrol->status) */ | |
29 | define('ENROL_INSTANCE_ENABLED', 0); | |
30 | ||
31 | /** Course enrol instance disabled, user may enter course if other enrol instance enabled. (used in enrol->status)*/ | |
32 | define('ENROL_INSTANCE_DISABLED', 1); | |
33 | ||
34 | /** User is active participant (used in user_enrolments->status)*/ | |
35 | define('ENROL_USER_ACTIVE', 0); | |
36 | ||
37 | /** User participation in course is suspended (used in user_enrolments->status) */ | |
38 | define('ENROL_USER_SUSPENDED', 1); | |
39 | ||
40 | /** Enrol info is cached for this number of seconds in require_login() */ | |
41 | define('ENROL_REQUIRE_LOGIN_CACHE_PERIOD', 1800); | |
42 | ||
34121765 PS |
43 | /** When user disappears from external source, the enrolment is completely removed */ |
44 | define('ENROL_EXT_REMOVED_UNENROL', 0); | |
45 | ||
46 | /** When user disappears from external source, the enrolment is kept as is - one way sync */ | |
47 | define('ENROL_EXT_REMOVED_KEEP', 1); | |
48 | ||
49 | /** | |
50 | * When user disappears from external source, user enrolment is suspended, roles are kept as is. | |
51 | * In some cases user needs a role with some capability to be visible in UI - suc has in gradebook, | |
52 | * assignments, etc. | |
53 | */ | |
54 | define('ENROL_EXT_REMOVED_SUSPEND', 2); | |
55 | ||
56 | /** | |
57 | * When user disappears from external source, the enrolment is suspended and roles assigned | |
58 | * by enrol instance are removed. Please note that user may "disappear" from gradebook and other areas. | |
59 | * */ | |
60 | define('ENROL_EXT_REMOVED_SUSPENDNOROLES', 3); | |
61 | ||
df997f84 PS |
62 | /** |
63 | * Returns instances of enrol plugins | |
64 | * @param bool $enable return enabled only | |
65 | * @return array of enrol plugins name=>instance | |
66 | */ | |
67 | function enrol_get_plugins($enabled) { | |
68 | global $CFG; | |
69 | ||
70 | $result = array(); | |
71 | ||
72 | if ($enabled) { | |
73 | // sorted by enabled plugin order | |
74 | $enabled = explode(',', $CFG->enrol_plugins_enabled); | |
75 | $plugins = array(); | |
76 | foreach ($enabled as $plugin) { | |
77 | $plugins[$plugin] = "$CFG->dirroot/enrol/$plugin"; | |
78 | } | |
79 | } else { | |
80 | // sorted alphabetically | |
81 | $plugins = get_plugin_list('enrol'); | |
82 | ksort($plugins); | |
83 | } | |
84 | ||
85 | foreach ($plugins as $plugin=>$location) { | |
86 | if (!file_exists("$location/lib.php")) { | |
87 | continue; | |
88 | } | |
89 | include_once("$location/lib.php"); | |
90 | $class = "enrol_{$plugin}_plugin"; | |
91 | if (!class_exists($class)) { | |
92 | continue; | |
93 | } | |
94 | ||
95 | $result[$plugin] = new $class(); | |
96 | } | |
97 | ||
98 | return $result; | |
99 | } | |
100 | ||
101 | /** | |
102 | * Returns instance of enrol plugin | |
103 | * @param string $name name of enrol plugin ('manual', 'guest', ...) | |
104 | * @return enrol_plugin | |
105 | */ | |
106 | function enrol_get_plugin($name) { | |
107 | global $CFG; | |
108 | ||
109 | if ($name !== clean_param($name, PARAM_SAFEDIR)) { | |
110 | // ignore malformed plugin names completely | |
111 | return null; | |
112 | } | |
113 | ||
114 | $location = "$CFG->dirroot/enrol/$name"; | |
115 | ||
116 | if (!file_exists("$location/lib.php")) { | |
117 | return null; | |
118 | } | |
119 | include_once("$location/lib.php"); | |
120 | $class = "enrol_{$name}_plugin"; | |
121 | if (!class_exists($class)) { | |
122 | return null; | |
123 | } | |
124 | ||
125 | return new $class(); | |
126 | } | |
127 | ||
128 | /** | |
129 | * Returns enrolment instances in given course. | |
130 | * @param int $courseid | |
131 | * @param bool $enabled | |
132 | * @return array of enrol instances | |
133 | */ | |
134 | function enrol_get_instances($courseid, $enabled) { | |
135 | global $DB, $CFG; | |
136 | ||
137 | if (!$enabled) { | |
138 | return $DB->get_records('enrol', array('courseid'=>$courseid), 'sortorder,id'); | |
139 | } | |
140 | ||
141 | $result = $DB->get_records('enrol', array('courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id'); | |
142 | ||
79721bd3 | 143 | $enabled = explode(',', $CFG->enrol_plugins_enabled); |
df997f84 PS |
144 | foreach ($result as $key=>$instance) { |
145 | if (!in_array($instance->enrol, $enabled)) { | |
146 | unset($result[$key]); | |
147 | continue; | |
148 | } | |
149 | if (!file_exists("$CFG->dirroot/enrol/$instance->enrol/lib.php")) { | |
150 | // broken plugin | |
151 | unset($result[$key]); | |
152 | continue; | |
153 | } | |
154 | } | |
155 | ||
156 | return $result; | |
157 | } | |
158 | ||
159 | /** | |
160 | * Checks if a given plugin is in the list of enabled enrolment plugins. | |
161 | * | |
162 | * @param string $enrol Enrolment plugin name | |
163 | * @return boolean Whether the plugin is enabled | |
164 | */ | |
165 | function enrol_is_enabled($enrol) { | |
166 | global $CFG; | |
167 | ||
168 | if (empty($CFG->enrol_plugins_enabled)) { | |
169 | return false; | |
170 | } | |
171 | return in_array($enrol, explode(',', $CFG->enrol_plugins_enabled)); | |
172 | } | |
173 | ||
174 | /** | |
175 | * Check all the login enrolment information for the given user object | |
176 | * by querying the enrolment plugins | |
177 | * | |
178 | * @param object $user | |
179 | * @return void | |
180 | */ | |
181 | function enrol_check_plugins($user) { | |
182 | global $CFG; | |
183 | ||
184 | if (empty($user->id) or isguestuser($user)) { | |
185 | // shortcut - there is no enrolment work for guests and not-logged-in users | |
186 | return; | |
187 | } | |
188 | ||
e384d2dc PS |
189 | if (is_siteadmin()) { |
190 | // no sync for admin user, please use admin accounts only for admin tasks like the unix root user! | |
191 | // if plugin fails on sync admins need to be able to log in | |
192 | return; | |
193 | } | |
194 | ||
df997f84 PS |
195 | static $inprogress = array(); // To prevent this function being called more than once in an invocation |
196 | ||
197 | if (!empty($inprogress[$user->id])) { | |
198 | return; | |
199 | } | |
200 | ||
201 | $inprogress[$user->id] = true; // Set the flag | |
202 | ||
203 | $enabled = enrol_get_plugins(true); | |
204 | ||
205 | foreach($enabled as $enrol) { | |
206 | $enrol->sync_user_enrolments($user); | |
207 | } | |
208 | ||
209 | unset($inprogress[$user->id]); // Unset the flag | |
210 | } | |
211 | ||
212 | /** | |
213 | * This function adds necessary enrol plugins UI into the course edit form. | |
214 | * | |
215 | * @param MoodleQuickForm $mform | |
216 | * @param object $data course edit form data | |
217 | * @param object $context context of existing course or parent category if course does not exist | |
218 | * @return void | |
219 | */ | |
220 | function enrol_course_edit_form(MoodleQuickForm $mform, $data, $context) { | |
221 | $plugins = enrol_get_plugins(true); | |
222 | if (!empty($data->id)) { | |
223 | $instances = enrol_get_instances($data->id, false); | |
224 | foreach ($instances as $instance) { | |
225 | if (!isset($plugins[$instance->enrol])) { | |
226 | continue; | |
227 | } | |
228 | $plugin = $plugins[$instance->enrol]; | |
229 | $plugin->course_edit_form($instance, $mform, $data, $context); | |
230 | } | |
231 | } else { | |
232 | foreach ($plugins as $plugin) { | |
233 | $plugin->course_edit_form(NULL, $mform, $data, $context); | |
234 | } | |
235 | } | |
236 | } | |
237 | ||
238 | /** | |
239 | * Validate course edit form data | |
240 | * | |
241 | * @param array $data raw form data | |
242 | * @param object $context context of existing course or parent category if course does not exist | |
243 | * @return array errors array | |
244 | */ | |
245 | function enrol_course_edit_validation(array $data, $context) { | |
246 | $errors = array(); | |
247 | $plugins = enrol_get_plugins(true); | |
248 | ||
249 | if (!empty($data['id'])) { | |
250 | $instances = enrol_get_instances($data['id'], false); | |
251 | foreach ($instances as $instance) { | |
252 | if (!isset($plugins[$instance->enrol])) { | |
253 | continue; | |
254 | } | |
255 | $plugin = $plugins[$instance->enrol]; | |
256 | $errors = array_merge($errors, $plugin->course_edit_validation($instance, $data, $context)); | |
257 | } | |
258 | } else { | |
259 | foreach ($plugins as $plugin) { | |
260 | $errors = array_merge($errors, $plugin->course_edit_validation(NULL, $data, $context)); | |
261 | } | |
262 | } | |
263 | ||
264 | return $errors; | |
265 | } | |
266 | ||
267 | /** | |
268 | * Update enrol instances after course edit form submission | |
269 | * @param bool $inserted true means new course added, false course already existed | |
270 | * @param object $course | |
271 | * @param object $data form data | |
272 | * @return void | |
273 | */ | |
274 | function enrol_course_updated($inserted, $course, $data) { | |
275 | global $DB, $CFG; | |
276 | ||
277 | $plugins = enrol_get_plugins(true); | |
278 | ||
279 | foreach ($plugins as $plugin) { | |
280 | $plugin->course_updated($inserted, $course, $data); | |
281 | } | |
282 | } | |
283 | ||
284 | /** | |
285 | * Add navigation nodes | |
286 | * @param navigation_node $coursenode | |
287 | * @param object $course | |
288 | * @return void | |
289 | */ | |
290 | function enrol_add_course_navigation(navigation_node $coursenode, $course) { | |
291 | ||
292 | $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); | |
293 | ||
294 | $instances = enrol_get_instances($course->id, true); | |
295 | $plugins = enrol_get_plugins(true); | |
296 | ||
297 | // we do not want to break all course pages if there is some borked enrol plugin, right? | |
298 | foreach ($instances as $k=>$instance) { | |
299 | if (!isset($plugins[$instance->enrol])) { | |
300 | unset($instances[$k]); | |
301 | } | |
302 | } | |
303 | ||
f5ce6b71 | 304 | $usersnode = $coursenode->add(get_string('users'), null, navigation_node::TYPE_CONTAINER, null, 'users'); |
df997f84 PS |
305 | |
306 | if ($course->id != SITEID) { | |
f5ce6b71 | 307 | // list all participants - allows assigning roles, groups, etc. |
df997f84 PS |
308 | if (has_capability('moodle/course:enrolreview', $coursecontext)) { |
309 | $url = new moodle_url('/enrol/users.php', array('id'=>$course->id)); | |
f5ce6b71 | 310 | $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'review', new pix_icon('i/users', '')); |
df997f84 PS |
311 | } |
312 | ||
313 | // manage enrol plugin instances | |
314 | if (has_capability('moodle/course:enrolconfig', $coursecontext) or has_capability('moodle/course:enrolreview', $coursecontext)) { | |
315 | $url = new moodle_url('/enrol/instances.php', array('id'=>$course->id)); | |
316 | } else { | |
317 | $url = NULL; | |
318 | } | |
f5ce6b71 | 319 | $instancesnode = $usersnode->add(get_string('enrolmentinstances', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'manageinstances'); |
df997f84 PS |
320 | |
321 | // each instance decides how to configure itself or how many other nav items are exposed | |
322 | foreach ($instances as $instance) { | |
323 | if (!isset($plugins[$instance->enrol])) { | |
324 | continue; | |
325 | } | |
326 | $plugins[$instance->enrol]->add_course_navigation($instancesnode, $instance); | |
327 | } | |
328 | ||
329 | if (!$url) { | |
330 | $instancesnode->trim_if_empty(); | |
331 | } | |
332 | } | |
333 | ||
334 | // Manage groups in this course or even frontpage | |
335 | if (($course->groupmode || !$course->groupmodeforce) && has_capability('moodle/course:managegroups', $coursecontext)) { | |
336 | $url = new moodle_url('/group/index.php', array('id'=>$course->id)); | |
337 | $usersnode->add(get_string('groups'), $url, navigation_node::TYPE_SETTING, null, 'groups', new pix_icon('i/group', '')); | |
338 | } | |
339 | ||
340 | if (has_any_capability(array( 'moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:review'), $coursecontext)) { | |
341 | // Override roles | |
342 | if (has_capability('moodle/role:review', $coursecontext)) { | |
343 | $url = new moodle_url('/admin/roles/permissions.php', array('contextid'=>$coursecontext->id)); | |
344 | } else { | |
345 | $url = NULL; | |
346 | } | |
f5ce6b71 | 347 | $permissionsnode = $usersnode->add(get_string('permissions', 'role'), $url, navigation_node::TYPE_SETTING, null, 'override'); |
df997f84 PS |
348 | |
349 | // Add assign or override roles if allowed | |
350 | if ($course->id == SITEID or (!empty($CFG->adminsassignrolesincourse) and is_siteadmin())) { | |
351 | if (has_capability('moodle/role:assign', $coursecontext)) { | |
352 | $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$coursecontext->id)); | |
f5ce6b71 | 353 | $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/roles', '')); |
df997f84 PS |
354 | } |
355 | } | |
356 | // Check role permissions | |
357 | if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride','moodle/role:override', 'moodle/role:assign'), $coursecontext)) { | |
358 | $url = new moodle_url('/admin/roles/check.php', array('contextid'=>$coursecontext->id)); | |
f5ce6b71 | 359 | $permissionsnode->add(get_string('checkpermissions', 'role'), $url, navigation_node::TYPE_SETTING, null, 'permissions', new pix_icon('i/checkpermissions', '')); |
df997f84 PS |
360 | } |
361 | } | |
362 | ||
363 | // Deal somehow with users that are not enrolled but still got a role somehow | |
364 | if ($course->id != SITEID) { | |
365 | //TODO, create some new UI for role assignments at course level | |
366 | if (has_capability('moodle/role:assign', $coursecontext)) { | |
367 | $url = new moodle_url('/enrol/otherusers.php', array('id'=>$course->id)); | |
f5ce6b71 | 368 | $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/roles', '')); |
df997f84 PS |
369 | } |
370 | } | |
371 | ||
372 | // just in case nothing was actually added | |
373 | $usersnode->trim_if_empty(); | |
374 | ||
375 | if ($course->id != SITEID) { | |
376 | // Unenrol link | |
377 | $unenrolprinted = false; | |
378 | foreach ($instances as $instance) { | |
379 | if (!isset($plugins[$instance->enrol])) { | |
380 | continue; | |
381 | } | |
382 | $plugin = $plugins[$instance->enrol]; | |
383 | if ($unenrollink = $plugin->get_unenrolself_link($instance)) { | |
384 | $coursenode->add(get_string('unenrolme', 'core_enrol', format_string($course->shortname)), $unenrollink, navigation_node::TYPE_SETTING, null, 'unenrolself', new pix_icon('i/user', '')); | |
385 | $unenrolprinted = true; | |
386 | //TODO. deal with multiple unenrol links - not likely case, but still... | |
387 | } | |
388 | } | |
389 | // Enrol link | |
390 | if (!$unenrolprinted and !is_viewing($coursecontext) and !is_enrolled($coursecontext)) { | |
391 | $url = new moodle_url('/enrol/index.php', array('id'=>$course->id)); | |
392 | $coursenode->add(get_string('enrolme', 'core_enrol', format_string($course->shortname)), $url, navigation_node::TYPE_SETTING, null, 'enrolself', new pix_icon('i/user', '')); | |
393 | } | |
394 | } | |
395 | } | |
396 | ||
397 | /** | |
398 | * Returns list of courses current $USER is enrolled in and can access | |
399 | * | |
400 | * - $fields is an array of field names to ADD | |
401 | * so name the fields you really need, which will | |
402 | * be added and uniq'd | |
403 | * | |
404 | * @param strin|array $fields | |
405 | * @param string $sort | |
406 | * @param int $limit max number of courses | |
407 | * @return array | |
408 | */ | |
409 | function enrol_get_my_courses($fields = NULL, $sort = 'visible DESC,sortorder ASC', $limit = 0) { | |
410 | global $DB, $USER; | |
411 | ||
412 | // Guest account does not have any courses | |
413 | if (isguestuser() or !isloggedin()) { | |
414 | return(array()); | |
415 | } | |
416 | ||
417 | $basefields = array('id', 'category', 'sortorder', | |
418 | 'shortname', 'fullname', 'idnumber', | |
419 | 'startdate', 'visible', | |
420 | 'groupmode', 'groupmodeforce'); | |
421 | ||
422 | if (empty($fields)) { | |
423 | $fields = $basefields; | |
424 | } else if (is_string($fields)) { | |
425 | // turn the fields from a string to an array | |
426 | $fields = explode(',', $fields); | |
427 | $fields = array_map('trim', $fields); | |
428 | $fields = array_unique(array_merge($basefields, $fields)); | |
429 | } else if (is_array($fields)) { | |
430 | $fields = array_unique(array_merge($basefields, $fields)); | |
431 | } else { | |
432 | throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()'); | |
433 | } | |
434 | if (in_array('*', $fields)) { | |
435 | $fields = array('*'); | |
436 | } | |
437 | ||
438 | $orderby = ""; | |
439 | $sort = trim($sort); | |
440 | if (!empty($sort)) { | |
441 | $rawsorts = explode(',', $sort); | |
442 | $sorts = array(); | |
443 | foreach ($rawsorts as $rawsort) { | |
444 | $rawsort = trim($rawsort); | |
445 | if (strpos($rawsort, 'c.') === 0) { | |
446 | $rawsort = substr($rawsort, 2); | |
447 | } | |
448 | $sorts[] = trim($rawsort); | |
449 | } | |
450 | $sort = 'c.'.implode(',c.', $sorts); | |
451 | $orderby = "ORDER BY $sort"; | |
452 | } | |
453 | ||
454 | $wheres = array("c.id <> :siteid"); | |
455 | $params = array('siteid'=>SITEID); | |
456 | ||
457 | if (isset($USER->loginascontext) and $USER->loginascontext->contextlevel == CONTEXT_COURSE) { | |
458 | // list _only_ this course - anything else is asking for trouble... | |
459 | $wheres[] = "courseid = :loginas"; | |
460 | $params['loginas'] = $USER->loginascontext->instanceid; | |
461 | } | |
462 | ||
463 | $coursefields = 'c.' .join(',c.', $fields); | |
464 | list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); | |
4129338c | 465 | $wheres = implode(" AND ", $wheres); |
df997f84 | 466 | |
4129338c PS |
467 | //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there |
468 | $sql = "SELECT $coursefields $ccselect | |
df997f84 | 469 | FROM {course} c |
4129338c PS |
470 | JOIN (SELECT DISTINCT e.courseid |
471 | FROM {enrol} e | |
472 | JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) | |
473 | WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2) | |
474 | ) en ON (en.courseid = c.id) | |
df997f84 | 475 | $ccjoin |
4129338c | 476 | WHERE $wheres |
df997f84 PS |
477 | $orderby"; |
478 | $params['userid'] = $USER->id; | |
479 | $params['active'] = ENROL_USER_ACTIVE; | |
480 | $params['enabled'] = ENROL_INSTANCE_ENABLED; | |
481 | $params['now1'] = round(time(), -2); // improves db caching | |
482 | $params['now2'] = $params['now1']; | |
483 | ||
484 | $courses = $DB->get_records_sql($sql, $params, 0, $limit); | |
485 | ||
486 | // preload contexts and check visibility | |
487 | foreach ($courses as $id=>$course) { | |
488 | context_instance_preload($course); | |
489 | if (!$course->visible) { | |
490 | if (!$context = get_context_instance(CONTEXT_COURSE, $id)) { | |
491 | unset($course[$id]); | |
492 | continue; | |
493 | } | |
494 | if (!has_capability('moodle/course:viewhiddencourses', $context)) { | |
495 | unset($course[$id]); | |
496 | continue; | |
497 | } | |
498 | } | |
499 | $courses[$id] = $course; | |
500 | } | |
501 | ||
502 | //wow! Is that really all? :-D | |
503 | ||
504 | return $courses; | |
505 | } | |
506 | ||
507 | /** | |
508 | * Returns list of courses user is enrolled into. | |
509 | * | |
510 | * - $fields is an array of fieldnames to ADD | |
511 | * so name the fields you really need, which will | |
512 | * be added and uniq'd | |
513 | * | |
514 | * @param int $userid | |
515 | * @param bool $onlyactive return only active enrolments in courses user may see | |
516 | * @param strin|array $fields | |
517 | * @param string $sort | |
518 | * @return array | |
519 | */ | |
520 | function enrol_get_users_courses($userid, $onlyactive = false, $fields = NULL, $sort = 'visible DESC,sortorder ASC') { | |
521 | global $DB; | |
522 | ||
523 | // Guest account does not have any courses | |
87163782 | 524 | if (isguestuser($userid) or empty($userid)) { |
df997f84 PS |
525 | return(array()); |
526 | } | |
527 | ||
528 | $basefields = array('id', 'category', 'sortorder', | |
529 | 'shortname', 'fullname', 'idnumber', | |
530 | 'startdate', 'visible', | |
531 | 'groupmode', 'groupmodeforce'); | |
532 | ||
533 | if (empty($fields)) { | |
534 | $fields = $basefields; | |
535 | } else if (is_string($fields)) { | |
536 | // turn the fields from a string to an array | |
537 | $fields = explode(',', $fields); | |
538 | $fields = array_map('trim', $fields); | |
539 | $fields = array_unique(array_merge($basefields, $fields)); | |
540 | } else if (is_array($fields)) { | |
541 | $fields = array_unique(array_merge($basefields, $fields)); | |
542 | } else { | |
543 | throw new coding_exception('Invalid $fileds parameter in enrol_get_my_courses()'); | |
544 | } | |
545 | if (in_array('*', $fields)) { | |
546 | $fields = array('*'); | |
547 | } | |
548 | ||
549 | $orderby = ""; | |
550 | $sort = trim($sort); | |
551 | if (!empty($sort)) { | |
552 | $rawsorts = explode(',', $sort); | |
553 | $sorts = array(); | |
554 | foreach ($rawsorts as $rawsort) { | |
555 | $rawsort = trim($rawsort); | |
556 | if (strpos($rawsort, 'c.') === 0) { | |
557 | $rawsort = substr($rawsort, 2); | |
558 | } | |
559 | $sorts[] = trim($rawsort); | |
560 | } | |
561 | $sort = 'c.'.implode(',c.', $sorts); | |
562 | $orderby = "ORDER BY $sort"; | |
563 | } | |
564 | ||
df997f84 PS |
565 | $params = array('siteid'=>SITEID); |
566 | ||
567 | if ($onlyactive) { | |
4129338c | 568 | $subwhere = "WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)"; |
df997f84 PS |
569 | $params['now1'] = round(time(), -2); // improves db caching |
570 | $params['now2'] = $params['now1']; | |
571 | $params['active'] = ENROL_USER_ACTIVE; | |
572 | $params['enabled'] = ENROL_INSTANCE_ENABLED; | |
4129338c PS |
573 | } else { |
574 | $subwhere = ""; | |
df997f84 PS |
575 | } |
576 | ||
577 | $coursefields = 'c.' .join(',c.', $fields); | |
578 | list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); | |
df997f84 | 579 | |
4129338c PS |
580 | //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there |
581 | $sql = "SELECT $coursefields $ccselect | |
df997f84 | 582 | FROM {course} c |
4129338c PS |
583 | JOIN (SELECT DISTINCT e.courseid |
584 | FROM {enrol} e | |
585 | JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) | |
586 | $subwhere | |
587 | ) en ON (en.courseid = c.id) | |
df997f84 | 588 | $ccjoin |
4129338c | 589 | WHERE c.id <> :siteid |
df997f84 | 590 | $orderby"; |
87163782 | 591 | $params['userid'] = $userid; |
df997f84 PS |
592 | |
593 | $courses = $DB->get_records_sql($sql, $params); | |
594 | ||
595 | // preload contexts and check visibility | |
596 | foreach ($courses as $id=>$course) { | |
597 | context_instance_preload($course); | |
598 | if ($onlyactive) { | |
599 | if (!$course->visible) { | |
600 | if (!$context = get_context_instance(CONTEXT_COURSE, $id)) { | |
601 | unset($course[$id]); | |
602 | continue; | |
603 | } | |
604 | if (!has_capability('moodle/course:viewhiddencourses', $context, $userid)) { | |
605 | unset($course[$id]); | |
606 | continue; | |
607 | } | |
608 | } | |
609 | } | |
610 | $courses[$id] = $course; | |
611 | } | |
612 | ||
613 | //wow! Is that really all? :-D | |
614 | ||
615 | return $courses; | |
616 | ||
617 | } | |
618 | ||
619 | /** | |
620 | * Called when user is about to be deleted. | |
621 | * @param object $user | |
622 | * @return void | |
623 | */ | |
624 | function enrol_user_delete($user) { | |
625 | global $DB; | |
626 | ||
627 | $plugins = enrol_get_plugins(true); | |
628 | foreach ($plugins as $plugin) { | |
629 | $plugin->user_delete($user); | |
630 | } | |
631 | ||
632 | // force cleanup of all broken enrolments | |
633 | $DB->delete_records('user_enrolments', array('userid'=>$user->id)); | |
634 | } | |
635 | ||
636 | /** | |
637 | * Try to enrol user via default internal auth plugin. | |
638 | * | |
639 | * For now this is always using the manual enrol plugin... | |
640 | * | |
641 | * @param $courseid | |
642 | * @param $userid | |
643 | * @param $roleid | |
644 | * @param $timestart | |
645 | * @param $timeend | |
646 | * @return bool success | |
647 | */ | |
648 | function enrol_try_internal_enrol($courseid, $userid, $roleid = null, $timestart = 0, $timeend = 0) { | |
649 | global $DB; | |
650 | ||
651 | //note: this is hardcoded to manual plugin for now | |
652 | ||
653 | if (!enrol_is_enabled('manual')) { | |
654 | return false; | |
655 | } | |
656 | ||
657 | if (!$enrol = enrol_get_plugin('manual')) { | |
658 | return false; | |
659 | } | |
660 | if (!$instances = $DB->get_records('enrol', array('enrol'=>'manual', 'courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id ASC')) { | |
661 | return false; | |
662 | } | |
663 | $instance = reset($instances); | |
664 | ||
665 | $enrol->enrol_user($instance, $userid, $roleid, $timestart, $timeend); | |
666 | ||
667 | return true; | |
668 | } | |
669 | ||
670 | /** | |
671 | * All enrol plugins should be based on this class, | |
672 | * this is also the main source of documentation. | |
673 | */ | |
674 | abstract class enrol_plugin { | |
675 | protected $config = null; | |
676 | ||
677 | /** | |
678 | * Returns name of this enrol plugin | |
679 | * @return string | |
680 | */ | |
681 | public function get_name() { | |
682 | // second word in class is always enrol name | |
683 | $words = explode('_', get_class($this)); | |
684 | return $words[1]; | |
685 | } | |
686 | ||
687 | /** | |
688 | * Returns localised name of enrol instance | |
689 | * | |
690 | * @param object $instance (null is accepted too) | |
691 | * @return string | |
692 | */ | |
693 | public function get_instance_name($instance) { | |
694 | if (empty($instance->name)) { | |
695 | $enrol = $this->get_name(); | |
696 | return get_string('pluginname', 'enrol_'.$enrol); | |
697 | } else { | |
698 | return format_string($instance->name); | |
699 | } | |
700 | } | |
701 | ||
702 | /** | |
703 | * Makes sure config is loaded and cached. | |
704 | * @return void | |
705 | */ | |
706 | protected function load_config() { | |
707 | if (!isset($this->config)) { | |
708 | $name = $this->get_name(); | |
709 | if (!$config = get_config("enrol_$name")) { | |
710 | $config = new object(); | |
711 | } | |
712 | $this->config = $config; | |
713 | } | |
714 | } | |
715 | ||
716 | /** | |
717 | * Returns plugin config value | |
718 | * @param string $name | |
719 | * @param string $default value if config does not exist yet | |
720 | * @return string value or default | |
721 | */ | |
722 | public function get_config($name, $default = NULL) { | |
723 | $this->load_config(); | |
724 | return isset($this->config->$name) ? $this->config->$name : $default; | |
725 | } | |
726 | ||
727 | /** | |
728 | * Sets plugin config value | |
729 | * @param string $name name of config | |
730 | * @param string $value string config value, null means delete | |
731 | * @return string value | |
732 | */ | |
733 | public function set_config($name, $value) { | |
47811589 | 734 | $pluginname = $this->get_name(); |
df997f84 PS |
735 | $this->load_config(); |
736 | if ($value === NULL) { | |
737 | unset($this->config->$name); | |
738 | } else { | |
739 | $this->config->$name = $value; | |
740 | } | |
47811589 | 741 | set_config($name, $value, "enrol_$pluginname"); |
df997f84 PS |
742 | } |
743 | ||
744 | /** | |
745 | * Does this plugin assign protected roles are can they be manually removed? | |
746 | * @return bool - false means anybody may tweak roles, it does not use itemid and component when assigning roles | |
747 | */ | |
748 | public function roles_protected() { | |
749 | return true; | |
750 | } | |
751 | ||
91b99e80 PS |
752 | /** |
753 | * Does this plugin allow manual enrolments? | |
754 | * | |
755 | * @param stdClass $instance course enrol instance | |
756 | * All plugins allowing this must implement 'enrol/xxx:enrol' capability | |
757 | * | |
758 | * @return bool - true means user with 'enrol/xxx:enrol' may enrol others freely, trues means nobody may add more enrolments manually | |
759 | */ | |
760 | public function allow_enrol(stdClass $instance) { | |
761 | return false; | |
762 | } | |
763 | ||
df997f84 PS |
764 | /** |
765 | * Does this plugin allow manual unenrolments? | |
766 | * | |
767 | * @param stdClass $instance course enrol instance | |
91b99e80 | 768 | * All plugins allowing this must implement 'enrol/xxx:unenrol' capability |
df997f84 | 769 | * |
91b99e80 | 770 | * @return bool - true means user with 'enrol/xxx:unenrol' may unenrol others freely, trues means nobody may touch user_enrolments |
df997f84 PS |
771 | */ |
772 | public function allow_unenrol(stdClass $instance) { | |
773 | return false; | |
774 | } | |
775 | ||
776 | /** | |
777 | * Does this plugin allow manual changes in user_enrolments table? | |
778 | * | |
91b99e80 | 779 | * All plugins allowing this must implement 'enrol/xxx:manage' capability |
df997f84 PS |
780 | * |
781 | * @param stdClass $instance course enrol instance | |
782 | * @return bool - true means it is possible to change enrol period and status in user_enrolments table | |
783 | */ | |
784 | public function allow_manage(stdClass $instance) { | |
785 | return false; | |
786 | } | |
787 | ||
788 | /** | |
789 | * Attempt to automatically enrol current user in course without any interaction, | |
790 | * calling code has to make sure the plugin and instance are active. | |
791 | * | |
792 | * @param stdClass $instance course enrol instance | |
793 | * @param stdClass $user record | |
794 | * @return bool|int false means not enrolled, integer means timeend | |
795 | */ | |
796 | public function try_autoenrol(stdClass $instance) { | |
797 | global $USER; | |
798 | ||
799 | return false; | |
800 | } | |
801 | ||
802 | /** | |
803 | * Attempt to automatically gain temporary guest access to course, | |
804 | * calling code has to make sure the plugin and instance are active. | |
805 | * | |
806 | * @param stdClass $instance course enrol instance | |
807 | * @param stdClass $user record | |
808 | * @return bool|int false means no guest access, integer means timeend | |
809 | */ | |
810 | public function try_guestaccess(stdClass $instance) { | |
811 | global $USER; | |
812 | ||
813 | return false; | |
814 | } | |
815 | ||
816 | /** | |
817 | * Enrol user into course via enrol instance. | |
818 | * | |
819 | * @param stdClass $instance | |
820 | * @param int $userid | |
821 | * @param int $roleid optional role id | |
822 | * @param int $timestart | |
823 | * @param int $timeend | |
824 | * @return void | |
825 | */ | |
826 | public function enrol_user(stdClass $instance, $userid, $roleid = null, $timestart = 0, $timeend = 0) { | |
827 | global $DB, $USER, $CFG; // CFG necessary!!! | |
828 | ||
829 | if ($instance->courseid == SITEID) { | |
830 | throw new coding_exception('invalid attempt to enrol into frontpage course!'); | |
831 | } | |
832 | ||
833 | $name = $this->get_name(); | |
834 | $courseid = $instance->courseid; | |
835 | ||
836 | if ($instance->enrol !== $name) { | |
837 | throw new coding_exception('invalid enrol instance!'); | |
838 | } | |
839 | $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); | |
840 | ||
841 | $inserted = false; | |
842 | if ($ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { | |
843 | if ($ue->timestart != $timestart or $ue->timeend != $timeend) { | |
844 | $ue->timestart = $timestart; | |
845 | $ue->timeend = $timeend; | |
846 | $ue->modifier = $USER->id; | |
847 | $ue->timemodified = time(); | |
848 | $DB->update_record('user_enrolments', $ue); | |
849 | } | |
850 | } else { | |
851 | $ue = new object(); | |
852 | $ue->enrolid = $instance->id; | |
853 | $ue->status = ENROL_USER_ACTIVE; | |
854 | $ue->userid = $userid; | |
855 | $ue->timestart = $timestart; | |
856 | $ue->timeend = $timeend; | |
857 | $ue->modifier = $USER->id; | |
858 | $ue->timemodified = time(); | |
859 | $ue->id = $DB->insert_record('user_enrolments', $ue); | |
860 | ||
861 | $inserted = true; | |
862 | } | |
863 | ||
864 | if ($roleid) { | |
865 | if ($this->roles_protected()) { | |
866 | role_assign($roleid, $userid, $context->id, 'enrol_'.$name, $instance->id); | |
867 | } else { | |
868 | role_assign($roleid, $userid, $context->id); | |
869 | } | |
870 | } | |
871 | ||
872 | if ($inserted) { | |
873 | // add extra info and trigger event | |
874 | $ue->courseid = $courseid; | |
875 | $ue->enrol = $name; | |
876 | events_trigger('user_enrolled', $ue); | |
877 | } | |
878 | ||
879 | // reset primitive require_login() caching | |
880 | if ($userid == $USER->id) { | |
881 | if (isset($USER->enrol['enrolled'][$courseid])) { | |
882 | unset($USER->enrol['enrolled'][$courseid]); | |
883 | } | |
884 | if (isset($USER->enrol['tempguest'][$courseid])) { | |
885 | unset($USER->enrol['tempguest'][$courseid]); | |
886 | $USER->access = remove_temp_roles($context, $USER->access); | |
887 | } | |
888 | } | |
889 | } | |
890 | ||
891 | /** | |
892 | * Store user_enrolments changes and trigger event. | |
893 | * | |
894 | * @param object $ue | |
895 | * @param int $user id | |
896 | * @param int $status | |
897 | * @param int $timestart | |
898 | * @param int $timeend | |
899 | * @return void | |
900 | */ | |
901 | public function update_user_enrol(stdClass $instance, $userid, $status = NULL, $timestart = NULL, $timeend = NULL) { | |
902 | global $DB, $USER; | |
903 | ||
904 | $name = $this->get_name(); | |
905 | ||
906 | if ($instance->enrol !== $name) { | |
907 | throw new coding_exception('invalid enrol instance!'); | |
908 | } | |
909 | ||
910 | if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { | |
911 | // weird, user not enrolled | |
912 | return; | |
913 | } | |
914 | ||
915 | $modified = false; | |
916 | if (isset($status) and $ue->status != $status) { | |
917 | $ue->status = $status; | |
918 | $modified = true; | |
919 | } | |
920 | if (isset($timestart) and $ue->timestart != $timestart) { | |
921 | $ue->timestart = $timestart; | |
922 | $modified = true; | |
923 | } | |
924 | if (isset($timeend) and $ue->timeend != $timeend) { | |
925 | $ue->timeend = $timeend; | |
926 | $modified = true; | |
927 | } | |
928 | ||
929 | if (!$modified) { | |
930 | // no change | |
931 | return; | |
932 | } | |
933 | ||
934 | $ue->modifierid = $USER->id; | |
935 | $DB->update_record('user_enrolments', $ue); | |
936 | ||
937 | // trigger event | |
938 | $ue->courseid = $instance->courseid; | |
939 | $ue->enrol = $instance->name; | |
940 | events_trigger('user_unenrol_modified', $ue); | |
941 | } | |
942 | ||
943 | /** | |
944 | * Unenrol user from course, | |
945 | * the last unenrolment removes all remaining roles. | |
946 | * | |
947 | * @param stdClass $instance | |
948 | * @param int $userid | |
949 | * @return void | |
950 | */ | |
951 | public function unenrol_user(stdClass $instance, $userid) { | |
952 | global $CFG, $USER, $DB; | |
953 | ||
954 | $name = $this->get_name(); | |
955 | $courseid = $instance->courseid; | |
956 | ||
957 | if ($instance->enrol !== $name) { | |
958 | throw new coding_exception('invalid enrol instance!'); | |
959 | } | |
960 | $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); | |
961 | ||
962 | if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { | |
963 | // weird, user not enrolled | |
964 | return; | |
965 | } | |
966 | ||
967 | role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id)); | |
968 | $DB->delete_records('user_enrolments', array('id'=>$ue->id)); | |
969 | ||
970 | // add extra info and trigger event | |
971 | $ue->courseid = $courseid; | |
972 | $ue->enrol = $name; | |
973 | ||
974 | $sql = "SELECT 'x' | |
975 | FROM {user_enrolments} ue | |
976 | JOIN {enrol} e ON (e.id = ue.enrolid) | |
977 | WHERE ue.userid = :userid AND e.courseid = :courseid"; | |
978 | if ($DB->record_exists_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid))) { | |
979 | $ue->lastenrol = false; | |
980 | events_trigger('user_unenrolled', $ue); | |
981 | // user still has some enrolments, no big cleanup yet | |
982 | } else { | |
983 | // the big cleanup IS necessary! | |
984 | ||
985 | require_once("$CFG->dirroot/group/lib.php"); | |
986 | require_once("$CFG->libdir/gradelib.php"); | |
987 | ||
988 | // remove all remaining roles | |
989 | role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id), true, false); | |
990 | ||
991 | //clean up ALL invisible user data from course if this is the last enrolment - groups, grades, etc. | |
992 | groups_delete_group_members($courseid, $userid); | |
993 | ||
994 | grade_user_unenrol($courseid, $userid); | |
995 | ||
996 | $DB->delete_records('user_lastaccess', array('userid'=>$userid, 'courseid'=>$courseid)); | |
997 | ||
998 | $ue->lastenrol = false; | |
999 | events_trigger('user_unenrolled', $ue); | |
1000 | } | |
1001 | // reset primitive require_login() caching | |
1002 | if ($userid == $USER->id) { | |
1003 | if (isset($USER->enrol['enrolled'][$courseid])) { | |
1004 | unset($USER->enrol['enrolled'][$courseid]); | |
1005 | } | |
1006 | if (isset($USER->enrol['tempguest'][$courseid])) { | |
1007 | unset($USER->enrol['tempguest'][$courseid]); | |
1008 | $USER->access = remove_temp_roles($context, $USER->access); | |
1009 | } | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | /** | |
1014 | * Forces synchronisation of user enrolments. | |
1015 | * | |
1016 | * This is important especially for external enrol plugins, | |
1017 | * this function is called for all enabled enrol plugins | |
1018 | * right after every user login. | |
1019 | * | |
1020 | * @param object $user user record | |
1021 | * @return void | |
1022 | */ | |
1023 | public function sync_user_enrolments($user) { | |
1024 | // override if necessary | |
1025 | } | |
1026 | ||
1027 | /** | |
1028 | * Returns link to page which may be used to add new instance of enrolment plugin in course. | |
1029 | * @param int $courseid | |
1030 | * @return moodle_url page url | |
1031 | */ | |
1032 | public function get_candidate_link($courseid) { | |
1033 | // override for most plugins, check if instance already exists in cases only one instance is supported | |
1034 | return NULL; | |
1035 | } | |
1036 | ||
1037 | /** | |
1038 | * Is it possible to delete enrol instance via standard UI? | |
1039 | * | |
1040 | * @param object $instance | |
1041 | * @return bool | |
1042 | */ | |
1043 | public function instance_deleteable($instance) { | |
1044 | return true; | |
1045 | } | |
1046 | ||
1047 | /** | |
1048 | * Returns link to manual enrol UI if exists. | |
1049 | * Does the access control tests automatically. | |
1050 | * | |
1051 | * @param object $instance | |
1052 | * @return moodle_url | |
1053 | */ | |
1054 | public function get_manual_enrol_link($instance) { | |
1055 | return NULL; | |
1056 | } | |
1057 | ||
1058 | /** | |
1059 | * Returns list of unenrol links for all enrol instances in course. | |
1060 | * | |
1061 | * @param int $courseid | |
1062 | * @return moodle_url | |
1063 | */ | |
1064 | public function get_unenrolself_link($instance) { | |
1065 | global $USER, $CFG, $DB; | |
1066 | ||
1067 | $name = $this->get_name(); | |
1068 | if ($instance->enrol !== $name) { | |
1069 | throw new coding_exception('invalid enrol instance!'); | |
1070 | } | |
1071 | ||
1072 | if ($instance->courseid == SITEID) { | |
1073 | return NULL; | |
1074 | } | |
1075 | ||
1076 | if (!enrol_is_enabled($name)) { | |
1077 | return NULL; | |
1078 | } | |
1079 | ||
1080 | if ($instance->status != ENROL_INSTANCE_ENABLED) { | |
1081 | return NULL; | |
1082 | } | |
1083 | ||
1084 | $context = get_context_instance(CONTEXT_COURSE, $instance->courseid, MUST_EXIST); | |
1085 | $courseid = $instance->courseid; | |
1086 | ||
1087 | if (!file_exists("$CFG->dirroot/enrol/$name/unenrolself.php")) { | |
1088 | return NULL; | |
1089 | } | |
1090 | ||
1091 | $context = get_context_instance(CONTEXT_COURSE, $courseid); | |
1092 | if (!has_capability("enrol/$name:unenrolself", $context)) { | |
1093 | return NULL; | |
1094 | } | |
1095 | ||
1096 | if (!$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$USER->id, 'status'=>ENROL_USER_ACTIVE))) { | |
1097 | return NULL; | |
1098 | } | |
1099 | ||
1100 | return new moodle_url("/enrol/$name/unenrolself.php", array('enrolid'=>$instance->id));; | |
1101 | } | |
1102 | ||
1103 | /** | |
1104 | * Adds enrol instance UI to course edit form | |
1105 | * | |
1106 | * @param object $instance enrol instance or null if does not exist yet | |
1107 | * @param MoodleQuickForm $mform | |
1108 | * @param object $data | |
1109 | * @param object $context context of existing course or parent category if course does not exist | |
1110 | * @return void | |
1111 | */ | |
1112 | public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) { | |
1113 | // override - usually at least enable/disable switch, has to add own form header | |
1114 | } | |
1115 | ||
1116 | /** | |
1117 | * Validates course edit form data | |
1118 | * | |
1119 | * @param object $instance enrol instance or null if does not exist yet | |
1120 | * @param array $data | |
1121 | * @param object $context context of existing course or parent category if course does not exist | |
1122 | * @return array errors array | |
1123 | */ | |
1124 | public function course_edit_validation($instance, array $data, $context) { | |
1125 | return array(); | |
1126 | } | |
1127 | ||
1128 | /** | |
1129 | * Called after updating/inserting course. | |
1130 | * | |
1131 | * @param bool $inserted true if course just inserted | |
1132 | * @param object $course | |
1133 | * @param object $data form data | |
1134 | * @return void | |
1135 | */ | |
1136 | public function course_updated($inserted, $course, $data) { | |
1137 | // override if settings on course edit page or some automatic sync needed | |
1138 | } | |
1139 | ||
1140 | /** | |
1141 | * Add new instance of enrol plugin settings. | |
1142 | * @param object $course | |
1143 | * @param array instance fields | |
1144 | * @return int id of new instance | |
1145 | */ | |
1146 | public function add_instance($course, array $fields = NULL) { | |
1147 | global $DB; | |
1148 | ||
1149 | if ($course->id == SITEID) { | |
1150 | throw new coding_exception('Invalid request to add enrol instance to frontpage.'); | |
1151 | } | |
1152 | ||
1153 | $instance = new object(); | |
1154 | $instance->enrol = $this->get_name(); | |
1155 | $instance->status = ENROL_INSTANCE_ENABLED; | |
1156 | $instance->courseid = $course->id; | |
1157 | $instance->enrolstartdate = 0; | |
1158 | $instance->enrolenddate = 0; | |
1159 | $instance->timemodified = time(); | |
1160 | $instance->timecreated = $instance->timemodified; | |
1161 | $instance->sortorder = $DB->get_field('enrol', 'COALESCE(MAX(sortorder), -1) + 1', array('courseid'=>$course->id)); | |
1162 | ||
1163 | $fields = (array)$fields; | |
1164 | unset($fields['enrol']); | |
1165 | unset($fields['courseid']); | |
1166 | unset($fields['sortorder']); | |
1167 | foreach($fields as $field=>$value) { | |
1168 | $instance->$field = $value; | |
1169 | } | |
1170 | ||
1171 | return $DB->insert_record('enrol', $instance); | |
1172 | } | |
1173 | ||
1174 | /** | |
1175 | * Add new instance of enrol plugin with default settings, | |
1176 | * called when adding new instance manually or when adding new course. | |
1177 | * | |
1178 | * Not all plugins support this. | |
1179 | * | |
1180 | * @param object $course | |
1181 | * @return int id of new instance or null if no default supported | |
1182 | */ | |
1183 | public function add_default_instance($course) { | |
1184 | return null; | |
1185 | } | |
1186 | ||
1187 | /** | |
1188 | * Delete course enrol plugin instance, unenrol all users. | |
1189 | * @param object $instance | |
1190 | * @return void | |
1191 | */ | |
1192 | public function delete_instance($instance) { | |
1193 | global $DB; | |
1194 | ||
1195 | $name = $this->get_name(); | |
1196 | if ($instance->enrol !== $name) { | |
1197 | throw new coding_exception('invalid enrol instance!'); | |
1198 | } | |
1199 | ||
1200 | //first unenrol all users | |
1201 | $participants = $DB->get_recordset('user_enrolments', array('enrolid'=>$instance->id)); | |
1202 | foreach ($participants as $participant) { | |
1203 | $this->unenrol_user($instance, $participant->userid); | |
1204 | } | |
1205 | $participants->close(); | |
1206 | ||
1207 | // now clean up all remainders that were not removed correctly | |
1208 | $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>$name)); | |
1209 | $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id)); | |
1210 | ||
1211 | // finally drop the enrol row | |
1212 | $DB->delete_records('enrol', array('id'=>$instance->id)); | |
1213 | } | |
1214 | ||
1215 | /** | |
1216 | * Creates course enrol form, checks if form submitted | |
1217 | * and enrols user if necessary. It can also redirect. | |
1218 | * | |
1219 | * @param stdClass $instance | |
1220 | * @return string html text, usually a form in a text box | |
1221 | */ | |
1222 | public function enrol_page_hook(stdClass $instance) { | |
1223 | return null; | |
1224 | } | |
1225 | ||
1226 | /** | |
1227 | * Adds navigation links into course admin block. | |
1228 | * | |
1229 | * By defaults looks for manage links only. | |
1230 | * | |
1231 | * @param navigation_node $instancesnode | |
1232 | * @param object $instance | |
1233 | * @return moodle_url; | |
1234 | */ | |
1235 | public function add_course_navigation($instancesnode, stdClass $instance) { | |
1236 | if ($managelink = $this->get_manage_link($instance)) { | |
1237 | $instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING); | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | /** | |
1242 | * Returns enrolment instance manage link. | |
1243 | * | |
1244 | * By defaults looks for manage.php file and tests for manage capability. | |
1245 | * | |
1246 | * @param object $instance | |
1247 | * @return moodle_url; | |
1248 | */ | |
1249 | public function get_manage_link($instance) { | |
1250 | global $CFG, $DB; | |
1251 | ||
1252 | $name = $this->get_name(); | |
1253 | ||
1254 | if ($instance->enrol !== $name) { | |
1255 | throw new coding_exception('Invalid enrol instance type!'); | |
1256 | } | |
1257 | ||
1258 | if (!file_exists("$CFG->dirroot/enrol/$name/manage.php")) { | |
1259 | return NULL; | |
1260 | } | |
1261 | ||
1262 | if ($instance->courseid == SITEID) { | |
1263 | // no enrolments on the frontpage, only roles there allowed | |
1264 | return NULL; | |
1265 | } | |
1266 | ||
1267 | $context = get_context_instance(CONTEXT_COURSE, $instance->courseid); | |
1268 | if (!has_capability('enrol/'.$name.':manage', $context)) { | |
1269 | return NULL; | |
1270 | } | |
1271 | ||
1272 | return new moodle_url("/enrol/$name/manage.php", array('enrolid'=>$instance->id)); | |
1273 | } | |
1274 | ||
1275 | /** | |
1276 | * Reads version.php and determines if it is necessary | |
1277 | * to execute the cron job now. | |
1278 | * @return bool | |
1279 | */ | |
1280 | public function is_cron_required() { | |
1281 | global $CFG; | |
1282 | ||
1283 | $name = $this->get_name(); | |
1284 | $versionfile = "$CFG->dirroot/enrol/$name/version.php"; | |
1285 | $plugin = new object(); | |
1286 | include($versionfile); | |
1287 | if (empty($plugin->cron)) { | |
1288 | return false; | |
1289 | } | |
1290 | $lastexecuted = $this->get_config('lastcron', 0); | |
1291 | if ($lastexecuted + $plugin->cron < time()) { | |
1292 | return true; | |
1293 | } else { | |
1294 | return false; | |
1295 | } | |
1296 | } | |
1297 | ||
1298 | /** | |
1299 | * Called for all enabled enrol plugins that returned true from is_cron_required(). | |
1300 | * @return void | |
1301 | */ | |
1302 | public function cron() { | |
1303 | } | |
1304 | ||
1305 | /** | |
1306 | * Called when user is about to be deleted | |
1307 | * @param object $user | |
1308 | * @return void | |
1309 | */ | |
1310 | public function user_delete($user) { | |
1311 | global $DB; | |
1312 | ||
1313 | $sql = "SELECT e.* | |
1314 | FROM {enrol} e | |
1315 | JOIN {user_enrolments} ue ON (ue.courseid = e.courseid) | |
1316 | WHERE e.enrol = :meta AND ue.userid = :userid"; | |
1317 | $params = array('name'=>$this->get_name(), 'userid'=>$user->id); | |
1318 | ||
1319 | $rs = $DB->get_records_recordset($sql, $params); | |
1320 | foreach($rs as $instance) { | |
1321 | $this->unenrol_user($instance, $user->id); | |
1322 | } | |
1323 | $rs->close(); | |
1324 | } | |
1325 | } | |
1326 |