MDL-29695 enrol-cohort: Minor code improvement
[moodle.git] / enrol / cohort / locallib.php
CommitLineData
df997f84
PS
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * Local stuff for cohort enrolment plugin.
20 *
465f5088
PS
21 * @package enrol
22 * @subpackage cohort
23 * @copyright 2010 Petr Skoda {@link http://skodak.org}
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
df997f84
PS
25 */
26
97795859 27defined('MOODLE_INTERNAL') || die();
df997f84 28
e0dd7cb0
PS
29require_once($CFG->dirroot . '/enrol/locallib.php');
30
31
df997f84
PS
32/**
33 * Event handler for cohort enrolment plugin.
34 *
35 * We try to keep everything in sync via listening to events,
36 * it may fail sometimes, so we always do a full sync in cron too.
37 */
38class enrol_cohort_handler {
39 public function member_added($ca) {
40 global $DB;
41
42 if (!enrol_is_enabled('cohort')) {
43 return true;
44 }
45
46 // does anything want to sync with this parent?
47 //TODO: add join to role table to make sure that roleid actually exists
48 if (!$enrols = $DB->get_records('enrol', array('customint1'=>$ca->cohortid, 'enrol'=>'cohort'), 'id ASC')) {
49 return true;
50 }
51
52 $plugin = enrol_get_plugin('cohort');
53 foreach ($enrols as $enrol) {
54 // no problem if already enrolled
55 $plugin->enrol_user($enrol, $ca->userid, $enrol->roleid);
56 }
57
58 return true;
59 }
60
61 public function member_removed($ca) {
62 global $DB;
63
64 // does anything want to sync with this parent?
65 if (!$enrols = $DB->get_records('enrol', array('customint1'=>$ca->cohortid, 'enrol'=>'cohort'), 'id ASC')) {
66 return true;
67 }
68
69 $plugin = enrol_get_plugin('cohort');
70 foreach ($enrols as $enrol) {
71 // no problem if already enrolled
72 $plugin->unenrol_user($enrol, $ca->userid);
73 }
74
75 return true;
76 }
77
78 public function deleted($cohort) {
79 global $DB;
80
81 // does anything want to sync with this parent?
82 if (!$enrols = $DB->get_records('enrol', array('customint1'=>$cohort->id, 'enrol'=>'cohort'), 'id ASC')) {
83 return true;
84 }
85
86 $plugin = enrol_get_plugin('cohort');
87 foreach ($enrols as $enrol) {
88 $plugin->delete_instance($enrol);
89 }
90
91 return true;
92 }
93}
94
95/**
96 * Sync all cohort course links.
97 * @param int $courseid one course, empty mean all
98 * @return void
99 */
100function enrol_cohort_sync($courseid = NULL) {
101 global $CFG, $DB;
102
103 // unfortunately this may take a long time
104 @set_time_limit(0); //if this fails during upgrade we can continue from cron, no big deal
105
106 $cohort = enrol_get_plugin('cohort');
107
108 $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
109
110 // iterate through all not enrolled yet users
111 if (enrol_is_enabled('cohort')) {
112 $params = array();
113 $onecourse = "";
114 if ($courseid) {
115 $params['courseid'] = $courseid;
116 $onecourse = "AND e.courseid = :courseid";
117 }
118 $sql = "SELECT cm.userid, e.id AS enrolid
119 FROM {cohort_members} cm
120 JOIN {enrol} e ON (e.customint1 = cm.cohortid AND e.status = :statusenabled AND e.enrol = 'cohort' $onecourse)
121 LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = cm.userid)
122 WHERE ue.id IS NULL";
123 $params['statusenabled'] = ENROL_INSTANCE_ENABLED;
124 $params['courseid'] = $courseid;
125 $rs = $DB->get_recordset_sql($sql, $params);
126 $instances = array(); //cache
127 foreach($rs as $ue) {
128 if (!isset($instances[$ue->enrolid])) {
129 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
130 }
131 $cohort->enrol_user($instances[$ue->enrolid], $ue->userid);
132 }
133 $rs->close();
134 unset($instances);
135 }
136
137 // unenrol as necessary - ignore enabled flag, we want to get rid of all
138 $sql = "SELECT ue.userid, e.id AS enrolid
139 FROM {user_enrolments} ue
140 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'cohort' $onecourse)
141 LEFT JOIN {cohort_members} cm ON (cm.cohortid = e.customint1 AND cm.userid = ue.userid)
142 WHERE cm.id IS NULL";
143 //TODO: this may use a bit of SQL optimisation
144 $rs = $DB->get_recordset_sql($sql, array('courseid'=>$courseid));
145 $instances = array(); //cache
146 foreach($rs as $ue) {
147 if (!isset($instances[$ue->enrolid])) {
148 $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
149 }
150 $cohort->unenrol_user($instances[$ue->enrolid], $ue->userid);
151 }
152 $rs->close();
153 unset($instances);
154
155 // now assign all necessary roles
156 if (enrol_is_enabled('cohort')) {
157 $sql = "SELECT e.roleid, ue.userid, c.id AS contextid, e.id AS itemid
158 FROM {user_enrolments} ue
159 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'cohort' AND e.status = :statusenabled $onecourse)
160 JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :coursecontext)
161 LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = ue.userid AND ra.itemid = e.id AND ra.component = 'enrol_cohort' AND e.roleid = ra.roleid)
162 WHERE ra.id IS NULL";
163 $params = array();
164 $params['statusenabled'] = ENROL_INSTANCE_ENABLED;
165 $params['coursecontext'] = CONTEXT_COURSE;
166 $params['courseid'] = $courseid;
167
168 $rs = $DB->get_recordset_sql($sql, $params);
169 foreach($rs as $ra) {
170 role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_cohort', $ra->itemid);
171 }
172 $rs->close();
173 }
174
175 // remove unwanted roles - include ignored roles and disabled plugins too
176 $onecourse = $courseid ? "AND c.instanceid = :courseid" : "";
177 $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid
178 FROM {role_assignments} ra
179 JOIN {context} c ON (c.id = ra.contextid AND c.contextlevel = :coursecontext $onecourse)
180 LEFT JOIN (SELECT e.id AS enrolid, e.roleid, ue.userid
181 FROM {user_enrolments} ue
182 JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'cohort')
183 ) x ON (x.enrolid = ra.itemid AND ra.component = 'enrol_cohort' AND x.roleid = ra.roleid AND x.userid = ra.userid)
184 WHERE x.userid IS NULL AND ra.component = 'enrol_cohort'";
185 $params = array('coursecontext' => CONTEXT_COURSE, 'courseid' => $courseid);
186
187 $rs = $DB->get_recordset_sql($sql, $params);
188 foreach($rs as $ra) {
189 role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_cohort', $ra->itemid);
190 }
191 $rs->close();
192
193}
cf855c0b
SH
194
195/**
196 * Enrols all of the users in a cohort through a manual plugin instance.
e0dd7cb0 197 *
cf855c0b
SH
198 * In order for this to succeed the course must contain a valid manual
199 * enrolment plugin instance that the user has permission to enrol users through.
200 *
201 * @global moodle_database $DB
202 * @param course_enrolment_manager $manager
203 * @param int $cohortid
204 * @param int $roleid
e0dd7cb0 205 * @return int
cf855c0b
SH
206 */
207function enrol_cohort_enrol_all_users(course_enrolment_manager $manager, $cohortid, $roleid) {
208 global $DB;
209 $context = $manager->get_context();
210 require_capability('moodle/course:enrolconfig', $context);
211
212 $instance = false;
213 $instances = $manager->get_enrolment_instances();
214 foreach ($instances as $i) {
215 if ($i->enrol == 'manual') {
216 $instance = $i;
217 break;
218 }
219 }
220 $plugin = enrol_get_plugin('manual');
221 if (!$instance || !$plugin || !$plugin->allow_enrol($instance) || !has_capability('enrol/'.$plugin->get_name().':enrol', $context)) {
222 return false;
223 }
224 $sql = "SELECT com.userid
884faffd
SH
225 FROM {cohort_members} com
226 LEFT JOIN (
cf855c0b
SH
227 SELECT *
228 FROM {user_enrolments} ue
229 WHERE ue.enrolid = :enrolid
884faffd
SH
230 ) ue ON ue.userid=com.userid
231 WHERE com.cohortid = :cohortid AND ue.id IS NULL";
cf855c0b
SH
232 $params = array('cohortid' => $cohortid, 'enrolid' => $instance->id);
233 $rs = $DB->get_recordset_sql($sql, $params);
234 $count = 0;
235 foreach ($rs as $user) {
236 $count++;
237 $plugin->enrol_user($instance, $user->userid, $roleid);
238 }
239 $rs->close();
240 return $count;
241}
242
243/**
244 * Gets all the cohorts the user is able to view.
245 *
246 * @global moodle_database $DB
22a811be 247 * @param course_enrolment_manager $manager
cf855c0b
SH
248 * @return array
249 */
250function enrol_cohort_get_cohorts(course_enrolment_manager $manager) {
251 global $DB;
252 $context = $manager->get_context();
253 $cohorts = array();
254 $instances = $manager->get_enrolment_instances();
255 $enrolled = array();
256 foreach ($instances as $instance) {
257 if ($instance->enrol == 'cohort') {
258 $enrolled[] = $instance->customint1;
259 }
260 }
261 list($sqlparents, $params) = $DB->get_in_or_equal(get_parent_contexts($context));
262 $sql = "SELECT id, name, contextid
263 FROM {cohort}
264 WHERE contextid $sqlparents
265 ORDER BY name ASC";
266 $rs = $DB->get_recordset_sql($sql, $params);
267 foreach ($rs as $c) {
268 $context = get_context_instance_by_id($c->contextid);
269 if (!has_capability('moodle/cohort:view', $context)) {
270 continue;
271 }
272 $cohorts[$c->id] = array(
273 'cohortid'=>$c->id,
274 'name'=>format_string($c->name),
275 'users'=>$DB->count_records('cohort_members', array('cohortid'=>$c->id)),
276 'enrolled'=>in_array($c->id, $enrolled)
277 );
278 }
279 $rs->close();
280 return $cohorts;
22a811be
RK
281}
282
283/**
284 * Check if cohort exists and user is allowed to enrol it
285 *
286 * @global moodle_database $DB
287 * @param int $cohortid Cohort ID
288 * @return boolean
289 */
290function enrol_cohort_can_view_cohort($cohortid) {
291 global $DB;
e797476f 292 $cohort = $DB->get_record('cohort', array('id' => $cohortid), 'id, contextid');
22a811be
RK
293 if ($cohort) {
294 $context = get_context_instance_by_id($cohort->contextid);
295 if (has_capability('moodle/cohort:view', $context)) {
296 return true;
297 }
298 }
299 return false;
300}
301
302/**
303 * Gets cohorts the user is able to view.
304 *
305 * @global moodle_database $DB
306 * @param course_enrolment_manager $manager
307 * @param int $offset limit output from
308 * @param int $limit items to output per load
309 * @param string $search search string
310 * @return array Array(more => bool, offset => int, cohorts => array)
311 */
312function enrol_cohort_search_cohorts(course_enrolment_manager $manager, $offset = 0, $limit = 25, $search = '') {
313 global $DB;
314 $context = $manager->get_context();
315 $cohorts = array();
316 $instances = $manager->get_enrolment_instances();
317 $enrolled = array();
318 foreach ($instances as $instance) {
319 if ($instance->enrol == 'cohort') {
320 $enrolled[] = $instance->customint1;
321 }
322 }
323
324 list($sqlparents, $params) = $DB->get_in_or_equal(get_parent_contexts($context));
325
326 // Add some additional sensible conditions
327 $tests = array('contextid ' . $sqlparents);
328
329 // Modify the quesry to perform the search if requred
330 if (!empty($search)) {
331 $conditions = array(
332 'name',
333 'idnumber',
334 'description'
335 );
336 $searchparam = '%' . $search . '%';
337 foreach ($conditions as $key=>$condition) {
338 $conditions[$key] = $DB->sql_like($condition,"?", false);
339 $params[] = $searchparam;
340 }
341 $tests[] = '(' . implode(' OR ', $conditions) . ')';
342 }
343 $wherecondition = implode(' AND ', $tests);
344
345 $fields = 'SELECT id, name, contextid, description';
346 $countfields = 'SELECT COUNT(1)';
347 $sql = " FROM {cohort}
348 WHERE $wherecondition";
349 $order = ' ORDER BY name ASC';
350 $rs = $DB->get_recordset_sql($fields . $sql . $order, $params, $offset);
351
352 // Produce the output respecting parameters
353 foreach ($rs as $c) {
354 // Track offset
355 $offset++;
356 // Check capabilities
357 $context = get_context_instance_by_id($c->contextid);
358 if (!has_capability('moodle/cohort:view', $context)) {
359 continue;
360 }
361 if ($limit === 0) {
362 // we have reached the required number of items and know that there are more, exit now
363 $offset--;
364 break;
365 }
366 $cohorts[$c->id] = array(
367 'cohortid'=>$c->id,
368 'name'=> shorten_text(format_string($c->name), 35),
369 'users'=>$DB->count_records('cohort_members', array('cohortid'=>$c->id)),
370 'enrolled'=>in_array($c->id, $enrolled)
371 );
372 // Count items
373 $limit--;
374 }
375 $rs->close();
376 return array('more' => !(bool)$limit, 'offset' => $offset, 'cohorts' => $cohorts);
cf855c0b 377}