Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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 category enrolment plugin.
19
 *
20
 * @package    enrol_category
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
 
25
defined('MOODLE_INTERNAL') || die();
26
 
27
/**
28
 * Sync all category enrolments in one course
29
 * @param stdClass $course
30
 * @return void
31
 */
32
function enrol_category_sync_course($course) {
33
    global $DB;
34
 
35
    if (!enrol_is_enabled('category')) {
36
        return;
37
    }
38
 
39
    $plugin = enrol_get_plugin('category');
40
 
41
    $syscontext = context_system::instance();
42
    $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
43
 
44
    if (!$roles) {
45
        // Nothing to sync, so remove the instance completely if exists.
46
        if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
47
            foreach ($instances as $instance) {
48
                $plugin->delete_instance($instance);
49
            }
50
        }
51
        return;
52
    }
53
 
54
    // First find out if any parent category context contains interesting role assignments.
55
    $coursecontext = context_course::instance($course->id);
56
    $contextids = $coursecontext->get_parent_context_ids();
57
    array_pop($contextids); // Remove system context, we are interested in categories only.
58
 
59
    list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');
60
    list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c');
61
    $params = array_merge($params, $contextparams);
62
    $params['courseid'] = $course->id;
63
 
64
    $sql = "SELECT 'x'
65
              FROM {role_assignments}
66
             WHERE roleid $roleids AND contextid $contextids";
67
    if (!$DB->record_exists_sql($sql, $params)) {
68
        if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
69
            // Should be max one instance, but anyway.
70
            foreach ($instances as $instance) {
71
                $plugin->delete_instance($instance);
72
            }
73
        }
74
        return;
75
    }
76
 
77
    // Make sure the enrol instance exists - there should be always only one instance.
78
    $delinstances = array();
79
    if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
80
        $instance = array_shift($instances);
81
        $delinstances = $instances;
82
    } else {
83
        $i = $plugin->add_instance($course);
84
        $instance = $DB->get_record('enrol', array('id'=>$i));
85
    }
86
 
87
    // Add new enrolments.
88
    $sql = "SELECT ra.userid, ra.estart
89
              FROM (SELECT xra.userid, MIN(xra.timemodified) AS estart
90
                      FROM {role_assignments} xra
91
                      JOIN {user} xu ON (xu.id = xra.userid AND xu.deleted = 0)
92
                     WHERE xra.roleid $roleids AND xra.contextid $contextids
93
                  GROUP BY xra.userid
94
                   ) ra
95
         LEFT JOIN {user_enrolments} ue ON (ue.enrolid = :instanceid AND ue.userid = ra.userid)
96
             WHERE ue.id IS NULL";
97
    $params['instanceid'] = $instance->id;
98
    $rs = $DB->get_recordset_sql($sql, $params);
99
    foreach ($rs as $ra) {
100
        $plugin->enrol_user($instance, $ra->userid, null, $ra->estart);
101
    }
102
    $rs->close();
103
 
104
    // Remove unwanted enrolments.
105
    $sql = "SELECT DISTINCT ue.userid
106
              FROM {user_enrolments} ue
107
         LEFT JOIN {role_assignments} ra ON (ra.roleid $roleids AND ra.contextid $contextids AND ra.userid = ue.userid)
108
             WHERE ue.enrolid = :instanceid AND ra.id IS NULL";
109
    $rs = $DB->get_recordset_sql($sql, $params);
110
    foreach ($rs as $ra) {
111
        $plugin->unenrol_user($instance, $ra->userid);
112
    }
113
    $rs->close();
114
 
115
    if ($delinstances) {
116
        // We have to do this as the last step in order to prevent temporary unenrolment.
117
        foreach ($delinstances as $delinstance) {
118
            $plugin->delete_instance($delinstance);
119
        }
120
    }
121
}
122
 
123
/**
124
 * Synchronise courses in all categories.
125
 *
126
 * It gets out-of-sync if:
127
 * - you move course to different category
128
 * - reorder categories
129
 * - disable enrol_category and enable it again
130
 *
131
 * @param progress_trace $trace
132
 * @return int exit code - 0 is ok, 1 means error, 2 if plugin disabled
133
 */
134
function enrol_category_sync_full(progress_trace $trace) {
135
    global $DB;
136
 
137
 
138
    if (!enrol_is_enabled('category')) {
139
        $trace->finished();
140
        return 2;
141
    }
142
 
143
    // We may need a lot of time here.
144
    core_php_time_limit::raise();
145
 
146
    $plugin = enrol_get_plugin('category');
147
 
148
    $syscontext = context_system::instance();
149
 
150
    // Any interesting roles worth synchronising?
151
    if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {
152
        // yay, nothing to do, so let's remove all leftovers
153
        $trace->output("No roles with 'enrol/category:synchronised' capability found.");
154
        if ($instances = $DB->get_records('enrol', array('enrol'=>'category'))) {
155
            $trace->output("Deleting all category enrol instances...");
156
            foreach ($instances as $instance) {
157
                $trace->output("deleting category enrol instance from course {$instance->courseid}", 1);
158
                $plugin->delete_instance($instance);
159
            }
160
            $trace->output("...all instances deleted.");
161
        }
162
        $trace->finished();
163
        return 0;
164
    }
165
    $rolenames = role_fix_names($roles, null, ROLENAME_SHORT, true);
166
    $trace->output('Synchronising category enrolments for roles: '.implode(', ', $rolenames).'...');
167
 
168
    list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');
169
    $params['courselevel'] = CONTEXT_COURSE;
170
    $params['catlevel'] = CONTEXT_COURSECAT;
171
 
172
    // First of all add necessary enrol instances to all courses.
173
    $parentcat = $DB->sql_concat("cat.path", "'/%'");
174
    $parentcctx = $DB->sql_concat("cctx.path", "'/%'");
175
    // Need whole course records to be used by add_instance(), use inner view (ci) to
176
    // get distinct records only.
177
    // TODO: Moodle 2.1. Improve enrol API to accept courseid / courserec
178
    $sql = "SELECT c.*
179
              FROM {course} c
180
              JOIN (
181
                SELECT DISTINCT c.id
182
                  FROM {course} c
183
                  JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel)
184
                  JOIN (SELECT DISTINCT cctx.path
185
                          FROM {course_categories} cc
186
                          JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
187
                          JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
188
                       ) cat ON (ctx.path LIKE $parentcat)
189
             LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'category')
190
                 WHERE e.id IS NULL) ci ON (c.id = ci.id)";
191
 
192
    $rs = $DB->get_recordset_sql($sql, $params);
193
    foreach($rs as $course) {
194
        $plugin->add_instance($course);
195
    }
196
    $rs->close();
197
 
198
    // Now look for courses that do not have any interesting roles in parent contexts,
199
    // but still have the instance and delete them.
200
    $sql = "SELECT e.*
201
              FROM {enrol} e
202
              JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
203
         LEFT JOIN ({course_categories} cc
204
                      JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
205
                      JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
206
                   ) ON (ctx.path LIKE $parentcctx)
207
             WHERE e.enrol = 'category' AND cc.id IS NULL";
208
 
209
    $rs = $DB->get_recordset_sql($sql, $params);
210
    foreach($rs as $instance) {
211
        $plugin->delete_instance($instance);
212
    }
213
    $rs->close();
214
 
215
    // Add missing enrolments.
216
    $sql = "SELECT e.*, cat.userid, cat.estart
217
              FROM {enrol} e
218
              JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
219
              JOIN (SELECT cctx.path, ra.userid, MIN(ra.timemodified) AS estart
220
                      FROM {course_categories} cc
221
                      JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
222
                      JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
223
                  GROUP BY cctx.path, ra.userid
224
                   ) cat ON (ctx.path LIKE $parentcat)
225
         LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = cat.userid)
226
             WHERE e.enrol = 'category' AND ue.id IS NULL";
227
    $rs = $DB->get_recordset_sql($sql, $params);
228
    foreach($rs as $instance) {
229
        $userid = $instance->userid;
230
        $estart = $instance->estart;
231
        unset($instance->userid);
232
        unset($instance->estart);
233
        $plugin->enrol_user($instance, $userid, null, $estart);
234
        $trace->output("enrolling: user $userid ==> course $instance->courseid", 1);
235
    }
236
    $rs->close();
237
 
238
    // Remove stale enrolments.
239
    $sql = "SELECT e.*, ue.userid
240
              FROM {enrol} e
241
              JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
242
              JOIN {user_enrolments} ue ON (ue.enrolid = e.id)
243
         LEFT JOIN ({course_categories} cc
244
                      JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
245
                      JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
246
                   ) ON (ctx.path LIKE $parentcctx AND ra.userid = ue.userid)
247
             WHERE e.enrol = 'category' AND cc.id IS NULL";
248
    $rs = $DB->get_recordset_sql($sql, $params);
249
    foreach($rs as $instance) {
250
        $userid = $instance->userid;
251
        unset($instance->userid);
252
        $plugin->unenrol_user($instance, $userid);
253
        $trace->output("unenrolling: user $userid ==> course $instance->courseid", 1);
254
    }
255
    $rs->close();
256
 
257
    $trace->output('...user enrolment synchronisation finished.');
258
    $trace->finished();
259
 
260
    return 0;
261
}