source: moodle/trunk/fuentes/enrol/meta/locallib.php

Last change on this file was 1331, checked in by jrpelegrina, 3 years ago

Updated to moodle 3.0.3

File size: 28.8 KB
Line 
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Local stuff for meta course enrolment plugin.
19 *
20 * @package    enrol_meta
21 * @copyright  2010 Petr Skoda {@link http://skodak.org}
22 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die();
26
27
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 {
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) {
44        global $DB;
45
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        require_once($CFG->dirroot . '/group/lib.php');
84
85        $plugin = enrol_get_plugin('meta');
86
87        if ($instance->customint1 == $instance->courseid) {
88            // can not sync with self!!!
89            return;
90        }
91
92        $context = context_course::instance($instance->courseid);
93
94        // list of enrolments in parent course (we ignore meta enrols in parents completely)
95        list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
96        $params['userid'] = $userid;
97        $params['parentcourse'] = $instance->customint1;
98        $sql = "SELECT ue.*, e.status AS enrolstatus
99                  FROM {user_enrolments} ue
100                  JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol <> 'meta' AND e.courseid = :parentcourse AND e.enrol $enabled)
101                 WHERE ue.userid = :userid";
102        $parentues = $DB->get_records_sql($sql, $params);
103        // current enrolments for this instance
104        $ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid));
105
106        // first deal with users that are not enrolled in parent
107        if (empty($parentues)) {
108            self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
109            return;
110        }
111
112        if (!$parentcontext = context_course::instance($instance->customint1, IGNORE_MISSING)) {
113            // Weird, we should not get here.
114            return;
115        }
116
117        $skiproles = $plugin->get_config('nosyncroleids', '');
118        $skiproles = empty($skiproles) ? array() : explode(',', $skiproles);
119        $syncall   = $plugin->get_config('syncall', 1);
120
121        // roles in parent course (meta enrols must be ignored!)
122        $parentroles = array();
123        list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
124        $params['contextid'] = $parentcontext->id;
125        $params['userid'] = $userid;
126        $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
127        foreach($DB->get_records_select('role_assignments', $select, $params) as $ra) {
128            $parentroles[$ra->roleid] = $ra->roleid;
129        }
130
131        // roles from this instance
132        $roles = array();
133        $ras = $DB->get_records('role_assignments', array('contextid'=>$context->id, 'userid'=>$userid, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
134        foreach($ras as $ra) {
135            $roles[$ra->roleid] = $ra->roleid;
136        }
137        unset($ras);
138
139        // do we want users without roles?
140        if (!$syncall and empty($parentroles)) {
141            self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
142            return;
143        }
144
145        // Is parent enrol active? Find minimum timestart and maximum timeend of all active enrolments.
146        $parentstatus = ENROL_USER_SUSPENDED;
147        $parenttimeend = null;
148        $parenttimestart = null;
149        foreach ($parentues as $pue) {
150            if ($pue->status == ENROL_USER_ACTIVE && $pue->enrolstatus == ENROL_INSTANCE_ENABLED) {
151                $parentstatus = ENROL_USER_ACTIVE;
152                if ($parenttimeend === null || $pue->timeend == 0 || ($parenttimeend && $parenttimeend < $pue->timeend)) {
153                    $parenttimeend = $pue->timeend;
154                }
155                if ($parenttimestart === null || $parenttimestart > $pue->timestart) {
156                    $parenttimestart = $pue->timestart;
157                }
158            }
159        }
160
161        // Enrol user if not enrolled yet or fix status/timestart/timeend. Use the minimum timestart and maximum timeend found above.
162        if ($ue) {
163            if ($parentstatus != $ue->status ||
164                    ($parentstatus == ENROL_USER_ACTIVE && ($parenttimestart != $ue->timestart || $parenttimeend != $ue->timeend))) {
165                $plugin->update_user_enrol($instance, $userid, $parentstatus, $parenttimestart, $parenttimeend);
166                $ue->status = $parentstatus;
167                $ue->timestart = $parenttimestart;
168                $ue->timeend = $parenttimeend;
169            }
170        } else {
171            $plugin->enrol_user($instance, $userid, NULL, (int)$parenttimestart, (int)$parenttimeend, $parentstatus);
172            $ue = new stdClass();
173            $ue->userid = $userid;
174            $ue->enrolid = $instance->id;
175            $ue->status = $parentstatus;
176            if ($instance->customint2) {
177                groups_add_member($instance->customint2, $userid, 'enrol_meta', $instance->id);
178            }
179        }
180
181        $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
182
183        // Only active users in enabled instances are supposed to have roles (we can reassign the roles any time later).
184        if ($ue->status != ENROL_USER_ACTIVE or $instance->status != ENROL_INSTANCE_ENABLED or
185                ($parenttimeend and $parenttimeend < time()) or ($parenttimestart > time())) {
186            if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
187                // Always keep the roles.
188            } else if ($roles) {
189                // This will only unassign roles that were assigned in this enrolment method, leaving all manual role assignments intact.
190                role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
191            }
192            return;
193        }
194
195        // add new roles
196        foreach ($parentroles as $rid) {
197            if (!isset($roles[$rid])) {
198                role_assign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
199            }
200        }
201
202        if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
203            // Always keep the roles.
204            return;
205        }
206
207        // remove roles
208        foreach ($roles as $rid) {
209            if (!isset($parentroles[$rid])) {
210                role_unassign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
211            }
212        }
213    }
214
215    /**
216     * Deal with users that are not supposed to be enrolled via this instance
217     * @static
218     * @param stdClass $instance
219     * @param stdClass $ue
220     * @param context_course $context
221     * @param enrol_meta $plugin
222     * @return void
223     */
224    protected static function user_not_supposed_to_be_here($instance, $ue, context_course $context, $plugin) {
225        if (!$ue) {
226            // Not enrolled yet - simple!
227            return;
228        }
229
230        $userid = $ue->userid;
231        $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
232
233        if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
234            // Purges grades, group membership, preferences, etc. - admins were warned!
235            $plugin->unenrol_user($instance, $userid);
236
237        } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
238            if ($ue->status != ENROL_USER_SUSPENDED) {
239                $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
240            }
241
242        } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
243            if ($ue->status != ENROL_USER_SUSPENDED) {
244                $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
245            }
246            role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
247
248        } else {
249            debugging('Unknown unenrol action '.$unenrolaction);
250        }
251    }
252}
253
254/**
255 * Sync all meta course links.
256 *
257 * @param int $courseid one course, empty mean all
258 * @param bool $verbose verbose CLI output
259 * @return int 0 means ok, 1 means error, 2 means plugin disabled
260 */
261function enrol_meta_sync($courseid = NULL, $verbose = false) {
262    global $CFG, $DB;
263    require_once("{$CFG->dirroot}/group/lib.php");
264
265    // purge all roles if meta sync disabled, those can be recreated later here in cron
266    if (!enrol_is_enabled('meta')) {
267        if ($verbose) {
268            mtrace('Meta sync plugin is disabled, unassigning all plugin roles and stopping.');
269        }
270        role_unassign_all(array('component'=>'enrol_meta'));
271        return 2;
272    }
273
274    // unfortunately this may take a long time, execution can be interrupted safely
275    core_php_time_limit::raise();
276    raise_memory_limit(MEMORY_HUGE);
277
278    if ($verbose) {
279        mtrace('Starting user enrolment synchronisation...');
280    }
281
282    $instances = array(); // cache instances
283
284    $meta = enrol_get_plugin('meta');
285
286    $unenrolaction = $meta->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
287    $skiproles     = $meta->get_config('nosyncroleids', '');
288    $skiproles     = empty($skiproles) ? array() : explode(',', $skiproles);
289    $syncall       = $meta->get_config('syncall', 1);
290
291    $allroles = get_all_roles();
292
293
294    // Iterate through all not enrolled yet users. For each active enrolment of each user find the minimum
295    // enrolment startdate and maximum enrolment enddate.
296    // This SQL relies on the fact that ENROL_USER_ACTIVE < ENROL_USER_SUSPENDED
297    // and ENROL_INSTANCE_ENABLED < ENROL_INSTANCE_DISABLED. Condition "pue.status + pe.status = 0" means
298    // that enrolment is active. When MIN(pue.status + pe.status)=0 it means there exists an active
299    // enrolment.
300    $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
301    list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
302    $params['courseid'] = $courseid;
303    $sql = "SELECT pue.userid, e.id AS enrolid, MIN(pue.status + pe.status) AS status,
304                      MIN(CASE WHEN (pue.status + pe.status = 0) THEN pue.timestart ELSE 9999999999 END) AS timestart,
305                      MAX(CASE WHEN (pue.status + pe.status = 0) THEN
306                                (CASE WHEN pue.timeend = 0 THEN 9999999999 ELSE pue.timeend END)
307                                ELSE 0 END) AS timeend
308              FROM {user_enrolments} pue
309              JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled)
310              JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' $onecourse)
311              JOIN {user} u ON (u.id = pue.userid AND u.deleted = 0)
312         LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid)
313             WHERE ue.id IS NULL
314             GROUP BY pue.userid, e.id";
315
316    $rs = $DB->get_recordset_sql($sql, $params);
317    foreach($rs as $ue) {
318        if (!isset($instances[$ue->enrolid])) {
319            $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
320        }
321        $instance = $instances[$ue->enrolid];
322
323        if (!$syncall) {
324            // this may be slow if very many users are ignored in sync
325            $parentcontext = context_course::instance($instance->customint1);
326            list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
327            $params['contextid'] = $parentcontext->id;
328            $params['userid'] = $ue->userid;
329            $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
330            if (!$DB->record_exists_select('role_assignments', $select, $params)) {
331                // bad luck, this user does not have any role we want in parent course
332                if ($verbose) {
333                    mtrace("  skipping enrolling: $ue->userid ==> $instance->courseid (user without role)");
334                }
335                continue;
336            }
337        }
338
339        // So now we have aggregated values that we will use for the meta enrolment status, timeend and timestart.
340        // Again, we use the fact that active=0 and disabled/suspended=1. Only when MIN(pue.status + pe.status)=0 the enrolment is active:
341        $ue->status = ($ue->status == ENROL_USER_ACTIVE + ENROL_INSTANCE_ENABLED) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED;
342        // Timeend 9999999999 was used instead of 0 in the "MAX()" function:
343        $ue->timeend = ($ue->timeend == 9999999999) ? 0 : (int)$ue->timeend;
344        // Timestart 9999999999 is only possible when there are no active enrolments:
345        $ue->timestart = ($ue->timestart == 9999999999) ? 0 : (int)$ue->timestart;
346
347        $meta->enrol_user($instance, $ue->userid, null, $ue->timestart, $ue->timeend, $ue->status);
348        if ($instance->customint2) {
349            groups_add_member($instance->customint2, $ue->userid, 'enrol_meta', $instance->id);
350        }
351        if ($verbose) {
352            mtrace("  enrolling: $ue->userid ==> $instance->courseid");
353        }
354    }
355    $rs->close();
356
357
358    // unenrol as necessary - ignore enabled flag, we want to get rid of existing enrols in any case
359    $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
360    list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
361    $params['courseid'] = $courseid;
362    $sql = "SELECT ue.*
363              FROM {user_enrolments} ue
364              JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
365         LEFT JOIN ({user_enrolments} xpue
366                      JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
367                   ) ON (xpe.courseid = e.customint1 AND xpue.userid = ue.userid)
368             WHERE xpue.userid IS NULL";
369    $rs = $DB->get_recordset_sql($sql, $params);
370    foreach($rs as $ue) {
371        if (!isset($instances[$ue->enrolid])) {
372            $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
373        }
374        $instance = $instances[$ue->enrolid];
375
376        if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
377            $meta->unenrol_user($instance, $ue->userid);
378            if ($verbose) {
379                mtrace("  unenrolling: $ue->userid ==> $instance->courseid");
380            }
381
382        } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
383            if ($ue->status != ENROL_USER_SUSPENDED) {
384                $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
385                if ($verbose) {
386                    mtrace("  suspending: $ue->userid ==> $instance->courseid");
387                }
388            }
389
390        } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
391            if ($ue->status != ENROL_USER_SUSPENDED) {
392                $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
393                $context = context_course::instance($instance->courseid);
394                role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
395                if ($verbose) {
396                    mtrace("  suspending and removing all roles: $ue->userid ==> $instance->courseid");
397                }
398            }
399        }
400    }
401    $rs->close();
402
403
404    // Update status - meta enrols are ignored to avoid recursion.
405    // Note the trick here is that the active enrolment and instance constants have value 0.
406    $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
407    list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
408    $params['courseid'] = $courseid;
409    $sql = "SELECT ue.userid, ue.enrolid, pue.pstatus, pue.ptimestart, pue.ptimeend
410              FROM {user_enrolments} ue
411              JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
412              JOIN (SELECT xpue.userid, xpe.courseid, MIN(xpue.status + xpe.status) AS pstatus,
413                      MIN(CASE WHEN (xpue.status + xpe.status = 0) THEN xpue.timestart ELSE 9999999999 END) AS ptimestart,
414                      MAX(CASE WHEN (xpue.status + xpe.status = 0) THEN
415                                (CASE WHEN xpue.timeend = 0 THEN 9999999999 ELSE xpue.timeend END)
416                                ELSE 0 END) AS ptimeend
417                      FROM {user_enrolments} xpue
418                      JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
419                  GROUP BY xpue.userid, xpe.courseid
420                   ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid)
421             WHERE (pue.pstatus = 0 AND ue.status > 0) OR (pue.pstatus > 0 and ue.status = 0)
422             OR ((CASE WHEN pue.ptimestart = 9999999999 THEN 0 ELSE pue.ptimestart END) <> ue.timestart)
423             OR ((CASE WHEN pue.ptimeend = 9999999999 THEN 0 ELSE pue.ptimeend END) <> ue.timeend)";
424    $rs = $DB->get_recordset_sql($sql, $params);
425    foreach($rs as $ue) {
426        if (!isset($instances[$ue->enrolid])) {
427            $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
428        }
429        $instance = $instances[$ue->enrolid];
430        $ue->pstatus = ($ue->pstatus == ENROL_USER_ACTIVE + ENROL_INSTANCE_ENABLED) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED;
431        $ue->ptimeend = ($ue->ptimeend == 9999999999) ? 0 : (int)$ue->ptimeend;
432        $ue->ptimestart = ($ue->ptimestart == 9999999999) ? 0 : (int)$ue->ptimestart;
433
434        if ($ue->pstatus == ENROL_USER_ACTIVE and (!$ue->ptimeend || $ue->ptimeend > time())
435                and !$syncall and $unenrolaction != ENROL_EXT_REMOVED_UNENROL) {
436            // this may be slow if very many users are ignored in sync
437            $parentcontext = context_course::instance($instance->customint1);
438            list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
439            $params['contextid'] = $parentcontext->id;
440            $params['userid'] = $ue->userid;
441            $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
442            if (!$DB->record_exists_select('role_assignments', $select, $params)) {
443                // bad luck, this user does not have any role we want in parent course
444                if ($verbose) {
445                    mtrace("  skipping unsuspending: $ue->userid ==> $instance->courseid (user without role)");
446                }
447                continue;
448            }
449        }
450
451        $meta->update_user_enrol($instance, $ue->userid, $ue->pstatus, $ue->ptimestart, $ue->ptimeend);
452        if ($verbose) {
453            if ($ue->pstatus == ENROL_USER_ACTIVE) {
454                mtrace("  unsuspending: $ue->userid ==> $instance->courseid");
455            } else {
456                mtrace("  suspending: $ue->userid ==> $instance->courseid");
457            }
458        }
459    }
460    $rs->close();
461
462
463    // now assign all necessary roles
464    $enabled = explode(',', $CFG->enrol_plugins_enabled);
465    foreach($enabled as $k=>$v) {
466        if ($v === 'meta') {
467            continue; // no meta sync of meta roles
468        }
469        $enabled[$k] = 'enrol_'.$v;
470    }
471    $enabled[] = ''; // manual assignments are replicated too
472
473    $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
474    list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e');
475    $params['coursecontext'] = CONTEXT_COURSE;
476    $params['courseid'] = $courseid;
477    $params['activeuser'] = ENROL_USER_ACTIVE;
478    $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
479    $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid, e.courseid
480              FROM {role_assignments} pra
481              JOIN {user} u ON (u.id = pra.userid AND u.deleted = 0)
482              JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled)
483              JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' $onecourse AND e.status = :enabledinstance)
484              JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = u.id AND ue.status = :activeuser)
485              JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid)
486         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')
487             WHERE ra.id IS NULL";
488
489    if ($ignored = $meta->get_config('nosyncroleids')) {
490        list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
491        $params = array_merge($params, $xparams);
492        $sql = "$sql AND pra.roleid $notignored";
493    }
494
495    $rs = $DB->get_recordset_sql($sql, $params);
496    foreach($rs as $ra) {
497        role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid);
498        if ($verbose) {
499            mtrace("  assigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
500        }
501    }
502    $rs->close();
503
504
505    // remove unwanted roles - include ignored roles and disabled plugins too
506    $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
507    $params = array();
508    $params['coursecontext'] = CONTEXT_COURSE;
509    $params['courseid'] = $courseid;
510    $params['activeuser'] = ENROL_USER_ACTIVE;
511    $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
512    if ($ignored = $meta->get_config('nosyncroleids')) {
513        list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
514        $params = array_merge($params, $xparams);
515        $notignored = "AND pra.roleid $notignored";
516    } else {
517        $notignored = "";
518    }
519
520    $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid, e.courseid
521              FROM {role_assignments} ra
522              JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse)
523              JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext)
524         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)
525         LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid AND ue.status = :activeuser)
526             WHERE pra.id IS NULL OR ue.id IS NULL OR e.status <> :enabledinstance";
527
528    if ($unenrolaction != ENROL_EXT_REMOVED_SUSPEND) {
529        $rs = $DB->get_recordset_sql($sql, $params);
530        foreach($rs as $ra) {
531            role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid);
532            if ($verbose) {
533                mtrace("  unassigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
534            }
535        }
536        $rs->close();
537    }
538
539
540    // kick out or suspend users without synced roles if syncall disabled
541    if (!$syncall) {
542        if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
543            $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
544            $params = array();
545            $params['coursecontext'] = CONTEXT_COURSE;
546            $params['courseid'] = $courseid;
547            $sql = "SELECT ue.userid, ue.enrolid
548                      FROM {user_enrolments} ue
549                      JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
550                      JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
551                 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
552                     WHERE ra.id IS NULL";
553            $ues = $DB->get_recordset_sql($sql, $params);
554            foreach($ues as $ue) {
555                if (!isset($instances[$ue->enrolid])) {
556                    $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
557                }
558                $instance = $instances[$ue->enrolid];
559                $meta->unenrol_user($instance, $ue->userid);
560                if ($verbose) {
561                    mtrace("  unenrolling: $ue->userid ==> $instance->courseid (user without role)");
562                }
563            }
564            $ues->close();
565
566        } else {
567            // just suspend the users
568            $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
569            $params = array();
570            $params['coursecontext'] = CONTEXT_COURSE;
571            $params['courseid'] = $courseid;
572            $params['active'] = ENROL_USER_ACTIVE;
573            $sql = "SELECT ue.userid, ue.enrolid
574                      FROM {user_enrolments} ue
575                      JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
576                      JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
577                 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
578                     WHERE ra.id IS NULL AND ue.status = :active";
579            $ues = $DB->get_recordset_sql($sql, $params);
580            foreach($ues as $ue) {
581                if (!isset($instances[$ue->enrolid])) {
582                    $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
583                }
584                $instance = $instances[$ue->enrolid];
585                $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
586                if ($verbose) {
587                    mtrace("  suspending: $ue->userid ==> $instance->courseid (user without role)");
588                }
589            }
590            $ues->close();
591        }
592    }
593
594    // Finally sync groups.
595    $affectedusers = groups_sync_with_enrolment('meta', $courseid);
596    if ($verbose) {
597        foreach ($affectedusers['removed'] as $gm) {
598            mtrace("removing user from group: $gm->userid ==> $gm->courseid - $gm->groupname", 1);
599        }
600        foreach ($affectedusers['added'] as $ue) {
601            mtrace("adding user to group: $ue->userid ==> $ue->courseid - $ue->groupname", 1);
602        }
603    }
604
605    if ($verbose) {
606        mtrace('...user enrolment synchronisation finished.');
607    }
608
609    return 0;
610}
611
612/**
613 * Create a new group with the course's name.
614 *
615 * @param int $courseid
616 * @param int $linkedcourseid
617 * @return int $groupid Group ID for this cohort.
618 */
619function enrol_meta_create_new_group($courseid, $linkedcourseid) {
620    global $DB, $CFG;
621
622    require_once($CFG->dirroot.'/group/lib.php');
623
624    $coursename = $DB->get_field('course', 'fullname', array('id' => $linkedcourseid), MUST_EXIST);
625    $a = new stdClass();
626    $a->name = $coursename;
627    $a->increment = '';
628    $inc = 1;
629    $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a));
630    // Check to see if the group name already exists in this course. Add an incremented number if it does.
631    while ($DB->record_exists('groups', array('name' => $groupname, 'courseid' => $courseid))) {
632        $a->increment = '(' . (++$inc) . ')';
633        $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a));
634    }
635    // Create a new group for the course meta sync.
636    $groupdata = new stdClass();
637    $groupdata->courseid = $courseid;
638    $groupdata->name = $groupname;
639    $groupid = groups_create_group($groupdata);
640
641    return $groupid;
642}
Note: See TracBrowser for help on using the repository browser.