diff --git a/admin/roles/assign.php b/admin/roles/assign.php index 65aa22159a1b3..45ea5f833651b 100644 --- a/admin/roles/assign.php +++ b/admin/roles/assign.php @@ -259,7 +259,7 @@ foreach ($assignableroles as $roleid => $notused) { $roleusers = ''; if (0 < $assigncounts[$roleid] && $assigncounts[$roleid] <= MAX_USERS_TO_LIST_PER_ROLE) { - $roleusers = get_role_users($roleid, $context, false, 'u.id, u.lastname, u.firstname'); + $roleusers = get_role_users($roleid, $context, false, 'u.id, u.firstname, u.lastname'); if (!empty($roleusers)) { $strroleusers = array(); foreach ($roleusers as $user) { diff --git a/admin/roles/lib.php b/admin/roles/lib.php index df537f008da93..078d2efc8a180 100644 --- a/admin/roles/lib.php +++ b/admin/roles/lib.php @@ -1043,11 +1043,12 @@ public function find_users($search) { WHERE u.id IN ($enrolsql) $wherecondition AND ra.id IS NULL"; - $order = ' ORDER BY lastname ASC, firstname ASC'; - $params['contextid'] = $this->context->id; $params['roleid'] = $this->roleid; + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; + // Check to see if there are too many to show sensibly. if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -1057,7 +1058,7 @@ public function find_users($search) { } // If not, show them. - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); @@ -1094,7 +1095,9 @@ public function find_users($search) { FROM {role_assignments} r WHERE r.contextid = :contextid AND r.roleid = :roleid)"; - $order = ' ORDER BY lastname ASC, firstname ASC'; + + list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; $params['contextid'] = $this->context->id; $params['roleid'] = $this->roleid; @@ -1106,7 +1109,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); @@ -1140,6 +1143,9 @@ public function find_users($search) { $params = array_merge($params, $ctxparams); $params['roleid'] = $this->roleid; + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $params = array_merge($params, $sortparams); + $sql = "SELECT ra.id as raid," . $this->required_fields_sql('u') . ",ra.contextid,ra.component FROM {role_assignments} ra JOIN {user} u ON u.id = ra.userid @@ -1148,7 +1154,7 @@ public function find_users($search) { $wherecondition AND ctx.id $ctxcondition AND ra.roleid = :roleid - ORDER BY ctx.depth DESC, ra.component, u.lastname, u.firstname"; + ORDER BY ctx.depth DESC, ra.component, $sort"; $contextusers = $DB->get_records_sql($sql, $params); // No users at all. @@ -1495,10 +1501,14 @@ class admins_potential_selector extends user_selector_base { * @param string $name control name * @param array $options should have two elements with keys groupid and courseid. */ - public function __construct() { - global $CFG, $USER; - $admins = explode(',', $CFG->siteadmins); - parent::__construct('addselect', array('multiselect'=>false, 'exclude'=>$admins)); + public function __construct($name = null, $options = array()) { + global $CFG; + if (is_null($name)) { + $name = 'addselect'; + } + $options['multiselect'] = false; + $options['exclude'] = explode(',', $CFG->siteadmins); + parent::__construct($name, $options); } public function find_users($search) { @@ -1510,9 +1520,12 @@ public function find_users($search) { $sql = " FROM {user} WHERE $wherecondition AND mnethostid = :localmnet"; - $order = ' ORDER BY lastname ASC, firstname ASC'; + $params['localmnet'] = $CFG->mnet_localhost_id; // it could be dangerous to make remote users admins and also this could lead to other problems + list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; + // Check to see if there are too many to show sensibly. if (!$this->is_validating()) { $potentialcount = $DB->count_records_sql($countfields . $sql, $params); @@ -1521,7 +1534,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); @@ -1549,9 +1562,12 @@ class admins_existing_selector extends user_selector_base { * @param string $name control name * @param array $options should have two elements with keys groupid and courseid. */ - public function __construct() { - global $CFG, $USER; - parent::__construct('removeselect', array('multiselect'=>false)); + public function __construct($name = null, $options = array()) { + if (is_null($name)) { + $name = 'removeselect'; + } + $options['multiselect'] = false; + parent::__construct($name, $options); } public function find_users($search) { @@ -1568,7 +1584,10 @@ public function find_users($search) { } $sql = " FROM {user} WHERE $wherecondition"; - $order = ' ORDER BY lastname ASC, firstname ASC'; + + list($sort, $sortparams) = users_order_by_sql('', $search, $this->accesscontext); + $params = array_merge($params, $sortparams); + $order = ' ORDER BY ' . $sort; $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); diff --git a/admin/webservice/forms.php b/admin/webservice/forms.php index bffaba9dc92e7..289dcc4d0938a 100644 --- a/admin/webservice/forms.php +++ b/admin/webservice/forms.php @@ -194,16 +194,18 @@ function definition() { array('deleted' => 0, 'suspended' => 0, 'confirmed' => 1)); if ($usertotal < 500) { + list($sort, $params) = users_order_by_sql('u'); //user searchable selector - get all users (admin and guest included) //user must be confirmed, not deleted, not suspended, not guest $sql = "SELECT u.id, u.firstname, u.lastname FROM {user} u - WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND u.id != ? - ORDER BY u.lastname"; - $users = $DB->get_records_sql($sql, array($CFG->siteguest)); + WHERE u.deleted = 0 AND u.confirmed = 1 AND u.suspended = 0 AND u.id != :siteguestid + ORDER BY $sort"; + $params['siteguestid'] = $CFG->siteguest; + $users = $DB->get_records_sql($sql, $params); $options = array(); foreach ($users as $userid => $user) { - $options[$userid] = $user->firstname . " " . $user->lastname; + $options[$userid] = fullname($user); } $mform->addElement('searchableselector', 'user', get_string('user'), $options); } else { diff --git a/admin/webservice/lib.php b/admin/webservice/lib.php index 137b672ccbc13..161c03af1f19d 100644 --- a/admin/webservice/lib.php +++ b/admin/webservice/lib.php @@ -25,8 +25,8 @@ require_once($CFG->dirroot . '/user/selector/lib.php'); /* -* This class displays either all the Moodle users allowed to use a service, -* either all the other Moodle users. + * This class displays either all the Moodle users allowed to use a service, + * either all the other Moodle users. */ class service_user_selector extends user_selector_base { const MAX_USERS_PER_PAGE = 100; @@ -41,8 +41,7 @@ public function __construct($name, $options) { parent::__construct($name, $options); if (!empty($options['serviceid'])) { $this->serviceid = $options['serviceid']; - } - else { + } else { throw new moodle_exception('serviceidnotfound'); } $this->displayallowedusers = !empty($options['displayallowedusers']); @@ -81,7 +80,8 @@ public function find_users($search) { AND esu.userid = u.id)"; } - $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -90,7 +90,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); diff --git a/cohort/locallib.php b/cohort/locallib.php index b257223b667ae..3cb1d3bfff81b 100644 --- a/cohort/locallib.php +++ b/cohort/locallib.php @@ -57,7 +57,8 @@ public function find_users($search) { LEFT JOIN {cohort_members} cm ON (cm.userid = u.id AND cm.cohortid = :cohortid) WHERE cm.id IS NULL AND $wherecondition"; - $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -66,7 +67,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); @@ -120,7 +121,8 @@ public function find_users($search) { JOIN {cohort_members} cm ON (cm.userid = u.id AND cm.cohortid = :cohortid) WHERE $wherecondition"; - $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -129,7 +131,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); diff --git a/course/lib.php b/course/lib.php index d3395566767be..5b991e4e07476 100644 --- a/course/lib.php +++ b/course/lib.php @@ -2520,10 +2520,11 @@ function print_course($course, $highlightterms = '') { $rusers = array(); if (!isset($course->managers)) { + list($sort, $sortparams) = users_order_by_sql('u'); $rusers = get_role_users($managerroles, $context, true, 'ra.id AS raid, u.id, u.username, u.firstname, u.lastname, rn.name AS rolecoursealias, r.name AS rolename, r.sortorder, r.id AS roleid, r.shortname AS roleshortname', - 'r.sortorder ASC, u.lastname ASC'); + 'r.sortorder ASC, ' . $sort, null, '', '', '', '', $sortparams); } else { // use the managers array if we have it for perf reasosn // populate the datastructure like output of get_role_users(); diff --git a/enrol/locallib.php b/enrol/locallib.php index 596320a7ee6da..ea40fa6fb1097 100644 --- a/enrol/locallib.php +++ b/enrol/locallib.php @@ -310,11 +310,15 @@ public function get_potential_users($enrolid, $search='', $searchanywhere=false, LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid) WHERE $wherecondition AND ue.id IS NULL"; - $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; $params['enrolid'] = $enrolid; + + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->get_context()); + $order = ' ORDER BY ' . $sort; + $params += $sortparams; + $totalusers = $DB->count_records_sql($countfields . $sql, $params); $availableusers = $DB->get_records_sql($fields . $sql . $order, $params, $page*$perpage, $perpage); - return array('totalusers'=>$totalusers, 'users'=>$availableusers); + return array('totalusers' => $totalusers, 'users' => $availableusers); } /** @@ -334,7 +338,7 @@ public function search_other_users($search='', $searchanywhere=false, $page=0, $ $tests = array("u.id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1'); $params = array('guestid'=>$CFG->siteguest); if (!empty($search)) { - $conditions = array('u.firstname','u.lastname'); + $conditions = array('u.firstname', 'u.lastname'); if ($searchanywhere) { $searchparam = '%' . $search . '%'; } else { @@ -356,11 +360,14 @@ public function search_other_users($search='', $searchanywhere=false, $page=0, $ LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid = :contextid) WHERE $wherecondition AND ra.id IS NULL"; - $order = ' ORDER BY lastname ASC, firstname ASC'; - $params['contextid'] = $this->context->id; + + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->context); + $order = ' ORDER BY ' . $sort; + $totalusers = $DB->count_records_sql($countfields . $sql, $params); - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params, $page*$perpage, $perpage); + $availableusers = $DB->get_records_sql($fields . $sql . $order, + array_merge($params, $sortparams), $page*$perpage, $perpage); return array('totalusers'=>$totalusers, 'users'=>$availableusers); } @@ -1008,14 +1015,16 @@ public function get_users_enrolments(array $userids) { $userfields = user_picture::fields('u'); list($idsql, $idparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'userid0000'); + list($sort, $sortparams) = users_order_by_sql('u'); + $sql = "SELECT ue.id AS ueid, ue.status, ue.enrolid, ue.userid, ue.timestart, ue.timeend, ue.modifierid, ue.timecreated, ue.timemodified, $userfields FROM {user_enrolments} ue LEFT JOIN {user} u ON u.id = ue.userid WHERE ue.enrolid $instancesql AND u.id $idsql - ORDER BY u.firstname ASC, u.lastname ASC"; + ORDER BY $sort"; - $rs = $DB->get_recordset_sql($sql, $idparams + $instanceparams); + $rs = $DB->get_recordset_sql($sql, $idparams + $instanceparams + $sortparams); $users = array(); foreach ($rs as $ue) { $user = user_picture::unalias($ue); diff --git a/enrol/manual/locallib.php b/enrol/manual/locallib.php index d7b8f0c5674d4..a96935429e908 100644 --- a/enrol/manual/locallib.php +++ b/enrol/manual/locallib.php @@ -57,7 +57,9 @@ public function find_users($search) { LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid) WHERE $wherecondition AND ue.id IS NULL"; - $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -66,7 +68,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); @@ -120,7 +122,8 @@ public function find_users($search) { JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid) WHERE $wherecondition"; - $order = ' ORDER BY u.lastname ASC, u.firstname ASC'; + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -129,7 +132,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); diff --git a/enrol/mnet/enrol.php b/enrol/mnet/enrol.php index 58fd876a38550..63966193804e4 100644 --- a/enrol/mnet/enrol.php +++ b/enrol/mnet/enrol.php @@ -344,9 +344,10 @@ public function course_enrolments($courseid, $roles=null) { $params = array_merge($params, $rparams); } - $sql .= " ORDER BY u.lastname, u.firstname"; + list($sort, $sortparams) = users_order_by_sql('u'); + $sql .= " ORDER BY $sort"; - $rs = $DB->get_recordset_sql($sql, $params); + $rs = $DB->get_recordset_sql($sql, array_merge($params, $sortparams)); $list = array(); foreach ($rs as $record) { $list[] = $record; diff --git a/enrol/self/lib.php b/enrol/self/lib.php index e4ac8359e42f2..01c3e14477317 100644 --- a/enrol/self/lib.php +++ b/enrol/self/lib.php @@ -317,7 +317,8 @@ protected function email_welcome_message($instance, $user) { $rusers = array(); if (!empty($CFG->coursecontact)) { $croles = explode(',', $CFG->coursecontact); - $rusers = get_role_users($croles, $context, true, '', 'r.sortorder ASC, u.lastname ASC'); + list($sort, $sortparams) = users_order_by_sql('u'); + $rusers = get_role_users($croles, $context, true, '', 'r.sortorder ASC, ' . $sort, null, '', '', '', '', $sortparams); } if ($rusers) { $contact = reset($rusers); diff --git a/grade/import/lib.php b/grade/import/lib.php index b4cb56f7753a2..aae171ebb51ad 100644 --- a/grade/import/lib.php +++ b/grade/import/lib.php @@ -169,6 +169,7 @@ function get_unenrolled_users_in_import($importcode, $courseid) { //enrolled users $context = context_course::instance($courseid); list($enrolledsql, $enrolledparams) = get_enrolled_sql($context); + list($sort, $sortparams) = users_order_by_sql('u'); $sql = "SELECT giv.id, u.firstname, u.lastname, u.idnumber AS useridnumber, COALESCE(gi.idnumber, gin.itemname) AS gradeidnumber @@ -185,8 +186,8 @@ function get_unenrolled_users_in_import($importcode, $courseid) { ON (giv.userid = ra.userid AND ra.roleid $gradebookrolessql AND ra.contextid $relatedctxcondition) WHERE giv.importcode = :importcode AND (ra.id IS NULL OR je.id IS NULL) - ORDER BY gradeidnumber, u.lastname, u.firstname"; - $params = array_merge($gradebookrolesparams, $enrolledparams); + ORDER BY gradeidnumber, $sort"; + $params = array_merge($gradebookrolesparams, $enrolledparams, $sortparams); $params['importcode'] = $importcode; return $DB->get_records_sql($sql, $params); diff --git a/group/index.php b/group/index.php index 1c9a6cdb88d5e..dc6d3074b834e 100644 --- a/group/index.php +++ b/group/index.php @@ -80,7 +80,7 @@ case 'ajax_getmembersingroup': $roles = array(); - if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id,u.firstname,u.lastname')) { + if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, u.firstname, u.lastname')) { foreach($groupmemberroles as $roleid=>$roledata) { $shortroledata = new stdClass(); $shortroledata->name = $roledata->name; @@ -248,7 +248,7 @@ $atleastonemember = false; if ($singlegroup) { - if ($groupmemberroles = groups_get_members_by_role($groupids[0],$courseid,'u.id,u.firstname,u.lastname')) { + if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, u.firstname, u.lastname')) { foreach($groupmemberroles as $roleid=>$roledata) { echo ''; foreach($roledata->users as $member) { diff --git a/group/lib.php b/group/lib.php index 6c59cfc041ac0..d5d5a7829fba8 100644 --- a/group/lib.php +++ b/group/lib.php @@ -751,13 +751,13 @@ function groups_unassign_grouping($groupingid, $groupid) { * @param int $groupid * @param int $courseid Course ID (should match the group's course) * @param string $fields List of fields from user table prefixed with u, default 'u.*' - * @param string $sort SQL ORDER BY clause, default 'u.lastname ASC' + * @param string $sort SQL ORDER BY clause, default (when null passed) is what comes from users_order_by_sql. * @param string $extrawheretest extra SQL conditions ANDed with the existing where clause. - * @param array $whereparams any parameters required by $extrawheretest (named parameters). + * @param array $whereorsortparams any parameters required by $extrawheretest (named parameters). * @return array Complex array as described above */ function groups_get_members_by_role($groupid, $courseid, $fields='u.*', - $sort='u.lastname ASC', $extrawheretest='', $whereparams=array()) { + $sort=null, $extrawheretest='', $whereorsortparams=array()) { global $CFG, $DB; // Retrieve information about all users and their roles on the course or @@ -768,6 +768,11 @@ function groups_get_members_by_role($groupid, $courseid, $fields='u.*', $extrawheretest = ' AND ' . $extrawheretest; } + if (is_null($sort)) { + list($sort, $sortparams) = users_order_by_sql('u'); + $whereorsortparams = array_merge($whereorsortparams, $sortparams); + } + $sql = "SELECT r.id AS roleid, u.id AS userid, $fields FROM {groups_members} gm JOIN {user} u ON u.id = gm.userid @@ -776,8 +781,8 @@ function groups_get_members_by_role($groupid, $courseid, $fields='u.*', WHERE gm.groupid=:mgroupid ".$extrawheretest." ORDER BY r.sortorder, $sort"; - $whereparams['mgroupid'] = $groupid; - $rs = $DB->get_recordset_sql($sql, $whereparams); + $whereorsortparams['mgroupid'] = $groupid; + $rs = $DB->get_recordset_sql($sql, $whereorsortparams); return groups_calculate_role_people($rs, $context); } diff --git a/group/overview.php b/group/overview.php index c6634f75e1481..7e6fa2cede5ec 100644 --- a/group/overview.php +++ b/group/overview.php @@ -87,15 +87,18 @@ } else { $groupingwhere = ""; } + +list($sort, $sortparams) = users_order_by_sql('u'); + $sql = "SELECT g.id AS groupid, gg.groupingid, u.id AS userid, u.firstname, u.lastname, u.idnumber, u.username FROM {groups} g LEFT JOIN {groupings_groups} gg ON g.id = gg.groupid LEFT JOIN {groups_members} gm ON g.id = gm.groupid LEFT JOIN {user} u ON gm.userid = u.id WHERE g.courseid = :courseid $groupwhere $groupingwhere - ORDER BY g.name, u.lastname, u.firstname"; + ORDER BY g.name, $sort"; -$rs = $DB->get_recordset_sql($sql, $params); +$rs = $DB->get_recordset_sql($sql, array_merge($params, $sortparams)); foreach ($rs as $row) { $user = new stdClass(); $user->id = $row->userid; diff --git a/lib/accesslib.php b/lib/accesslib.php index 2163435043da3..ec222d5bcf2f9 100644 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -2309,7 +2309,7 @@ function get_enrolled_sql(context $context, $withcapability = '', $groupid = 0, * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set). * @return array of user records */ -function get_enrolled_users(context $context, $withcapability = '', $groupid = 0, $userfields = 'u.*', $orderby = '', $limitfrom = 0, $limitnum = 0) { +function get_enrolled_users(context $context, $withcapability = '', $groupid = 0, $userfields = 'u.*', $orderby = null, $limitfrom = 0, $limitnum = 0) { global $DB; list($esql, $params) = get_enrolled_sql($context, $withcapability, $groupid); @@ -2321,7 +2321,9 @@ function get_enrolled_users(context $context, $withcapability = '', $groupid = 0 if ($orderby) { $sql = "$sql ORDER BY $orderby"; } else { - $sql = "$sql ORDER BY u.lastname ASC, u.firstname ASC"; + list($sort, $sortparams) = users_order_by_sql('u'); + $sql = "$sql ORDER BY $sort"; + $params = array_merge($params, $sortparams); } return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); @@ -3841,18 +3843,19 @@ function sort_by_roleassignment_authority($users, context $context, $roles = arr * @param context $context * @param bool $parent if true, get list of users assigned in higher context too * @param string $fields fields from user (u.) , role assignment (ra) or role (r.) - * @param string $sort sort from user (u.) , role assignment (ra) or role (r.) + * @param string $sort sort from user (u.) , role assignment (ra.) or role (r.). + * null => use default sort from users_order_by_sql. * @param bool $gethidden_ignored use enrolments instead * @param string $group defaults to '' * @param mixed $limitfrom defaults to '' * @param mixed $limitnum defaults to '' * @param string $extrawheretest defaults to '' - * @param string|array $whereparams defaults to '' + * @param array $whereorsortparams any paramter values used by $sort or $extrawheretest. * @return array */ function get_role_users($roleid, context $context, $parent = false, $fields = '', - $sort = 'u.lastname, u.firstname', $gethidden_ignored = null, $group = '', - $limitfrom = '', $limitnum = '', $extrawheretest = '', $whereparams = array()) { + $sort = null, $gethidden_ignored = null, $group = '', + $limitfrom = '', $limitnum = '', $extrawheretest = '', $whereorsortparams = array()) { global $DB; if (empty($fields)) { @@ -3899,9 +3902,17 @@ function get_role_users($roleid, context $context, $parent = false, $fields = '' if ($extrawheretest) { $extrawheretest = ' AND ' . $extrawheretest; + } + + if ($whereorsortparams) { $params = array_merge($params, $whereparams); } + if (!$sort) { + list($sort, $sortparams) = users_order_by_sql('u'); + $params = array_merge($params, $sortparams); + } + $sql = "SELECT DISTINCT $fields, ra.roleid FROM {role_assignments} ra JOIN {user} u ON u.id = ra.userid diff --git a/lib/adminlib.php b/lib/adminlib.php index 1bc2a439b7a9b..2ce7bc885ec10 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -3017,8 +3017,14 @@ function load_choices() { if (is_array($this->choices)) { return true; } + list($sort, $sortparams) = users_order_by_sql('u'); + if (!empty($sortparams)) { + throw new coding_exception('users_order_by_sql returned some query parameters. ' . + 'This is unexpected, and a problem because there is no way to pass these ' . + 'parameters to get_users_by_capability. See MDL-34657.'); + } $users = get_users_by_capability(context_system::instance(), - $this->capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname'); + $this->capability, 'u.id,u.username,u.firstname,u.lastname', $sort); $this->choices = array( '$@NONE@$' => get_string('nobody'), '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)), diff --git a/lib/datalib.php b/lib/datalib.php index abf24dfecc525..2167d665762b1 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -172,6 +172,97 @@ function search_users($courseid, $groupid, $searchtext, $sort='', array $excepti } } +/** + * This function generates the standard ORDER BY clause for use when generating + * lists of users. If you don't have a reason to use a different order, then + * you should use this method to generate the order when displaying lists of users. + * + * If the optional $search parameter is passed, then exact matches to the search + * will be sorted first. For example, suppose you have two users 'Al Zebra' and + * 'Alan Aardvark'. The default sort is Alan, then Al. If, however, you search for + * 'Al', then Al will be listed first. (With two users, this is not a big deal, + * but with thousands of users, it is essential.) + * + * The list of fields scanned for exact matches are: + * - firstname + * - lastname + * - $DB->sql_fullname + * - those returned by get_extra_user_fields + * + * If named parameters are used (which is the default, and highly recommended), + * then the parameter names are like :usersortexactN, where N is an int. + * + * The simplest possible example use is: + * list($sort, $params) = users_order_by_sql(); + * $sql = 'SELECT * FROM {users} ORDER BY ' . $sort; + * + * A more complex example, showing that this sort can be combined with other sorts: + * list($sort, $sortparams) = users_order_by_sql('u'); + * $sql = "SELECT g.id AS groupid, gg.groupingid, u.id AS userid, u.firstname, u.lastname, u.idnumber, u.username + * FROM {groups} g + * LEFT JOIN {groupings_groups} gg ON g.id = gg.groupid + * LEFT JOIN {groups_members} gm ON g.id = gm.groupid + * LEFT JOIN {user} u ON gm.userid = u.id + * WHERE g.courseid = :courseid $groupwhere $groupingwhere + * ORDER BY g.name, $sort"; + * $params += $sortparams; + * + * An example showing the use of $search: + * list($sort, $sortparams) = users_order_by_sql('u', $search, $this->get_context()); + * $order = ' ORDER BY ' . $sort; + * $params += $sortparams; + * $availableusers = $DB->get_records_sql($fields . $sql . $order, $params, $page*$perpage, $perpage); + * + * @param string $usertablealias (optional) any table prefix for the {users} table. E.g. 'u'. + * @param string $search (optional) a current search string. If given, + * any exact matches to this string will be sorted first. + * @param context $context the context we are in. Use by get_extra_user_fields. + * Defaults to $PAGE->context. + * @return array with two elements: + * string SQL fragment to use in the ORDER BY clause. For example, "firstname, lastname". + * array of parameters used in the SQL fragment. + */ +function users_order_by_sql($usertablealias = '', $search = null, context $context = null) { + global $DB, $PAGE; + + if ($usertablealias) { + $tableprefix = $usertablealias . '.'; + } else { + $tableprefix = ''; + } + + $sort = "{$tableprefix}lastname, {$tableprefix}firstname, {$tableprefix}id"; + $params = array(); + + if (!$search) { + return array($sort, $params); + } + + if (!$context) { + $context = $PAGE->context; + } + + $exactconditions = array(); + $paramkey = 'usersortexact1'; + + $exactconditions[] = $DB->sql_fullname($tableprefix . 'firstname', $tableprefix . 'lastname') . + ' = :' . $paramkey; + $params[$paramkey] = $search; + $paramkey++; + + $fieldstocheck = array_merge(array('firstname', 'lastname'), get_extra_user_fields($context)); + foreach ($fieldstocheck as $key => $field) { + $exactconditions[] = $tableprefix . $field . ' = :' . $paramkey; + $params[$paramkey] = $search; + $paramkey++; + } + + $sort = 'CASE WHEN ' . implode(' OR ', $exactconditions) . + ' THEN 0 ELSE 1 END, ' . $sort; + + return array($sort, $params); +} + /** * Returns a subset of users * @@ -189,7 +280,7 @@ function search_users($courseid, $groupid, $searchtext, $sort='', array $excepti * @param string $recordsperpage The number of records to return per page * @param string $fields A comma separated list of fields to be returned from the chosen table. * @return array|int|bool {@link $USER} records unless get is false in which case the integer count of the records found is returned. - * False is returned if an error is encountered. + * False is returned if an error is encountered. */ function get_users($get=true, $search='', $confirmed=false, array $exceptions=null, $sort='firstname ASC', $firstinitial='', $lastinitial='', $page='', $recordsperpage='', $fields='*', $extraselect='', array $extraparams=null) { diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index 6faf7522b5b5e..418d518cc6c8b 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -4114,6 +4114,22 @@ public function test_get_records_sql_complicated() { $records = $DB->get_records_sql($sql, null); $this->assertEquals($result, $records); + // Test CASE expressions in the ORDER BY clause - used by MDL-34657. + $sql = "SELECT id, course, name + FROM {{$tablename}} + ORDER BY CASE WHEN (course = 5 OR name = 'xyz') THEN 0 ELSE 1 END, name, course"; + // First, records matching the course = 5 OR name = 'xyz', then the rest. Each + // group ordered by name and course. + $result = array( + 3 => (object)array('id' => 3, 'course' => 5, 'name' => 'def'), + 1 => (object)array('id' => 1, 'course' => 3, 'name' => 'xyz'), + 4 => (object)array('id' => 4, 'course' => 2, 'name' => 'abc'), + 2 => (object)array('id' => 2, 'course' => 3, 'name' => 'abc')); + $records = $DB->get_records_sql($sql, null); + $this->assertEquals($result, $records); + // Verify also array keys, order is important in this test. + $this->assertEquals(array_keys($result), array_keys($records)); + // test limits in queries with DISTINCT/ALL clauses and multiple whitespace. MDL-25268 $sql = "SELECT DISTINCT course FROM {{$tablename}} diff --git a/lib/tests/datalib_test.php b/lib/tests/datalib_test.php new file mode 100644 index 0000000000000..96e5ce8c71000 --- /dev/null +++ b/lib/tests/datalib_test.php @@ -0,0 +1,90 @@ +. + +/** + * Test for various bits of datalib.php. + * + * @package core + * @category phpunit + * @copyright 2012 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + + +/** + * Test for various bits of datalib.php. + * + * @package core_css + * @category css + * @copyright 2012 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class datalib_testcase extends advanced_testcase { + protected function normalise_sql($sort) { + return preg_replace('~\s+~', ' ', $sort); + } + + protected function assert_same_sql($expected, $actual) { + $this->assertEquals($this->normalise_sql($expected), $this->normalise_sql($actual)); + } + + public function test_users_order_by_sql_simple() { + list($sort, $params) = users_order_by_sql(); + $this->assert_same_sql('lastname, firstname, id', $sort); + $this->assertEquals(array(), $params); + } + + public function test_users_order_by_sql_table_prefix() { + list($sort, $params) = users_order_by_sql('u'); + $this->assert_same_sql('u.lastname, u.firstname, u.id', $sort); + $this->assertEquals(array(), $params); + } + + public function test_users_order_by_sql_search_no_extra_fields() { + global $CFG, $DB; + $CFG->showuseridentity = ''; + $this->resetAfterTest(true); + + list($sort, $params) = users_order_by_sql('', 'search', context_system::instance()); + $this->assert_same_sql('CASE WHEN + ' . $DB->sql_fullname() . ' = :usersortexact1 OR + firstname = :usersortexact2 OR + lastname = :usersortexact3 + THEN 0 ELSE 1 END, lastname, firstname, id', $sort); + $this->assertEquals(array('usersortexact1' => 'search', 'usersortexact2' => 'search', + 'usersortexact3' => 'search'), $params); + } + + public function test_users_order_by_sql_search_with_extra_fields_and_prefix() { + global $CFG, $DB; + $CFG->showuseridentity = 'email,idnumber'; + $this->setAdminUser(); + $this->resetAfterTest(true); + + list($sort, $params) = users_order_by_sql('u', 'search', context_system::instance()); + $this->assert_same_sql('CASE WHEN + ' . $DB->sql_fullname('u.firstname', 'u.lastname') . ' = :usersortexact1 OR + u.firstname = :usersortexact2 OR + u.lastname = :usersortexact3 OR + u.email = :usersortexact4 OR + u.idnumber = :usersortexact5 + THEN 0 ELSE 1 END, u.lastname, u.firstname, u.id', $sort); + $this->assertEquals(array('usersortexact1' => 'search', 'usersortexact2' => 'search', + 'usersortexact3' => 'search', 'usersortexact4' => 'search', 'usersortexact5' => 'search'), $params); + } +} diff --git a/mnet/service/enrol/course.php b/mnet/service/enrol/course.php index d67eaf62bb3d9..97ec77181b0c5 100644 --- a/mnet/service/enrol/course.php +++ b/mnet/service/enrol/course.php @@ -167,13 +167,15 @@ id, $course->remoteid); + WHERE e.hostid = :hostid AND e.remotecourseid = :remotecourseid AND e.enroltype != 'mnet' + ORDER BY $sort"; +$params['hostid'] = $host->id; +$params['remotecourseid'] = $course->remoteid; if ($enrolments = $DB->get_records_sql($sql, $params)) { echo $OUTPUT->heading(get_string('otherenrolledusers', 'mnetservice_enrol'), 3); diff --git a/mnet/service/enrol/locallib.php b/mnet/service/enrol/locallib.php index c54ea2d083a58..50494daf90eaf 100644 --- a/mnet/service/enrol/locallib.php +++ b/mnet/service/enrol/locallib.php @@ -291,6 +291,7 @@ public function req_course_enrolments($mnethostid, $remotecourseid) { if (!empty($usernames)) { list($usql, $params) = $DB->get_in_or_equal($usernames, SQL_PARAMS_NAMED); + list($sort, $sortparams) = users_order_by_sql(); $params['mnetlocalhostid'] = $CFG->mnet_localhost_id; $sql = "SELECT username,id FROM {user} @@ -298,8 +299,8 @@ public function req_course_enrolments($mnethostid, $remotecourseid) { AND username $usql AND deleted = 0 AND confirmed = 1 - ORDER BY lastname,firstname,email"; - $usersbyusername = $DB->get_records_sql($sql, $params); + ORDER BY $sort"; + $usersbyusername = $DB->get_records_sql($sql, array_merge($params, $sortparams)); } else { $usersbyusername = array(); } @@ -489,7 +490,9 @@ public function find_users($search) { WHERE e.hostid = :hostid AND e.remotecourseid = :remotecourseid AND e.enroltype = 'mnet' AND $wherecondition"; - $order = " ORDER BY u.lastname ASC, u.firstname ASC"; + + list($sort, $sortparams) = users_order_by_sql('u'); + $order = " ORDER BY $sort"; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -498,7 +501,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); @@ -576,7 +579,8 @@ public function find_users($search) { FROM {mnetservice_enrol_enrolments} e WHERE (e.hostid = :hostid AND e.remotecourseid = :remotecourseid))"; - $order = " ORDER BY u.lastname ASC, u.firstname ASC"; + list($sort, $sortparams) = users_order_by_sql('u'); + $order = " ORDER BY $sort"; if (!$this->is_validating()) { $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); @@ -585,7 +589,7 @@ public function find_users($search) { } } - $availableusers = $DB->get_records_sql($fields . $sql . $order, $params); + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); if (empty($availableusers)) { return array(); diff --git a/mod/choice/lib.php b/mod/choice/lib.php index e961311ab5a45..b10da50ac7468 100644 --- a/mod/choice/lib.php +++ b/mod/choice/lib.php @@ -720,7 +720,7 @@ function choice_get_response_data($choice, $cm, $groupmode) { /// First get all the users who have access here /// To start with we assume they are all "unanswered" then move them later - $allresponses[0] = get_enrolled_users($context, 'mod/choice:choose', $currentgroup, user_picture::fields('u', array('idnumber')), 'u.lastname ASC,u.firstname ASC'); + $allresponses[0] = get_enrolled_users($context, 'mod/choice:choose', $currentgroup, user_picture::fields('u', array('idnumber'))); /// Get all the recorded responses for this choice $rawresponses = $DB->get_records('choice_answers', array('choiceid' => $choice->id)); diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 6f887739a0e84..3b9ab6cc76422 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -107,13 +107,7 @@ function forum_add_instance($forum, $mform = null) { } if ($forum->forcesubscribe == FORUM_INITIALSUBSCRIBE) { - /// all users should be subscribed initially - /// Note: forum_get_potential_subscribers should take the forum context, - /// but that does not exist yet, becuase the forum is only half build at this - /// stage. However, because the forum is brand new, we know that there are - /// no role assignments or overrides in the forum context, so using the - /// course context gives the same list of users. - $users = forum_get_potential_subscribers($modcontext, 0, 'u.id, u.email', ''); + $users = forum_get_potential_subscribers($modcontext, 0, 'u.id, u.email'); foreach ($users as $user) { forum_subscribe($user->id, $forum->id); } @@ -2857,20 +2851,20 @@ function forum_get_user_discussions($courseid, $userid, $groupid=0) { * @param string $sort sort order. As for get_users_by_capability. * @return array list of users. */ -function forum_get_potential_subscribers($forumcontext, $groupid, $fields, $sort) { +function forum_get_potential_subscribers($forumcontext, $groupid, $fields, $sort = '') { global $DB; // only active enrolled users or everybody on the frontpage list($esql, $params) = get_enrolled_sql($forumcontext, 'mod/forum:allowforcesubscribe', $groupid, true); + if (!$sort) { + list($sort, $sortparams) = users_order_by_sql('u'); + $params = array_merge($params, $sortparams); + } $sql = "SELECT $fields FROM {user} u - JOIN ($esql) je ON je.id = u.id"; - if ($sort) { - $sql = "$sql ORDER BY $sort"; - } else { - $sql = "$sql ORDER BY u.lastname ASC, u.firstname ASC"; - } + JOIN ($esql) je ON je.id = u.id + ORDER BY $sort"; return $DB->get_records_sql($sql, $params); } @@ -7823,6 +7817,7 @@ protected function get_options() { * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class forum_potential_subscriber_selector extends forum_subscriber_selector_base { + const MAX_USERS_PER_PAGE = 100; /** * If set to true EVERYONE in this course is force subscribed to this forum @@ -7862,8 +7857,7 @@ protected function get_options() { /** * Finds all potential users * - * Potential users are determined by checking for users with a capability - * determined in {@see forum_get_potential_subscribers()} + * Potential subscribers are all enroled users who are not already subscribed. * * @param string $search * @return array @@ -7871,28 +7865,57 @@ protected function get_options() { public function find_users($search) { global $DB; - $availableusers = forum_get_potential_subscribers($this->context, $this->currentgroup, $this->required_fields_sql('u'), 'u.firstname ASC, u.lastname ASC'); - - if (empty($availableusers)) { - $availableusers = array(); - } else if ($search) { - $search = strtolower($search); - foreach ($availableusers as $key=>$user) { - if (stripos($user->firstname, $search) === false && stripos($user->lastname, $search) === false) { - unset($availableusers[$key]); - } - } + $whereconditions = array(); + list($wherecondition, $params) = $this->search_sql($search, 'u'); + if ($wherecondition) { + $whereconditions[] = $wherecondition; } - // Unset any existing subscribers - if (count($this->existingsubscribers)>0 && !$this->forcesubscribed) { + if (!$this->forcesubscribed) { + $existingids = array(); foreach ($this->existingsubscribers as $group) { foreach ($group as $user) { - if (array_key_exists($user->id, $availableusers)) { - unset($availableusers[$user->id]); - } + $existingids[$user->id] = 1; } } + if ($existingids) { + list($usertest, $userparams) = $DB->get_in_or_equal( + array_keys($existingids), SQL_PARAMS_NAMED, 'existing', false); + $whereconditions[] = 'u.id ' . $usertest; + $params = array_merge($params, $userparams); + } + } + + if ($whereconditions) { + $wherecondition = 'WHERE ' . implode(' AND ', $whereconditions); + } + + list($esql, $eparams) = get_enrolled_sql($this->context, '', $this->currentgroup, true); + $params = array_merge($params, $eparams); + + $fields = 'SELECT ' . $this->required_fields_sql('u'); + $countfields = 'SELECT COUNT(u.id)'; + + $sql = " FROM {user} u + JOIN ($esql) je ON je.id = u.id + $wherecondition"; + + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $order = ' ORDER BY ' . $sort; + + // Check to see if there are too many to show sensibly. + if (!$this->is_validating()) { + $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params); + if ($potentialmemberscount > self::MAX_USERS_PER_PAGE) { + return $this->too_many_results($search, $potentialmemberscount); + } + } + + // If not, show them. + $availableusers = $DB->get_records_sql($fields . $sql . $order, array_merge($params, $sortparams)); + + if (empty($availableusers)) { + return array(); } if ($this->forcesubscribed) { @@ -7939,16 +7962,16 @@ public function find_users($search) { // only active enrolled or everybody on the frontpage list($esql, $eparams) = get_enrolled_sql($this->context, '', $this->currentgroup, true); - $params = array_merge($params, $eparams); - $fields = $this->required_fields_sql('u'); + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $params = array_merge($params, $eparams, $sortparams); $subscribers = $DB->get_records_sql("SELECT $fields FROM {user} u JOIN ($esql) je ON je.id = u.id JOIN {forum_subscriptions} s ON s.userid = u.id WHERE $wherecondition AND s.forum = :forumid - ORDER BY u.lastname ASC, u.firstname ASC", $params); + ORDER BY $sort", $params); return array(get_string("existingsubscribers", 'forum') => $subscribers); } diff --git a/mod/lesson/essay.php b/mod/lesson/essay.php index 51d35cf576588..887f9cb582232 100644 --- a/mod/lesson/essay.php +++ b/mod/lesson/essay.php @@ -160,12 +160,10 @@ SELECT u.* FROM {user} u JOIN ( - SELECT DISTINCT u.id - FROM {user} u, - {lesson_attempts} a - WHERE a.lessonid = :lessonid and - u.id = a.userid) ui ON (u.id = ui.id) - ORDER BY u.lastname", $params)) { + SELECT DISTINCT userid + FROM {lesson_attempts} + WHERE lessonid = :lessonid + ) ui ON u.id = ui.id", $params)) { print_error('cannotfinduser', 'lesson'); } } @@ -268,6 +266,8 @@ if ($essayattempts = $DB->get_records_select('lesson_attempts', 'pageid '.$usql, $parameters)) { // Get all the users who have taken this lesson, order by their last name $ufields = user_picture::fields('u'); + list($sort, $sortparams) = users_order_by_sql('u'); + $params = array_merge($params, $sortparams); if (!empty($cm->groupingid)) { $params["groupinid"] = $cm->groupingid; $sql = "SELECT DISTINCT $ufields @@ -276,14 +276,14 @@ INNER JOIN {groups_members} gm ON gm.userid = u.id INNER JOIN {groupings_groups} gg ON gm.groupid = :groupinid WHERE a.lessonid = :lessonid - ORDER BY u.lastname"; + ORDER BY $sort"; } else { $sql = "SELECT DISTINCT $ufields FROM {user} u, {lesson_attempts} a WHERE a.lessonid = :lessonid and u.id = a.userid - ORDER BY u.lastname"; + ORDER BY $sort"; } if (!$users = $DB->get_records_sql($sql, $params)) { $mode = 'none'; // not displaying anything diff --git a/mod/lesson/report.php b/mod/lesson/report.php index 1d0461fd0e86f..2d44affe82a7c 100644 --- a/mod/lesson/report.php +++ b/mod/lesson/report.php @@ -43,6 +43,8 @@ $ufields = user_picture::fields('u'); // These fields are enough $params = array("lessonid" => $lesson->id); +list($sort, $sortparams) = users_order_by_sql('u'); +$params = array_merge($params, $sortparams); // TODO: Improve this. Fetching all students always is crazy! if (!empty($cm->groupingid)) { $params["groupid"] = $cm->groupingid; @@ -52,14 +54,14 @@ INNER JOIN {groups_members} gm ON gm.userid = u.id INNER JOIN {groupings_groups} gg ON gm.groupid = :groupid WHERE a.lessonid = :lessonid - ORDER BY u.lastname"; + ORDER BY $sort"; } else { $sql = "SELECT DISTINCT $ufields FROM {user} u, {lesson_attempts} a WHERE a.lessonid = :lessonid and u.id = a.userid - ORDER BY u.lastname"; + ORDER BY $sort"; } if (! $students = $DB->get_records_sql($sql, $params)) { diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index fc2aa97b47ed9..f006e75584adb 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -885,6 +885,7 @@ function quiz_get_recent_mod_activity(&$activities, &$index, $timestart, $tmpactivity->sectionnum = $cm->sectionnum; $tmpactivity->timestamp = $attempt->timefinish; + $tmpactivity->content = new stdClass(); $tmpactivity->content->attemptid = $attempt->id; $tmpactivity->content->attempt = $attempt->attempt; if (quiz_has_grades($quiz) && $options->marks >= question_display_options::MARK_AND_MAX) { @@ -895,6 +896,7 @@ function quiz_get_recent_mod_activity(&$activities, &$index, $timestart, $tmpactivity->content->maxgrade = null; } + $tmpactivity->user = new stdClass(); $tmpactivity->user->id = $attempt->userid; $tmpactivity->user->firstname = $attempt->firstname; $tmpactivity->user->lastname = $attempt->lastname; diff --git a/mod/quiz/override_form.php b/mod/quiz/override_form.php index 8e4fb3d1cb7ac..80976ecef61da 100644 --- a/mod/quiz/override_form.php +++ b/mod/quiz/override_form.php @@ -130,19 +130,25 @@ protected function definition() { } else { // Prepare the list of users. $users = array(); + list($sort, $sortparams) = users_order_by_sql('u'); + if (!empty($sortparams)) { + throw new coding_exception('users_order_by_sql returned some query parameters. ' . + 'This is unexpected, and a problem because there is no way to pass these ' . + 'parameters to get_users_by_capability. See MDL-34657.'); + } if (!empty($CFG->enablegroupmembersonly) && $cm->groupmembersonly) { // Only users from the grouping. $groups = groups_get_all_groups($cm->course, 0, $cm->groupingid); if (!empty($groups)) { $users = get_users_by_capability($this->context, 'mod/quiz:attempt', 'u.id, u.firstname, u.lastname, u.email', - 'firstname ASC, lastname ASC', '', '', array_keys($groups), + $sort, '', '', array_keys($groups), '', false, true); } } else { $users = get_users_by_capability($this->context, 'mod/quiz:attempt', 'u.id, u.firstname, u.lastname, u.email' , - 'firstname ASC, lastname ASC', '', '', '', '', false, true); + $sort, '', '', '', '', false, true); } if (empty($users)) { // Generate an error. diff --git a/mod/quiz/overrides.php b/mod/quiz/overrides.php index 88739209a8682..e6a5d840cd17c 100644 --- a/mod/quiz/overrides.php +++ b/mod/quiz/overrides.php @@ -90,20 +90,22 @@ if ($groupmode) { $colname = get_string('group'); $sql = 'SELECT o.*, g.name - FROM {quiz_overrides} o JOIN {groups} g - ON o.groupid = g.id - WHERE o.quiz = ? + FROM {quiz_overrides} o + JOIN {groups} g ON o.groupid = g.id + WHERE o.quiz = :quizid ORDER BY g.name'; + $params = array('quizid' => $quiz->id); } else { $colname = get_string('user'); + list($sort, $params) = users_order_by_sql('u'); $sql = 'SELECT o.*, u.firstname, u.lastname - FROM {quiz_overrides} o JOIN {user} u - ON o.userid = u.id - WHERE o.quiz = ? - ORDER BY u.lastname, u.firstname'; + FROM {quiz_overrides} o + JOIN {user} u ON o.userid = u.id + WHERE o.quiz = :quizid + ORDER BY ' . $sort; + $params['quizid'] = $quiz->id; } -$params = array($quiz->id); $overrides = $DB->get_records_sql($sql, $params); // Initialise table. diff --git a/mod/workshop/locallib.php b/mod/workshop/locallib.php index 358a2ec7670a7..b42b4c68a3acf 100644 --- a/mod/workshop/locallib.php +++ b/mod/workshop/locallib.php @@ -400,9 +400,10 @@ public function get_potential_authors($musthavesubmission=true, $groupid=0, $lim return array(); } - $sql .= " ORDER BY lastname ASC, firstname ASC, id ASC"; + list($sort, $sortparams) = users_order_by_sql('u'); + $sql .= " ORDER BY $sort"; - return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); + return $DB->get_records_sql($sql, array_merge($params, $sortparams), $limitfrom, $limitnum); } /** @@ -448,9 +449,10 @@ public function get_potential_reviewers($musthavesubmission=false, $groupid=0, $ return array(); } - $sql .= " ORDER BY lastname ASC, firstname ASC, id ASC"; + list($sort, $sortparams) = users_order_by_sql('u'); + $sql .= " ORDER BY $sort"; - return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); + return $DB->get_records_sql($sql, array_merge($params, $sortparams), $limitfrom, $limitnum); } /** @@ -498,9 +500,10 @@ public function get_participants($musthavesubmission=false, $groupid=0, $limitfr return array(); } - $sql .= " ORDER BY lastname ASC, firstname ASC, id ASC"; + list($sort, $sortparams) = users_order_by_sql('u'); + $sql .= " ORDER BY $sort"; - return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); + return $DB->get_records_sql($sql, array_merge($params, $sortparams), $limitfrom, $limitnum); } /** @@ -696,9 +699,10 @@ public function get_submissions($authorid='all', $groupid=0, $limitfrom=0, $limi // $authorid is empty return array(); } - $sql .= " ORDER BY u.lastname, u.firstname"; + list($sort, $sortparams) = users_order_by_sql('u'); + $sql .= " ORDER BY $sort"; - return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); + return $DB->get_records_sql($sql, array_merge($params, $sortparams), $limitfrom, $limitnum); } /** @@ -1030,6 +1034,7 @@ public function get_all_assessments() { $reviewerfields = user_picture::fields('reviewer', null, 'revieweridx', 'reviewer'); $authorfields = user_picture::fields('author', null, 'authorid', 'author'); $overbyfields = user_picture::fields('overby', null, 'gradinggradeoverbyx', 'overby'); + list($sort, $params) = users_order_by_sql('reviewer'); $sql = "SELECT a.id, a.submissionid, a.reviewerid, a.timecreated, a.timemodified, a.grade, a.gradinggrade, a.gradinggradeover, a.gradinggradeoverby, $reviewerfields, $authorfields, $overbyfields, @@ -1040,8 +1045,8 @@ public function get_all_assessments() { INNER JOIN {user} author ON (s.authorid = author.id) LEFT JOIN {user} overby ON (a.gradinggradeoverby = overby.id) WHERE s.workshopid = :workshopid AND s.example = 0 - ORDER BY reviewer.lastname, reviewer.firstname"; - $params = array('workshopid' => $this->id); + ORDER BY $sort"; + $params['workshopid'] = $this->id; return $DB->get_records_sql($sql, $params); } @@ -1106,14 +1111,16 @@ public function get_assessments_of_submission($submissionid) { $reviewerfields = user_picture::fields('reviewer', null, 'revieweridx', 'reviewer'); $overbyfields = user_picture::fields('overby', null, 'gradinggradeoverbyx', 'overby'); + list($sort, $params) = users_order_by_sql('reviewer'); $sql = "SELECT a.*, s.title, $reviewerfields, $overbyfields FROM {workshop_assessments} a INNER JOIN {user} reviewer ON (a.reviewerid = reviewer.id) INNER JOIN {workshop_submissions} s ON (a.submissionid = s.id) LEFT JOIN {user} overby ON (a.gradinggradeoverby = overby.id) WHERE s.example = 0 AND s.id = :submissionid AND s.workshopid = :workshopid - ORDER BY reviewer.lastname, reviewer.firstname, reviewer.id"; - $params = array('submissionid' => $submissionid, 'workshopid' => $this->id); + ORDER BY $sort"; + $params['submissionid'] = $submissionid; + $params['workshopid'] = $this->id; return $DB->get_records_sql($sql, $params); } @@ -1702,6 +1709,7 @@ public function prepare_grading_report_data($userid, $groupid, $page, $perpage, $reviewers = array(); if ($submissions) { list($submissionids, $params) = $DB->get_in_or_equal(array_keys($submissions), SQL_PARAMS_NAMED); + list($sort, $sortparams) = users_order_by_sql('r'); $sql = "SELECT a.id AS assessmentid, a.submissionid, a.grade, a.gradinggrade, a.gradinggradeover, a.weight, r.id AS reviewerid, r.lastname, r.firstname, r.picture, r.imagealt, r.email, s.id AS submissionid, s.authorid @@ -1709,8 +1717,8 @@ public function prepare_grading_report_data($userid, $groupid, $page, $perpage, JOIN {user} r ON (a.reviewerid = r.id) JOIN {workshop_submissions} s ON (a.submissionid = s.id AND s.example = 0) WHERE a.submissionid $submissionids - ORDER BY a.weight DESC, r.lastname, r.firstname"; - $reviewers = $DB->get_records_sql($sql, $params); + ORDER BY a.weight DESC, $sort"; + $reviewers = $DB->get_records_sql($sql, array_merge($params, $sortparams)); foreach ($reviewers as $reviewer) { if (!isset($userinfo[$reviewer->reviewerid])) { $userinfo[$reviewer->reviewerid] = new stdclass(); @@ -1728,6 +1736,7 @@ public function prepare_grading_report_data($userid, $groupid, $page, $perpage, $reviewees = array(); if ($participants) { list($participantids, $params) = $DB->get_in_or_equal(array_keys($participants), SQL_PARAMS_NAMED); + list($sort, $sortparams) = users_order_by_sql('e'); $params['workshopid'] = $this->id; $sql = "SELECT a.id AS assessmentid, a.submissionid, a.grade, a.gradinggrade, a.gradinggradeover, a.reviewerid, a.weight, s.id AS submissionid, @@ -1737,8 +1746,8 @@ public function prepare_grading_report_data($userid, $groupid, $page, $perpage, JOIN {workshop_submissions} s ON (a.submissionid = s.id AND s.example = 0) JOIN {user} e ON (s.authorid = e.id) WHERE u.id $participantids AND s.workshopid = :workshopid - ORDER BY a.weight DESC, e.lastname, e.firstname"; - $reviewees = $DB->get_records_sql($sql, $params); + ORDER BY a.weight DESC, $sort"; + $reviewees = $DB->get_records_sql($sql, array_merge($sortparams)); foreach ($reviewees as $reviewee) { if (!isset($userinfo[$reviewee->authorid])) { $userinfo[$reviewee->authorid] = new stdclass(); diff --git a/report/log/locallib.php b/report/log/locallib.php index cf16be7b64442..fc08362349d6d 100644 --- a/report/log/locallib.php +++ b/report/log/locallib.php @@ -143,7 +143,7 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0, // If looking at a different host, we're interested in all our site users if ($hostid == $CFG->mnet_localhost_id && $course->id != SITEID) { - $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname, u.idnumber', 'lastname ASC, firstname ASC', $limitfrom, $limitnum); + $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname, u.idnumber', null, $limitfrom, $limitnum); } else { // this may be a lot of users :-( $courseusers = $DB->get_records('user', array('deleted'=>0), 'lastaccess DESC', 'id, firstname, lastname, idnumber', $limitfrom, $limitnum); @@ -442,7 +442,7 @@ function report_log_print_selector_form($course, $selecteduser=0, $selecteddate= $limitfrom = empty($showusers) ? 0 : ''; $limitnum = empty($showusers) ? COURSE_MAX_USERS_PER_DROPDOWN + 1 : ''; - $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname', 'lastname ASC, firstname ASC', $limitfrom, $limitnum); + $courseusers = get_enrolled_users($context, '', $selectedgroup, 'u.id, u.firstname, u.lastname', null, $limitfrom, $limitnum); if (count($courseusers) < COURSE_MAX_USERS_PER_DROPDOWN && !$showusers) { $showusers = 1; diff --git a/report/security/locallib.php b/report/security/locallib.php index f6021fd2193b9..e30944fb5ede2 100644 --- a/report/security/locallib.php +++ b/report/security/locallib.php @@ -863,8 +863,9 @@ function report_security_check_riskbackup($detailed=false) { // Get a list of affected users as well $users = array(); + list($sort, $sortparams) = users_order_by_sql('u'); $rs = $DB->get_recordset_sql("SELECT DISTINCT u.id, u.firstname, u.lastname, u.picture, u.imagealt, u.email, ra.contextid, ra.roleid - $sqluserinfo ORDER BY u.lastname, u.firstname", $params); + $sqluserinfo ORDER BY $sort", array_merge($params, $sortparams)); foreach ($rs as $user) { $context = context::instance_by_id($user->contextid); diff --git a/report/stats/locallib.php b/report/stats/locallib.php index 6a901d9939838..bde2b0d6a0c71 100644 --- a/report/stats/locallib.php +++ b/report/stats/locallib.php @@ -107,18 +107,25 @@ function report_stats_report($course, $report, $mode, $user, $roleid, $time) { $table->width = 'auto'; if ($mode == STATS_MODE_DETAILED) { - $param = stats_get_parameters($time,null,$course->id,$mode); // we only care about the table and the time string (if we have time) - - //TODO: lceanup this ugly mess - $sql = 'SELECT DISTINCT s.userid, u.firstname, u.lastname, u.idnumber - FROM {stats_user_'.$param->table.'} s - JOIN {user} u ON u.id = s.userid - WHERE courseid = '.$course->id - . ((!empty($param->stattype)) ? ' AND stattype = \''.$param->stattype.'\'' : '') - . ((!empty($time)) ? ' AND timeend >= '.$param->timeafter : '') - .' ORDER BY u.lastname, u.firstname ASC'; - - if (!$us = $DB->get_records_sql($sql, $param->params)) { + $param = stats_get_parameters($time, null, $course->id, $mode); // we only care about the table and the time string (if we have time) + + list($sort, $moreparams) = users_order_by_sql('u'); + $moreparams['courseid'] = $course->id; + $sql = "SELECT DISTINCT s.userid, u.firstname, u.lastname, u.idnumber + FROM {stats_user_{$param->table}} s + JOIN {user} u ON u.id = s.userid + WHERE courseid = :courseid"; + if (!empty($param->stattype)) { + $sql .= " AND stattype = :stattype"; + $moreparams['stattype'] = $param->stattype; + } + if (!empty($time)) { + $sql .= " AND timeend >= :timeafter"; + $moreparams['timeafter'] = $param->timeafter; + } + $sql .= " ORDER BY {$sort}"; + + if (!$us = $DB->get_records_sql($sql, array_merge($param->params, $moreparams))) { print_error('nousers'); } diff --git a/user/selector/lib.php b/user/selector/lib.php index c1bdb2a7794a0..52b1b1bf7df7c 100644 --- a/user/selector/lib.php +++ b/user/selector/lib.php @@ -737,7 +737,7 @@ public function find_users($search) { list($wherecondition, $params) = $this->search_sql($search, 'u'); $roles = groups_get_members_by_role($this->groupid, $this->courseid, $this->required_fields_sql('u') . ', gm.component', - 'u.lastname, u.firstname', $wherecondition, $params); + null, $wherecondition, $params); return $this->convert_array_format($roles, $search); } } @@ -846,7 +846,9 @@ public function find_users($search) { WHERE u.deleted = 0 AND gm.id IS NULL AND $searchcondition"; - $orderby = "ORDER BY u.lastname, u.firstname"; + + list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext); + $orderby = ' ORDER BY ' . $sort; $params = array_merge($searchparams, $roleparams, $enrolparams); $params['courseid'] = $this->courseid; @@ -859,7 +861,7 @@ public function find_users($search) { } } - $rs = $DB->get_recordset_sql("$fields $sql $orderby", $params); + $rs = $DB->get_recordset_sql("$fields $sql $orderby", array_merge($params, $sortparams)); $roles = groups_calculate_role_people($rs, $context); //don't hold onto user IDs if we're doing validation diff --git a/user/selector/module.js b/user/selector/module.js index 26a017ddf3fbd..8ecd5aa42f76a 100644 --- a/user/selector/module.js +++ b/user/selector/module.js @@ -237,6 +237,7 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc option.set('disabled', true); } else if (selectedusers===true || selectedusers[userid]) { option.set('selected', true); + delete selectedusers[userid]; } else { option.set('selected', false); }