MDL-34657 datalib: function to generate user sort sql.

The purpose of this method is to ensure that when we display lists of
users in different places, the default sort order is consistent.

Having this code centralised in one place them makes it possible to
improve things accross the board, and there is an example of that here.
There is logic so that if we are searching for particular string, then
users with an exact match are sorted first.
This commit is contained in:
Tim Hunt
2012-09-27 12:41:41 +01:00
parent 8e4f6bb1d4
commit 9f82ddd66f
2 changed files with 182 additions and 1 deletions
+92 -1
View File
@@ -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) {
+90
View File
@@ -0,0 +1,90 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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);
}
}