Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/enrol/category/locallib.php
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Enumerations