MDL-29695 enrol-cohort: Minor code improvement
[moodle.git] / enrol / cohort / locallib.php
1 <?php
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/>.
18 /**
19  * Local stuff for cohort enrolment plugin.
20  *
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
25  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->dirroot . '/enrol/locallib.php');
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  */
38 class enrol_cohort_handler {
39     public function member_added($ca) {
40         global $DB;
42         if (!enrol_is_enabled('cohort')) {
43             return true;
44         }
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         }
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         }
58         return true;
59     }
61     public function member_removed($ca) {
62         global $DB;
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         }
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         }
75         return true;
76     }
78     public function deleted($cohort) {
79         global $DB;
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         }
86         $plugin = enrol_get_plugin('cohort');
87         foreach ($enrols as $enrol) {
88             $plugin->delete_instance($enrol);
89         }
91         return true;
92     }
93 }
95 /**
96  * Sync all cohort course links.
97  * @param int $courseid one course, empty mean all
98  * @return void
99  */
100 function enrol_cohort_sync($courseid = NULL) {
101     global $CFG, $DB;
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
106     $cohort = enrol_get_plugin('cohort');
108     $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
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     }
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);
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;
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     }
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);
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();
195 /**
196  * Enrols all of the users in a cohort through a manual plugin instance.
197  *
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
205  * @return int
206  */
207 function 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);
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
225               FROM {cohort_members} com
226          LEFT JOIN (
227                 SELECT *
228                 FROM {user_enrolments} ue
229                 WHERE ue.enrolid = :enrolid
230                  ) ue ON ue.userid=com.userid
231              WHERE com.cohortid = :cohortid AND ue.id IS NULL";
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;
243 /**
244  * Gets all the cohorts the user is able to view.
245  *
246  * @global moodle_database $DB
247  * @param course_enrolment_manager $manager
248  * @return array
249  */
250 function 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;
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  */
290 function enrol_cohort_can_view_cohort($cohortid) {
291     global $DB;
292     $cohort = $DB->get_record('cohort', array('id' => $cohortid), 'id, contextid');
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;
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  */
312 function 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     }
324     list($sqlparents, $params) = $DB->get_in_or_equal(get_parent_contexts($context));
326     // Add some additional sensible conditions
327     $tests = array('contextid ' . $sqlparents);
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);
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);
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);