AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Local stuff for category enrolment plugin.** @package enrol_category* @copyright 2010 Petr Skoda {@link http://skodak.org}* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/defined('MOODLE_INTERNAL') || die();/*** Sync all category enrolments in one course* @param stdClass $course* @return void*/function enrol_category_sync_course($course) {global $DB;if (!enrol_is_enabled('category')) {return;}$plugin = enrol_get_plugin('category');$syscontext = context_system::instance();$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);if (!$roles) {// Nothing to sync, so remove the instance completely if exists.if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {foreach ($instances as $instance) {$plugin->delete_instance($instance);}}return;}// First find out if any parent category context contains interesting role assignments.$coursecontext = context_course::instance($course->id);$contextids = $coursecontext->get_parent_context_ids();array_pop($contextids); // Remove system context, we are interested in categories only.list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c');$params = array_merge($params, $contextparams);$params['courseid'] = $course->id;$sql = "SELECT 'x'FROM {role_assignments}WHERE roleid $roleids AND contextid $contextids";if (!$DB->record_exists_sql($sql, $params)) {if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {// Should be max one instance, but anyway.foreach ($instances as $instance) {$plugin->delete_instance($instance);}}return;}// Make sure the enrol instance exists - there should be always only one instance.$delinstances = array();if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {$instance = array_shift($instances);$delinstances = $instances;} else {$i = $plugin->add_instance($course);$instance = $DB->get_record('enrol', array('id'=>$i));}// Add new enrolments.$sql = "SELECT ra.userid, ra.estartFROM (SELECT xra.userid, MIN(xra.timemodified) AS estartFROM {role_assignments} xraJOIN {user} xu ON (xu.id = xra.userid AND xu.deleted = 0)WHERE xra.roleid $roleids AND xra.contextid $contextidsGROUP BY xra.userid) raLEFT JOIN {user_enrolments} ue ON (ue.enrolid = :instanceid AND ue.userid = ra.userid)WHERE ue.id IS NULL";$params['instanceid'] = $instance->id;$rs = $DB->get_recordset_sql($sql, $params);foreach ($rs as $ra) {$plugin->enrol_user($instance, $ra->userid, null, $ra->estart);}$rs->close();// Remove unwanted enrolments.$sql = "SELECT DISTINCT ue.useridFROM {user_enrolments} ueLEFT JOIN {role_assignments} ra ON (ra.roleid $roleids AND ra.contextid $contextids AND ra.userid = ue.userid)WHERE ue.enrolid = :instanceid AND ra.id IS NULL";$rs = $DB->get_recordset_sql($sql, $params);foreach ($rs as $ra) {$plugin->unenrol_user($instance, $ra->userid);}$rs->close();if ($delinstances) {// We have to do this as the last step in order to prevent temporary unenrolment.foreach ($delinstances as $delinstance) {$plugin->delete_instance($delinstance);}}}/*** Synchronise courses in all categories.** It gets out-of-sync if:* - you move course to different category* - reorder categories* - disable enrol_category and enable it again** @param progress_trace $trace* @return int exit code - 0 is ok, 1 means error, 2 if plugin disabled*/function enrol_category_sync_full(progress_trace $trace) {global $DB;if (!enrol_is_enabled('category')) {$trace->finished();return 2;}// We may need a lot of time here.core_php_time_limit::raise();$plugin = enrol_get_plugin('category');$syscontext = context_system::instance();// Any interesting roles worth synchronising?if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {// yay, nothing to do, so let's remove all leftovers$trace->output("No roles with 'enrol/category:synchronised' capability found.");if ($instances = $DB->get_records('enrol', array('enrol'=>'category'))) {$trace->output("Deleting all category enrol instances...");foreach ($instances as $instance) {$trace->output("deleting category enrol instance from course {$instance->courseid}", 1);$plugin->delete_instance($instance);}$trace->output("...all instances deleted.");}$trace->finished();return 0;}$rolenames = role_fix_names($roles, null, ROLENAME_SHORT, true);$trace->output('Synchronising category enrolments for roles: '.implode(', ', $rolenames).'...');list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');$params['courselevel'] = CONTEXT_COURSE;$params['catlevel'] = CONTEXT_COURSECAT;// First of all add necessary enrol instances to all courses.$parentcat = $DB->sql_concat("cat.path", "'/%'");$parentcctx = $DB->sql_concat("cctx.path", "'/%'");// Need whole course records to be used by add_instance(), use inner view (ci) to// get distinct records only.// TODO: Moodle 2.1. Improve enrol API to accept courseid / courserec$sql = "SELECT c.*FROM {course} cJOIN (SELECT DISTINCT c.idFROM {course} cJOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel)JOIN (SELECT DISTINCT cctx.pathFROM {course_categories} ccJOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)) cat ON (ctx.path LIKE $parentcat)LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category')WHERE e.id IS NULL) ci ON (c.id = ci.id)";$rs = $DB->get_recordset_sql($sql, $params);foreach($rs as $course) {$plugin->add_instance($course);}$rs->close();// Now look for courses that do not have any interesting roles in parent contexts,// but still have the instance and delete them.$sql = "SELECT e.*FROM {enrol} eJOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)LEFT JOIN ({course_categories} ccJOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)) ON (ctx.path LIKE $parentcctx)WHERE e.enrol = 'category' AND cc.id IS NULL";$rs = $DB->get_recordset_sql($sql, $params);foreach($rs as $instance) {$plugin->delete_instance($instance);}$rs->close();// Add missing enrolments.$sql = "SELECT e.*, cat.userid, cat.estartFROM {enrol} eJOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)JOIN (SELECT cctx.path, ra.userid, MIN(ra.timemodified) AS estartFROM {course_categories} ccJOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)GROUP BY cctx.path, ra.userid) cat ON (ctx.path LIKE $parentcat)LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = cat.userid)WHERE e.enrol = 'category' AND ue.id IS NULL";$rs = $DB->get_recordset_sql($sql, $params);foreach($rs as $instance) {$userid = $instance->userid;$estart = $instance->estart;unset($instance->userid);unset($instance->estart);$plugin->enrol_user($instance, $userid, null, $estart);$trace->output("enrolling: user $userid ==> course $instance->courseid", 1);}$rs->close();// Remove stale enrolments.$sql = "SELECT e.*, ue.useridFROM {enrol} eJOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)JOIN {user_enrolments} ue ON (ue.enrolid = e.id)LEFT JOIN ({course_categories} ccJOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)) ON (ctx.path LIKE $parentcctx AND ra.userid = ue.userid)WHERE e.enrol = 'category' AND cc.id IS NULL";$rs = $DB->get_recordset_sql($sql, $params);foreach($rs as $instance) {$userid = $instance->userid;unset($instance->userid);$plugin->unenrol_user($instance, $userid);$trace->output("unenrolling: user $userid ==> course $instance->courseid", 1);}$rs->close();$trace->output('...user enrolment synchronisation finished.');$trace->finished();return 0;}