MDL-17929 enrol_meta: synchronise with groups
[moodle.git] / enrol / meta / locallib.php
CommitLineData
df997f84 1<?php
df997f84
PS
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Local stuff for meta course enrolment plugin.
19 *
31ac2aef 20 * @package enrol_meta
e2382027
PS
21 * @copyright 2010 Petr Skoda {@link http://skodak.org}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
df997f84
PS
23 */
24
e2382027 25defined('MOODLE_INTERNAL') || die();
df997f84 26
ad68ed74 27
df997f84
PS
28/**
29 * Event handler for meta enrolment plugin.
30 *
31 * We try to keep everything in sync via listening to events,
32 * it may fail sometimes, so we always do a full sync in cron too.
33 */
34class enrol_meta_handler {
ad68ed74
PS
35
36 /**
37 * Synchronise meta enrolments of this user in this course
38 * @static
39 * @param int $courseid
40 * @param int $userid
41 * @return void
42 */
43 protected static function sync_course_instances($courseid, $userid) {
df997f84
PS
44 global $DB;
45
ad68ed74
PS
46 static $preventrecursion = false;
47
48 // does anything want to sync with this parent?
49 if (!$enrols = $DB->get_records('enrol', array('customint1'=>$courseid, 'enrol'=>'meta'), 'id ASC')) {
50 return;
51 }
52
53 if ($preventrecursion) {
54 return;
55 }
56
57 $preventrecursion = true;
58
59 try {
60 foreach ($enrols as $enrol) {
61 self::sync_with_parent_course($enrol, $userid);
62 }
63 } catch (Exception $e) {
64 $preventrecursion = false;
65 throw $e;
66 }
67
68 $preventrecursion = false;
69 }
70
71 /**
72 * Synchronise user enrolments in given instance as fast as possible.
73 *
74 * All roles are removed if the meta plugin disabled.
75 *
76 * @static
77 * @param stdClass $instance
78 * @param int $userid
79 * @return void
80 */
81 protected static function sync_with_parent_course(stdClass $instance, $userid) {
82 global $DB, $CFG;
83
84 $plugin = enrol_get_plugin('meta');
85
86 if ($instance->customint1 == $instance->courseid) {
87 // can not sync with self!!!
88 return;
89 }
90
91 $context = context_course::instance($instance->courseid);
92
ad68ed74
PS
93 // list of enrolments in parent course (we ignore meta enrols in parents completely)
94 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
95 $params['userid'] = $userid;
96 $params['parentcourse'] = $instance->customint1;
97 $sql = "SELECT ue.*
98 FROM {user_enrolments} ue
99 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol <> 'meta' AND e.courseid = :parentcourse AND e.enrol $enabled)
100 WHERE ue.userid = :userid";
101 $parentues = $DB->get_records_sql($sql, $params);
102 // current enrolments for this instance
103 $ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid));
104
105 // first deal with users that are not enrolled in parent
106 if (empty($parentues)) {
107 self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
108 return;
109 }
110
1344bc78
PS
111 if (!$parentcontext = context_course::instance($instance->customint1, IGNORE_MISSING)) {
112 // Weird, we should not get here.
ad68ed74 113 return;
df997f84
PS
114 }
115
ad68ed74
PS
116 $skiproles = $plugin->get_config('nosyncroleids', '');
117 $skiproles = empty($skiproles) ? array() : explode(',', $skiproles);
118 $syncall = $plugin->get_config('syncall', 1);
119
120 // roles in parent course (meta enrols must be ignored!)
121 $parentroles = array();
122 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
123 $params['contextid'] = $parentcontext->id;
124 $params['userid'] = $userid;
125 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
126 foreach($DB->get_records_select('role_assignments', $select, $params) as $ra) {
127 $parentroles[$ra->roleid] = $ra->roleid;
df997f84
PS
128 }
129
ad68ed74
PS
130 // roles from this instance
131 $roles = array();
132 $ras = $DB->get_records('role_assignments', array('contextid'=>$context->id, 'userid'=>$userid, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
133 foreach($ras as $ra) {
134 $roles[$ra->roleid] = $ra->roleid;
df997f84 135 }
ad68ed74 136 unset($ras);
df997f84 137
ad68ed74
PS
138 // do we want users without roles?
139 if (!$syncall and empty($parentroles)) {
140 self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
141 return;
df997f84
PS
142 }
143
ad68ed74
PS
144 // is parent enrol active? (we ignore enrol starts and ends, sorry it would be too complex)
145 $parentstatus = ENROL_USER_SUSPENDED;
146 foreach ($parentues as $pue) {
147 if ($pue->status == ENROL_USER_ACTIVE) {
148 $parentstatus = ENROL_USER_ACTIVE;
149 break;
df997f84
PS
150 }
151 }
152
ad68ed74
PS
153 // enrol user if not enrolled yet or fix status
154 if ($ue) {
155 if ($parentstatus != $ue->status) {
156 $plugin->update_user_enrol($instance, $userid, $parentstatus);
157 $ue->status = $parentstatus;
158 }
159 } else {
160 $plugin->enrol_user($instance, $userid, NULL, 0, 0, $parentstatus);
161 $ue = new stdClass();
162 $ue->userid = $userid;
163 $ue->enrolid = $instance->id;
164 $ue->status = $parentstatus;
9e37d365
MG
165 if ($instance->customint2) {
166 groups_add_member($instance->customint2, $userid, 'enrol_meta', $instance->id);
167 }
ad68ed74
PS
168 }
169
1344bc78
PS
170 $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
171
ad68ed74
PS
172 // only active users in enabled instances are supposed to have roles (we can reassign the roles any time later)
173 if ($ue->status != ENROL_USER_ACTIVE or $instance->status != ENROL_INSTANCE_ENABLED) {
1344bc78
PS
174 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
175 // Always keep the roles.
176 } else if ($roles) {
ad68ed74 177 role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
df997f84 178 }
ad68ed74
PS
179 return;
180 }
df997f84 181
ad68ed74
PS
182 // add new roles
183 foreach ($parentroles as $rid) {
184 if (!isset($roles[$rid])) {
185 role_assign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
186 }
df997f84
PS
187 }
188
1344bc78
PS
189 if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
190 // Always keep the roles.
191 return;
192 }
193
ad68ed74
PS
194 // remove roles
195 foreach ($roles as $rid) {
196 if (!isset($parentroles[$rid])) {
197 role_unassign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
198 }
199 }
df997f84
PS
200 }
201
ad68ed74
PS
202 /**
203 * Deal with users that are not supposed to be enrolled via this instance
204 * @static
205 * @param stdClass $instance
206 * @param stdClass $ue
207 * @param context_course $context
208 * @param enrol_meta $plugin
209 * @return void
210 */
211 protected static function user_not_supposed_to_be_here($instance, $ue, context_course $context, $plugin) {
212 if (!$ue) {
1344bc78 213 // Not enrolled yet - simple!
ad68ed74
PS
214 return;
215 }
216
217 $userid = $ue->userid;
1344bc78 218 $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
ad68ed74
PS
219
220 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
1344bc78 221 // Purges grades, group membership, preferences, etc. - admins were warned!
ad68ed74 222 $plugin->unenrol_user($instance, $userid);
ad68ed74 223
1344bc78 224 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
ad68ed74
PS
225 if ($ue->status != ENROL_USER_SUSPENDED) {
226 $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
ad68ed74 227 }
1344bc78
PS
228
229 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
230 if ($ue->status != ENROL_USER_SUSPENDED) {
231 $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
232 }
233 role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
234
235 } else {
236 debugging('Unknown unenrol action '.$unenrolaction);
ad68ed74
PS
237 }
238 }
df997f84
PS
239}
240
241/**
242 * Sync all meta course links.
ad68ed74 243 *
df997f84 244 * @param int $courseid one course, empty mean all
ad68ed74
PS
245 * @param bool $verbose verbose CLI output
246 * @return int 0 means ok, 1 means error, 2 means plugin disabled
df997f84 247 */
ad68ed74 248function enrol_meta_sync($courseid = NULL, $verbose = false) {
df997f84 249 global $CFG, $DB;
98177a45 250 require_once("{$CFG->dirroot}/group/lib.php");
df997f84 251
ad68ed74
PS
252 // purge all roles if meta sync disabled, those can be recreated later here in cron
253 if (!enrol_is_enabled('meta')) {
254 if ($verbose) {
255 mtrace('Meta sync plugin is disabled, unassigning all plugin roles and stopping.');
256 }
257 role_unassign_all(array('component'=>'enrol_meta'));
258 return 2;
259 }
260
261 // unfortunately this may take a long time, execution can be interrupted safely
3ef7279f 262 core_php_time_limit::raise();
ad68ed74 263 raise_memory_limit(MEMORY_HUGE);
df997f84 264
ad68ed74
PS
265 if ($verbose) {
266 mtrace('Starting user enrolment synchronisation...');
267 }
268
269 $instances = array(); // cache instances
379434e4 270
df997f84
PS
271 $meta = enrol_get_plugin('meta');
272
1344bc78 273 $unenrolaction = $meta->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
ad68ed74
PS
274 $skiproles = $meta->get_config('nosyncroleids', '');
275 $skiproles = empty($skiproles) ? array() : explode(',', $skiproles);
276 $syncall = $meta->get_config('syncall', 1);
277
278 $allroles = get_all_roles();
279
df997f84
PS
280
281 // iterate through all not enrolled yet users
ad68ed74
PS
282 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
283 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
284 $params['courseid'] = $courseid;
285 $sql = "SELECT pue.userid, e.id AS enrolid, pue.status
286 FROM {user_enrolments} pue
287 JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled)
288 JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' $onecourse)
f3bd4ea6 289 JOIN {user} u ON (u.id = pue.userid AND u.deleted = 0)
ad68ed74
PS
290 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid)
291 WHERE ue.id IS NULL";
292
293 $rs = $DB->get_recordset_sql($sql, $params);
294 foreach($rs as $ue) {
295 if (!isset($instances[$ue->enrolid])) {
296 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
df997f84 297 }
ad68ed74
PS
298 $instance = $instances[$ue->enrolid];
299
300 if (!$syncall) {
301 // this may be slow if very many users are ignored in sync
302 $parentcontext = context_course::instance($instance->customint1);
303 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
304 $params['contextid'] = $parentcontext->id;
305 $params['userid'] = $ue->userid;
306 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
307 if (!$DB->record_exists_select('role_assignments', $select, $params)) {
308 // bad luck, this user does not have any role we want in parent course
309 if ($verbose) {
310 mtrace(" skipping enrolling: $ue->userid ==> $instance->courseid (user without role)");
311 }
312 continue;
df997f84 313 }
df997f84 314 }
ad68ed74
PS
315
316 $meta->enrol_user($instance, $ue->userid, $ue->status);
9e37d365
MG
317 if ($instance->customint2) {
318 groups_add_member($instance->customint2, $ue->userid, 'enrol_meta', $instance->id);
319 }
ad68ed74
PS
320 if ($verbose) {
321 mtrace(" enrolling: $ue->userid ==> $instance->courseid");
322 }
df997f84 323 }
ad68ed74
PS
324 $rs->close();
325
df997f84 326
ad68ed74
PS
327 // unenrol as necessary - ignore enabled flag, we want to get rid of existing enrols in any case
328 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
329 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
330 $params['courseid'] = $courseid;
331 $sql = "SELECT ue.*
df997f84
PS
332 FROM {user_enrolments} ue
333 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
26a06fa7 334 LEFT JOIN ({user_enrolments} xpue
ad68ed74 335 JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
26a06fa7
MA
336 ) ON (xpe.courseid = e.customint1 AND xpue.userid = ue.userid)
337 WHERE xpue.userid IS NULL";
ad68ed74 338 $rs = $DB->get_recordset_sql($sql, $params);
df997f84
PS
339 foreach($rs as $ue) {
340 if (!isset($instances[$ue->enrolid])) {
341 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
342 }
ad68ed74
PS
343 $instance = $instances[$ue->enrolid];
344
345 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
346 $meta->unenrol_user($instance, $ue->userid);
347 if ($verbose) {
348 mtrace(" unenrolling: $ue->userid ==> $instance->courseid");
349 }
ad68ed74 350
1344bc78
PS
351 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
352 if ($ue->status != ENROL_USER_SUSPENDED) {
353 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
354 if ($verbose) {
355 mtrace(" suspending: $ue->userid ==> $instance->courseid");
356 }
357 }
358
359 } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
ad68ed74
PS
360 if ($ue->status != ENROL_USER_SUSPENDED) {
361 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
362 $context = context_course::instance($instance->courseid);
1344bc78 363 role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
ad68ed74
PS
364 if ($verbose) {
365 mtrace(" suspending and removing all roles: $ue->userid ==> $instance->courseid");
366 }
367 }
ad68ed74 368 }
df997f84
PS
369 }
370 $rs->close();
df997f84 371
ad68ed74
PS
372
373 // update status - meta enrols + start and end dates are ignored, sorry
374 // note the trick here is that the active enrolment and instance constants have value 0
375 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
376 list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
377 $params['courseid'] = $courseid;
378 $sql = "SELECT ue.userid, ue.enrolid, pue.pstatus
379 FROM {user_enrolments} ue
380 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
381 JOIN (SELECT xpue.userid, xpe.courseid, MIN(xpue.status + xpe.status) AS pstatus
382 FROM {user_enrolments} xpue
383 JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
384 GROUP BY xpue.userid, xpe.courseid
385 ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid)
386 WHERE (pue.pstatus = 0 AND ue.status > 0) OR (pue.pstatus > 0 and ue.status = 0)";
387 $rs = $DB->get_recordset_sql($sql, $params);
388 foreach($rs as $ue) {
389 if (!isset($instances[$ue->enrolid])) {
390 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
391 }
392 $instance = $instances[$ue->enrolid];
393 $ue->pstatus = ($ue->pstatus == ENROL_USER_ACTIVE) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED;
394
395 if ($ue->pstatus == ENROL_USER_ACTIVE and !$syncall and $unenrolaction != ENROL_EXT_REMOVED_UNENROL) {
396 // this may be slow if very many users are ignored in sync
397 $parentcontext = context_course::instance($instance->customint1);
398 list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
399 $params['contextid'] = $parentcontext->id;
400 $params['userid'] = $ue->userid;
401 $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
402 if (!$DB->record_exists_select('role_assignments', $select, $params)) {
403 // bad luck, this user does not have any role we want in parent course
404 if ($verbose) {
405 mtrace(" skipping unsuspending: $ue->userid ==> $instance->courseid (user without role)");
406 }
407 continue;
df997f84 408 }
ad68ed74
PS
409 }
410
411 $meta->update_user_enrol($instance, $ue->userid, $ue->pstatus);
412 if ($verbose) {
413 if ($ue->pstatus == ENROL_USER_ACTIVE) {
414 mtrace(" unsuspending: $ue->userid ==> $instance->courseid");
415 } else {
416 mtrace(" suspending: $ue->userid ==> $instance->courseid");
417 }
418 }
419 }
420 $rs->close();
421
422
423 // now assign all necessary roles
424 $enabled = explode(',', $CFG->enrol_plugins_enabled);
425 foreach($enabled as $k=>$v) {
426 if ($v === 'meta') {
427 continue; // no meta sync of meta roles
428 }
429 $enabled[$k] = 'enrol_'.$v;
430 }
77a5c093 431 $enabled[] = ''; // manual assignments are replicated too
ad68ed74
PS
432
433 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
434 list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e');
435 $params['coursecontext'] = CONTEXT_COURSE;
436 $params['courseid'] = $courseid;
437 $params['activeuser'] = ENROL_USER_ACTIVE;
438 $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
439 $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid, e.courseid
440 FROM {role_assignments} pra
441 JOIN {user} u ON (u.id = pra.userid AND u.deleted = 0)
442 JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled)
443 JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' $onecourse AND e.status = :enabledinstance)
444 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = u.id AND ue.status = :activeuser)
445 JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid)
446 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = pra.userid AND ra.roleid = pra.roleid AND ra.itemid = e.id AND ra.component = 'enrol_meta')
447 WHERE ra.id IS NULL";
448
449 if ($ignored = $meta->get_config('nosyncroleids')) {
450 list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
451 $params = array_merge($params, $xparams);
452 $sql = "$sql AND pra.roleid $notignored";
df997f84
PS
453 }
454
ad68ed74
PS
455 $rs = $DB->get_recordset_sql($sql, $params);
456 foreach($rs as $ra) {
457 role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid);
458 if ($verbose) {
459 mtrace(" assigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
460 }
461 }
462 $rs->close();
463
464
df997f84 465 // remove unwanted roles - include ignored roles and disabled plugins too
ad68ed74
PS
466 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
467 $params = array();
468 $params['coursecontext'] = CONTEXT_COURSE;
469 $params['courseid'] = $courseid;
470 $params['activeuser'] = ENROL_USER_ACTIVE;
471 $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
df997f84 472 if ($ignored = $meta->get_config('nosyncroleids')) {
cf717dc2 473 list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
df997f84
PS
474 $params = array_merge($params, $xparams);
475 $notignored = "AND pra.roleid $notignored";
476 } else {
477 $notignored = "";
478 }
1344bc78 479
ad68ed74 480 $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid, e.courseid
df997f84
PS
481 FROM {role_assignments} ra
482 JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse)
483 JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext)
484 LEFT JOIN {role_assignments} pra ON (pra.contextid = pc.id AND pra.userid = ra.userid AND pra.roleid = ra.roleid AND pra.component <> 'enrol_meta' $notignored)
ad68ed74
PS
485 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid AND ue.status = :activeuser)
486 WHERE pra.id IS NULL OR ue.id IS NULL OR e.status <> :enabledinstance";
df997f84 487
1344bc78
PS
488 if ($unenrolaction != ENROL_EXT_REMOVED_SUSPEND) {
489 $rs = $DB->get_recordset_sql($sql, $params);
490 foreach($rs as $ra) {
491 role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid);
492 if ($verbose) {
493 mtrace(" unassigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
494 }
ad68ed74 495 }
1344bc78 496 $rs->close();
df997f84 497 }
df997f84 498
ad68ed74
PS
499
500 // kick out or suspend users without synced roles if syncall disabled
501 if (!$syncall) {
502 if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
503 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
504 $params = array();
505 $params['coursecontext'] = CONTEXT_COURSE;
379434e4 506 $params['courseid'] = $courseid;
ad68ed74
PS
507 $sql = "SELECT ue.userid, ue.enrolid
508 FROM {user_enrolments} ue
509 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
510 JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
511 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
512 WHERE ra.id IS NULL";
513 $ues = $DB->get_recordset_sql($sql, $params);
514 foreach($ues as $ue) {
515 if (!isset($instances[$ue->enrolid])) {
516 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
517 }
518 $instance = $instances[$ue->enrolid];
519 $meta->unenrol_user($instance, $ue->userid);
520 if ($verbose) {
521 mtrace(" unenrolling: $ue->userid ==> $instance->courseid (user without role)");
522 }
379434e4 523 }
ad68ed74 524 $ues->close();
379434e4 525
ad68ed74
PS
526 } else {
527 // just suspend the users
528 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
529 $params = array();
530 $params['coursecontext'] = CONTEXT_COURSE;
379434e4 531 $params['courseid'] = $courseid;
ad68ed74
PS
532 $params['active'] = ENROL_USER_ACTIVE;
533 $sql = "SELECT ue.userid, ue.enrolid
534 FROM {user_enrolments} ue
535 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
536 JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
537 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
538 WHERE ra.id IS NULL AND ue.status = :active";
539 $ues = $DB->get_recordset_sql($sql, $params);
540 foreach($ues as $ue) {
541 if (!isset($instances[$ue->enrolid])) {
542 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
543 }
544 $instance = $instances[$ue->enrolid];
545 $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
546 if ($verbose) {
547 mtrace(" suspending: $ue->userid ==> $instance->courseid (user without role)");
548 }
379434e4 549 }
ad68ed74 550 $ues->close();
379434e4 551 }
ad68ed74 552 }
379434e4 553
98177a45
DNA
554 // Finally sync groups.
555 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
556
557 // Remove invalid.
558 $sql = "SELECT gm.*, e.courseid, g.name AS groupname
559 FROM {groups_members} gm
560 JOIN {groups} g ON (g.id = gm.groupid)
561 JOIN {enrol} e ON (e.enrol = 'meta' AND e.courseid = g.courseid $onecourse)
562 JOIN {user_enrolments} ue ON (ue.userid = gm.userid AND ue.enrolid = e.id)
563 WHERE gm.component='enrol_meta' AND gm.itemid = e.id AND g.id <> e.customint2";
564 $params = array();
565 $params['courseid'] = $courseid;
566
567 $rs = $DB->get_recordset_sql($sql, $params);
568 foreach ($rs as $gm) {
569 groups_remove_member($gm->groupid, $gm->userid);
9e37d365
MG
570 if ($verbose) {
571 mtrace("removing user from group: $gm->userid ==> $gm->courseid - $gm->groupname", 1);
572 }
98177a45
DNA
573 }
574 $rs->close();
575
576 // Add missing.
577 $sql = "SELECT ue.*, g.id AS groupid, e.courseid, g.name AS groupname
578 FROM {user_enrolments} ue
579 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
580 JOIN {groups} g ON (g.courseid = e.courseid AND g.id = e.customint2)
581 JOIN {user} u ON (u.id = ue.userid AND u.deleted = 0)
582 LEFT JOIN {groups_members} gm ON (gm.groupid = g.id AND gm.userid = ue.userid)
583 WHERE gm.id IS NULL";
584 $params = array();
585 $params['courseid'] = $courseid;
586
587 $rs = $DB->get_recordset_sql($sql, $params);
588 foreach ($rs as $ue) {
589 groups_add_member($ue->groupid, $ue->userid, 'enrol_meta', $ue->enrolid);
9e37d365
MG
590 if ($verbose) {
591 mtrace("adding user to group: $ue->userid ==> $ue->courseid - $ue->groupname", 1);
592 }
98177a45
DNA
593 }
594 $rs->close();
595
ad68ed74
PS
596 if ($verbose) {
597 mtrace('...user enrolment synchronisation finished.');
379434e4
PS
598 }
599
ad68ed74 600 return 0;
df997f84 601}