*/
}
+/*
+ * Retrieve course records with the course managers and other related records
+ * that we need for print_course(). This allows print_courses() to do its job
+ * in a constant number of DB queries, regardless of the number of courses,
+ * role assignments, etc.
+ *
+ * The returned array is indexed on c.id, and each course will have
+ * - $course->context - a context obj
+ * - $course->managers - array containing RA objects that include a $user obj
+ * with the minimal fields needed for fullname()
+ *
+ */
+function get_courses_wmanagers($categoryid=0, $sort="c.sortorder ASC", $fields=array()) {
+ /*
+ * The plan is to
+ *
+ * - Grab the courses JOINed w/context
+ *
+ * - Grab the interesting course-manager RAs
+ * JOINed with a base user obj and add them to each course
+ *
+ * So as to do all the work in 2 DB queries. The RA+user JOIN
+ * ends up being pretty expensive if it happens over _all_
+ * courses on a large site. (Are we surprised!?)
+ *
+ * So this should _never_ get called with 'all' on a large site.
+ *
+ */
+ global $USER, $CFG;
+
+ $allcats = false; // bool flag
+ if ($categoryid === 'all') {
+ $categoryclause = '';
+ $allcats = true;
+ } elseif (is_numeric($categoryid)) {
+ $categoryclause = "c.category = $categoryid";
+ } else {
+ debugging("Could not recognise categoryid = $categoryid");
+ $categoryclause = '';
+ }
+
+ $basefields = array('id', 'category', 'sortorder',
+ 'shortname', 'fullname', 'idnumber',
+ 'teacher', 'teachers', 'student', 'students',
+ 'guest', 'startdate', 'visible',
+ 'newsitems', 'cost', 'enrol',
+ 'groupmode', 'groupmodeforce');
+
+ if (!is_null($fields) && is_string($fields)) {
+ if (empty($fields)) {
+ $fields = $basefields;
+ } else {
+ // turn the fields from a string to an array that
+ // get_user_courses_bycap() will like...
+ $fields = explode(',',$fields);
+ $fields = array_map('trim', $fields);
+ $fields = array_unique(array_merge($basefields, $fields));
+ }
+ } elseif (is_array($fields)) {
+ $fields = array_merge($basefields,$fields);
+ }
+ $coursefields = 'c.' .join(',c.', $fields);
+
+ if (empty($sort)) {
+ $sortstatement = "";
+ } else {
+ $sortstatement = "ORDER BY $sort";
+ }
+
+ $where = '';
+ if ($categoryclause !== ''){
+ $where = "WHERE $categoryclause";
+ }
+
+ // pull out all courses matching the cat
+ $sql = "SELECT $coursefields,
+ ctx.id AS ctxid, ctx.path AS ctxpath, ctx.depth as ctxdepth
+ FROM {$CFG->prefix}course c
+ JOIN {$CFG->prefix}context ctx
+ ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
+ $where
+ $sortstatement";
+
+ $catpaths = array();
+ $catpath = NULL;
+ if ($courses = get_records_sql($sql)) {
+ // loop on courses materialising
+ // the context, and prepping data to fetch the
+ // managers efficiently later...
+ foreach ($courses as $k => $course) {
+ $courses[$k] = make_context_subobj($courses[$k]);
+ $courses[$k]->managers = array();
+ if ($allcats === false) {
+ // single cat, so take just the first one...
+ if ($catpath === NULL) {
+ $catpath = preg_replace(':/\d+$:', '',$courses[$k]->context->path);
+ }
+ } else {
+ // chop off the contextid of the course itself
+ // like dirname() does...
+ $catpaths[] = preg_replace(':/\d+$:', '',$courses[$k]->context->path);
+ }
+ }
+ } else {
+ return array(); // no courses!
+ }
+
+ $managerroles = split(',', $CFG->coursemanager);
+ $catctxids = '';
+ if (count($managerroles)) {
+ if ($allcats === true) {
+ $catpaths = array_unique($catpaths);
+ $ctxids = array();
+ foreach ($catpaths as $cpath) {
+ $ctxids = array_merge($ctxids, explode('/',substr($cpath,1)));
+ }
+ $ctxids = array_unique($ctxids);
+ $catctxids = implode( ',' , $ctxids);
+ unset($catpaths);unset($cpath);
+ } else {
+ // take the ctx path from the first course
+ // as all categories will be the same...
+ $catpath = substr($catpath,1);
+ $catpath = preg_replace(':/\d+$:','',$catpath);
+ $catctxids = str_replace('/',',',$catpath);
+ }
+ if ($categoryclause !== '') {
+ $categoryclause = "AND $categoryclause";
+ }
+ /*
+ * Note: Here we use a LEFT OUTER JOIN that can
+ * "optionally" match to avoid passing a ton of context
+ * ids in an IN() clause. Perhaps a subselect is faster.
+ *
+ * In any case, this SQL is not-so-nice over large sets of
+ * courses with no $categoryclause.
+ *
+ */
+ $sql = "SELECT ctx.path, ctx.instanceid, ctx.contextlevel,
+ ra.hidden,
+ r.id AS roleid, r.name as rolename,
+ u.id AS userid, u.firstname, u.lastname
+ FROM {$CFG->prefix}role_assignments ra
+ JOIN {$CFG->prefix}context ctx
+ ON ra.contextid = ctx.id
+ JOIN {$CFG->prefix}user u
+ ON ra.userid = u.id
+ JOIN {$CFG->prefix}role r
+ ON ra.roleid = r.id
+ LEFT OUTER JOIN {$CFG->prefix}course c
+ ON (ctx.instanceid=c.id AND ctx.contextlevel=".CONTEXT_COURSE.")
+ WHERE ( c.id IS NOT NULL
+ OR ra.contextid IN ($catctxids) )
+ AND ra.roleid IN ({$CFG->coursemanager})
+ $categoryclause
+ ORDER BY r.sortorder ASC, ctx.contextlevel ASC, ra.sortorder ASC";
+
+ $rs = get_recordset_sql($sql);
+
+ // This loop is fairly stupid as it stands - might get better
+ // results doing an initial pass clustering RAs by path.
+ if ($rs->RecordCount()) {
+ while ($ra = rs_fetch_next_record($rs)) {
+ $user = new StdClass;
+ $user->id = $ra->userid; unset($ra->userid);
+ $user->firstname = $ra->firstname; unset($ra->firstname);
+ $user->lastname = $ra->lastname; unset($ra->lastname);
+ $ra->user = $user;
+ if ($ra->contextlevel == CONTEXT_SYSTEM) {
+ foreach ($courses as $k => $course) {
+ $courses[$k]->managers[] = $ra;
+ }
+ } elseif ($ra->contextlevel == CONTEXT_COURSECAT) {
+ if ($allcats === false) {
+ // It always applies
+ foreach ($courses as $k => $course) {
+ $courses[$k]->managers[] = $ra;
+ }
+ } else {
+ foreach ($courses as $k => $course) {
+ // Note that strpos() returns 0 as "matched at pos 0"
+ if (strpos($course->context->path, $ra->path.'/')===0) {
+ // Only add it to subpaths
+ $courses[$k]->managers[] = $ra;
+ }
+ }
+ }
+ } else { // course-level
+ $courses[$ra->instanceid]->managers[] = $ra;
+ }
+ }
+ }
+
+
+
+ }
+
+ return $courses;
+}
/**
* Convenience function - lists courses that a user has access to view.