MDL-28348 fix spelling and some whitespace issues
[moodle.git] / enrol / meta / locallib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Local stuff for meta course enrolment plugin.
19  *
20  * @package    enrol
21  * @subpackage meta
22  * @copyright  2010 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
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  */
34 class enrol_meta_handler {
35     public function role_assigned($ra) {
36         global $DB;
38         if (!enrol_is_enabled('meta')) {
39             return true;
40         }
42         // prevent circular dependencies - we can not sync meta roles recursively
43         if ($ra->component === 'enrol_meta') {
44             return true;
45         }
47         // only course level roles are interesting
48         $parentcontext = get_context_instance_by_id($ra->contextid);
49         if ($parentcontext->contextlevel != CONTEXT_COURSE) {
50             return true;
51         }
53         // does anything want to sync with this parent?
54         if (!$enrols = $DB->get_records('enrol', array('customint1'=>$parentcontext->instanceid, 'enrol'=>'meta'), 'id ASC')) {
55             return true;
56         }
58         // make sure the role sync is not prevented
59         $plugin = enrol_get_plugin('meta');
60         if ($disabled = $plugin->get_config('nosyncroleids')) {
61             if (in_array($ra->roleid, explode(',', $disabled))) {
62                 return true;
63             }
64         }
66         foreach ($enrols as $enrol) {
67             // Is the user enrolled? We want to sync only really enrolled users
68             if (!$DB->record_exists('user_enrolments', array('userid'=>$ra->userid, 'enrolid'=>$enrol->id))) {
69                 continue;
70             }
71             $context = get_context_instance(CONTEXT_COURSE, $enrol->courseid);
73             // just try to assign role, no problem if role assignment already exists
74             role_assign($ra->roleid, $ra->userid, $context->id, 'enrol_meta', $enrol->id);
75         }
77         return true;
78     }
80     public function role_unassigned($ra) {
81         global $DB;
83         // note: do not test if plugin enabled, we want to keep removing previous roles
85         // prevent circular dependencies - we can not sync meta roles recursively
86         if ($ra->component === 'enrol_meta') {
87             return true;
88         }
90         // only course level roles are interesting
91         $parentcontext = get_context_instance_by_id($ra->contextid);
92         if ($parentcontext->contextlevel != CONTEXT_COURSE) {
93             return true;
94         }
96         // does anything want to sync with this parent?
97         if (!$enrols = $DB->get_records('enrol', array('customint1'=>$parentcontext->instanceid, 'enrol'=>'meta'), 'id ASC')) {
98             return true;
99         }
101         // note: do not check 'nosyncroleids', somebody might have just enabled it, we want to get rid of nosync roles gradually
103         foreach ($enrols as $enrol) {
104             // Is the user enrolled? We want to sync only really enrolled users
105             if (!$DB->record_exists('user_enrolments', array('userid'=>$ra->userid, 'enrolid'=>$enrol->id))) {
106                 continue;
107             }
108             $context = get_context_instance(CONTEXT_COURSE, $enrol->courseid);
110             // now make sure the user does not have the role through some other enrol plugin
111             $params = array('contextid'=>$ra->contextid, 'roleid'=>$ra->roleid, 'userid'=>$ra->userid);
112             if ($DB->record_exists_select('role_assignments', "contextid = :contextid AND roleid = :roleid AND userid = :userid AND component <> 'enrol_meta'", $params)) {
113                 continue;
114             }
116             // unassign role, there is no other role assignment in parent course
117             role_unassign($ra->roleid, $ra->userid, $context->id, 'enrol_meta', $enrol->id);
118         }
120         return true;
121     }
123     public function user_enrolled($ue) {
124         global $DB;
126         if (!enrol_is_enabled('meta')) {
127             return true;
128         }
130         if ($ue->enrol === 'meta') {
131             // prevent circular dependencies - we can not sync meta enrolments recursively
132             return true;
133         }
135         // does anything want to sync with this parent?
136         if (!$enrols = $DB->get_records('enrol', array('customint1'=>$ue->courseid, 'enrol'=>'meta'), 'id ASC')) {
137             return true;
138         }
140         $plugin = enrol_get_plugin('meta');
141         foreach ($enrols as $enrol) {
142             // no problem if already enrolled
143             $plugin->enrol_user($enrol, $ue->userid);
144         }
146         return true;
147     }
149     public function user_unenrolled($ue) {
150         global $DB;
152         //note: do not test if plugin enabled, we want to keep removing previously linked courses
154         // look for unenrolment candidates - it may be possible that user has multiple enrolments...
155         $sql = "SELECT e.*
156                   FROM {enrol} e
157                   JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)
158                   JOIN {enrol} pe ON (pe.courseid = e.customint1 AND pe.enrol <> 'meta' AND pe.courseid = :courseid)
159              LEFT JOIN {user_enrolments} pue ON (pue.enrolid = pe.id AND pue.userid = ue.userid)
160                  WHERE pue.id IS NULL AND e.enrol = 'meta'";
161         $params = array('courseid'=>$ue->courseid, 'userid'=>$ue->userid);
163         $rs = $DB->get_recordset_sql($sql, $params);
165         $plugin = enrol_get_plugin('meta');
166         foreach ($rs as $enrol) {
167             $plugin->unenrol_user($enrol, $ue->userid);
168         }
169         $rs->close();
171         return true;
172     }
174     public function course_deleted($course) {
175         global $DB;
177         // note: do not test if plugin enabled, we want to keep removing previously linked courses
179         // does anything want to sync with this parent?
180         if (!$enrols = $DB->get_records('enrol', array('customint1'=>$course->id, 'enrol'=>'meta'), 'id ASC')) {
181             return true;
182         }
184         $plugin = enrol_get_plugin('meta');
185         foreach ($enrols as $enrol) {
186             // unenrol all users
187             $ues = $DB->get_recordset('user_enrolments', array('enrolid'=>$enrol->id));
188             foreach ($ues as $ue) {
189                 $plugin->unenrol_user($enrol, $ue->userid);
190             }
191             $ues->close();
192         }
194         return true;
195     }
199 /**
200  * Sync all meta course links.
201  * @param int $courseid one course, empty mean all
202  * @return void
203  */
204 function enrol_meta_sync($courseid = NULL) {
205     global $CFG, $DB;
207     // unfortunately this may take a loooong time
208     @set_time_limit(0); //if this fails during upgrade we can continue from cron, no big deal
210     $meta = enrol_get_plugin('meta');
212     $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
214     // iterate through all not enrolled yet users
215     if (enrol_is_enabled('meta')) {
216         list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
217         $onecourse = "";
218         if ($courseid) {
219             $params['courseid'] = $courseid;
220             $onecourse = "AND e.courseid = :courseid";
221         }
222         $sql = "SELECT pue.userid, e.id AS enrolid
223                   FROM {user_enrolments} pue
224                   JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled )
225                   JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' AND e.status = :statusenabled $onecourse)
226              LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid)
227                  WHERE ue.id IS NULL";
228         $params['statusenabled'] = ENROL_INSTANCE_ENABLED;
229         $params['courseid'] = $courseid;
231         $rs = $DB->get_recordset_sql($sql, $params);
232         $instances = array(); //cache
233         foreach($rs as $ue) {
234             if (!isset($instances[$ue->enrolid])) {
235                 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
236             }
237             $meta->enrol_user($instances[$ue->enrolid], $ue->userid);
238         }
239         $rs->close();
240         unset($instances);
241     }
243     // unenrol as necessary - ignore enabled flag, we want to get rid of all
244     $sql = "SELECT ue.userid, e.id AS enrolid
245               FROM {user_enrolments} ue
246               JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
247          LEFT JOIN (SELECT xue.userid, xe.courseid
248                       FROM {enrol} xe
249                       JOIN {user_enrolments} xue ON (xue.enrolid = xe.id)
250                    ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid)
251              WHERE pue.courseid IS NULL";
252     //TODO: this may use a bit of SQL optimisation
253     $rs = $DB->get_recordset_sql($sql, array('courseid'=>$courseid));
254     $instances = array(); //cache
255     foreach($rs as $ue) {
256         if (!isset($instances[$ue->enrolid])) {
257             $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
258         }
259         $meta->unenrol_user($instances[$ue->enrolid], $ue->userid);
260     }
261     $rs->close();
262     unset($instances);
264     // now assign all necessary roles
265     if (enrol_is_enabled('meta')) {
266         $enabled = explode(',', $CFG->enrol_plugins_enabled);
267         foreach($enabled as $k=>$v) {
268             if ($v === 'meta') {
269                 continue; // no meta sync of meta roles
270             }
271             $enabled[$k] = 'enrol_'.$v;
272         }
273         $enabled[] = $DB->sql_empty(); // manual assignments are replicated too
275         list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e');
276         $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid
277                   FROM {role_assignments} pra
278                   JOIN {user} u ON (u.id = pra.userid AND u.deleted = 0)
279                   JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled)
280                   JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' AND e.status = :statusenabled $onecourse)
281                   JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid)
282              LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = pra.userid AND ra.roleid = pra.itemid AND ra.itemid = e.id AND ra.component = 'enrol_meta')
283                  WHERE ra.id IS NULL";
284         $params['statusenabled'] = ENROL_INSTANCE_ENABLED;
285         $params['coursecontext'] = CONTEXT_COURSE;
286         $params['courseid'] = $courseid;
288         if ($ignored = $meta->get_config('nosyncroleids')) {
289             list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
290             $params = array_merge($params, $xparams);
291             $sql = "$sql AND pra.roleid $notignored";
292         }
294         $rs = $DB->get_recordset_sql($sql, $params);
295         foreach($rs as $ra) {
296             role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid);
297         }
298         $rs->close();
299     }
301     // remove unwanted roles - include ignored roles and disabled plugins too
302     $params = array('coursecontext' => CONTEXT_COURSE, 'courseid' => $courseid);
303     if ($ignored = $meta->get_config('nosyncroleids')) {
304         list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
305         $params = array_merge($params, $xparams);
306         $notignored = "AND pra.roleid $notignored";
307     } else {
308         $notignored = "";
309     }
310     $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid
311               FROM {role_assignments} ra
312               JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse)
313               JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext)
314          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)
315              WHERE pra.id IS NULL";
317     $rs = $DB->get_recordset_sql($sql, $params);
318     foreach($rs as $ra) {
319         role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid);
320     }
321     $rs->close();