|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00027 defined('MOODLE_INTERNAL') || die(); 00028 00035 class enrol_category_handler { 00036 public function role_assigned($ra) { 00037 global $DB; 00038 00039 if (!enrol_is_enabled('category')) { 00040 return true; 00041 } 00042 00043 //only category level roles are interesting 00044 $parentcontext = get_context_instance_by_id($ra->contextid); 00045 if ($parentcontext->contextlevel != CONTEXT_COURSECAT) { 00046 return true; 00047 } 00048 00049 // make sure the role is to be actually synchronised 00050 // please note we are ignoring overrides of the synchronised capability (for performance reasons in full sync) 00051 $syscontext = get_context_instance(CONTEXT_SYSTEM); 00052 if (!$DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$ra->roleid, 'capability'=>'enrol/category:synchronised', 'permission'=>CAP_ALLOW))) { 00053 return true; 00054 } 00055 00056 // add necessary enrol instances 00057 $plugin = enrol_get_plugin('category'); 00058 $sql = "SELECT c.* 00059 FROM {course} c 00060 JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match) 00061 LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') 00062 WHERE e.id IS NULL"; 00063 $params = array('courselevel'=>CONTEXT_COURSE, 'match'=>$parentcontext->path.'/%'); 00064 $rs = $DB->get_recordset_sql($sql, $params); 00065 foreach ($rs as $course) { 00066 $plugin->add_instance($course); 00067 } 00068 $rs->close(); 00069 00070 // now look for missing enrols 00071 $sql = "SELECT e.* 00072 FROM {course} c 00073 JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match) 00074 JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') 00075 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid) 00076 WHERE ue.id IS NULL"; 00077 $params = array('courselevel'=>CONTEXT_COURSE, 'match'=>$parentcontext->path.'/%', 'userid'=>$ra->userid); 00078 $rs = $DB->get_recordset_sql($sql, $params); 00079 foreach ($rs as $instance) { 00080 $plugin->enrol_user($instance, $ra->userid, null, $ra->timemodified); 00081 } 00082 $rs->close(); 00083 00084 return true; 00085 } 00086 00087 public function role_unassigned($ra) { 00088 global $DB; 00089 00090 if (!enrol_is_enabled('category')) { 00091 return true; 00092 } 00093 00094 // only category level roles are interesting 00095 $parentcontext = get_context_instance_by_id($ra->contextid); 00096 if ($parentcontext->contextlevel != CONTEXT_COURSECAT) { 00097 return true; 00098 } 00099 00100 // now this is going to be a bit slow, take all enrolments in child courses and verify each separately 00101 $syscontext = get_context_instance(CONTEXT_SYSTEM); 00102 if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) { 00103 return true; 00104 } 00105 00106 $plugin = enrol_get_plugin('category'); 00107 00108 $sql = "SELECT e.* 00109 FROM {course} c 00110 JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match) 00111 JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') 00112 JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)"; 00113 $params = array('courselevel'=>CONTEXT_COURSE, 'match'=>$parentcontext->path.'/%', 'userid'=>$ra->userid); 00114 $rs = $DB->get_recordset_sql($sql, $params); 00115 00116 list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r'); 00117 $params['userid'] = $ra->userid; 00118 00119 foreach ($rs as $instance) { 00120 $coursecontext = get_context_instance(CONTEXT_COURSE, $instance->courseid); 00121 $contextids = get_parent_contexts($coursecontext); 00122 array_pop($contextids); // remove system context, we are interested in categories only 00123 00124 list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c'); 00125 $params = array_merge($params, $contextparams); 00126 00127 $sql = "SELECT ra.id 00128 FROM {role_assignments} ra 00129 WHERE ra.userid = :userid AND ra.contextid $contextids AND ra.roleid $roleids"; 00130 if (!$DB->record_exists_sql($sql, $params)) { 00131 // user does not have any interesting role in any parent context, let's unenrol 00132 $plugin->unenrol_user($instance, $ra->userid); 00133 } 00134 } 00135 $rs->close(); 00136 00137 return true; 00138 } 00139 } 00140 00146 function enrol_category_sync_course($course) { 00147 global $DB; 00148 00149 if (!enrol_is_enabled('category')) { 00150 return; 00151 } 00152 00153 $plugin = enrol_get_plugin('category'); 00154 00155 $syscontext = get_context_instance(CONTEXT_SYSTEM); 00156 $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext); 00157 00158 if (!$roles) { 00159 //nothing to sync, so remove the instance completely if exists 00160 if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) { 00161 foreach ($instances as $instance) { 00162 $plugin->delete_instance($instance); 00163 } 00164 } 00165 return; 00166 } 00167 00168 // first find out if any parent category context contains interesting role assignments 00169 $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); 00170 $contextids = get_parent_contexts($coursecontext); 00171 array_pop($contextids); // remove system context, we are interested in categories only 00172 00173 list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r'); 00174 list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c'); 00175 $params = array_merge($params, $contextparams); 00176 $params['courseid'] = $course->id; 00177 00178 $sql = "SELECT 'x' 00179 FROM {role_assignments} 00180 WHERE roleid $roleids AND contextid $contextids"; 00181 if (!$DB->record_exists_sql($sql, $params)) { 00182 if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) { 00183 // should be max one instance, but anyway 00184 foreach ($instances as $instance) { 00185 $plugin->delete_instance($instance); 00186 } 00187 } 00188 return; 00189 } 00190 00191 // make sure the enrol instance exists - there should be always only one instance 00192 $delinstances = array(); 00193 if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) { 00194 $instance = array_shift($instances); 00195 $delinstances = $instances; 00196 } else { 00197 $i = $plugin->add_instance($course); 00198 $instance = $DB->get_record('enrol', array('id'=>$i)); 00199 } 00200 00201 // add new enrolments 00202 $sql = "SELECT ra.userid, ra.estart 00203 FROM (SELECT xra.userid, MIN(xra.timemodified) AS estart 00204 FROM {role_assignments} xra 00205 WHERE xra.roleid $roleids AND xra.contextid $contextids 00206 GROUP BY xra.userid 00207 ) ra 00208 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = :instanceid AND ue.userid = ra.userid) 00209 WHERE ue.id IS NULL"; 00210 $params['instanceid'] = $instance->id; 00211 $rs = $DB->get_recordset_sql($sql, $params); 00212 foreach ($rs as $ra) { 00213 $plugin->enrol_user($instance, $ra->userid, null, $ra->estart); 00214 } 00215 $rs->close(); 00216 00217 // remove unwanted enrolments 00218 $sql = "SELECT DISTINCT ue.userid 00219 FROM {user_enrolments} ue 00220 LEFT JOIN {role_assignments} ra ON (ra.roleid $roleids AND ra.contextid $contextids AND ra.userid = ue.userid) 00221 WHERE ue.enrolid = :instanceid AND ra.id IS NULL"; 00222 $rs = $DB->get_recordset_sql($sql, $params); 00223 foreach ($rs as $ra) { 00224 $plugin->unenrol_user($instance, $ra->userid); 00225 } 00226 $rs->close(); 00227 00228 if ($delinstances) { 00229 // we have to do this as the last step in order to prevent temporary unenrolment 00230 foreach ($delinstances as $delinstance) { 00231 $plugin->delete_instance($delinstance); 00232 } 00233 } 00234 } 00235 00236 function enrol_category_sync_full() { 00237 global $DB; 00238 00239 00240 if (!enrol_is_enabled('category')) { 00241 return; 00242 } 00243 00244 // we may need a lot of time here 00245 @set_time_limit(0); 00246 00247 $plugin = enrol_get_plugin('category'); 00248 00249 $syscontext = get_context_instance(CONTEXT_SYSTEM); 00250 00251 // any interesting roles worth synchronising? 00252 if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) { 00253 // yay, nothing to do, so let's remove all leftovers 00254 if ($instances = $DB->get_records('enrol', array('enrol'=>'category'))) { 00255 foreach ($instances as $instance) { 00256 $plugin->delete_instance($instance); 00257 } 00258 } 00259 return; 00260 } 00261 00262 list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r'); 00263 $params['courselevel'] = CONTEXT_COURSE; 00264 $params['catlevel'] = CONTEXT_COURSECAT; 00265 00266 // first of all add necessary enrol instances to all courses 00267 $parentcat = $DB->sql_concat("cat.path", "'/%'"); 00268 // need whole course records to be used by add_instance(), use inner view (ci) to 00269 // get distinct records only. 00270 // TODO: Moodle 2.1. Improve enrol API to accept courseid / courserec 00271 $sql = "SELECT c.* 00272 FROM {course} c 00273 JOIN ( 00274 SELECT DISTINCT c.id 00275 FROM {course} c 00276 JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel) 00277 JOIN (SELECT DISTINCT cctx.path 00278 FROM {course_categories} cc 00279 JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) 00280 JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) 00281 ) cat ON (ctx.path LIKE $parentcat) 00282 LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category') 00283 WHERE e.id IS NULL) ci ON (c.id = ci.id)"; 00284 00285 $rs = $DB->get_recordset_sql($sql, $params); 00286 foreach($rs as $course) { 00287 $plugin->add_instance($course); 00288 } 00289 $rs->close(); 00290 00291 // now look for courses that do not have any interesting roles in parent contexts, 00292 // but still have the instance and delete them 00293 $sql = "SELECT e.* 00294 FROM {enrol} e 00295 JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel) 00296 LEFT JOIN (SELECT DISTINCT cctx.path 00297 FROM {course_categories} cc 00298 JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) 00299 JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) 00300 ) cat ON (ctx.path LIKE $parentcat) 00301 WHERE e.enrol = 'category' AND cat.path IS NULL"; 00302 00303 $rs = $DB->get_recordset_sql($sql, $params); 00304 foreach($rs as $instance) { 00305 $plugin->delete_instance($instance); 00306 } 00307 $rs->close(); 00308 00309 // add missing enrolments 00310 $sql = "SELECT e.*, cat.userid, cat.estart 00311 FROM {enrol} e 00312 JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel) 00313 JOIN (SELECT cctx.path, ra.userid, MIN(ra.timemodified) AS estart 00314 FROM {course_categories} cc 00315 JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) 00316 JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) 00317 GROUP BY cctx.path, ra.userid 00318 ) cat ON (ctx.path LIKE $parentcat) 00319 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = cat.userid) 00320 WHERE e.enrol = 'category' AND ue.id IS NULL"; 00321 $rs = $DB->get_recordset_sql($sql, $params); 00322 foreach($rs as $instance) { 00323 $userid = $instance->userid; 00324 $estart = $instance->estart; 00325 unset($instance->userid); 00326 unset($instance->estart); 00327 $plugin->enrol_user($instance, $userid, null, $estart); 00328 } 00329 $rs->close(); 00330 00331 // remove stale enrolments 00332 $sql = "SELECT e.*, ue.userid 00333 FROM {enrol} e 00334 JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel) 00335 JOIN {user_enrolments} ue ON (ue.enrolid = e.id) 00336 LEFT JOIN (SELECT DISTINCT cctx.path, ra.userid 00337 FROM {course_categories} cc 00338 JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel) 00339 JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids) 00340 ) cat ON (ctx.path LIKE $parentcat AND cat.userid = ue.userid) 00341 WHERE e.enrol = 'category' AND cat.userid IS NULL"; 00342 $rs = $DB->get_recordset_sql($sql, $params); 00343 foreach($rs as $instance) { 00344 $userid = $instance->userid; 00345 unset($instance->userid); 00346 $plugin->unenrol_user($instance, $userid); 00347 } 00348 $rs->close(); 00349 }