mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 04:52:36 +02:00
MDL-26956 (1) Library: Move search SQL function to datalib
This function used to be in the user selector, but it is useful in other areas where we want to search for users as it handles a number of search options (including extra fields, etc.) and returns SQL which can be included in a joined query. A unit test has been added to check the results of these searches.
This commit is contained in:
parent
d8201d49d8
commit
b2ec866fc7
@ -190,6 +190,95 @@ function search_users($courseid, $groupid, $searchtext, $sort='', array $excepti
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SQL used to search through user table to find users (in a query
|
||||
* which may also join and apply other conditions).
|
||||
*
|
||||
* You can combine this SQL with an existing query by adding 'AND $sql' to the
|
||||
* WHERE clause of your query (where $sql is the first element in the array
|
||||
* returned by this function), and merging in the $params array to the parameters
|
||||
* of your query (where $params is the second element). Your query should use
|
||||
* named parameters such as :param, rather than the question mark style.
|
||||
*
|
||||
* There are examples of basic usage in the unit test for this function.
|
||||
*
|
||||
* @param string $search the text to search for (empty string = find all)
|
||||
* @param string $u the table alias for the user table in the query being
|
||||
* built. May be ''.
|
||||
* @param bool $searchanywhere If true (default), searches in the middle of
|
||||
* names, otherwise only searches at start
|
||||
* @param array $extrafields Array of extra user fields to include in search
|
||||
* @param array $exclude Array of user ids to exclude (empty = don't exclude)
|
||||
* @param array $includeonly If specified, only returns users that have ids
|
||||
* incldued in this array (empty = don't restrict)
|
||||
* @return array an array with two elements, a fragment of SQL to go in the
|
||||
* where clause the query, and an associative array containing any required
|
||||
* parameters (using named placeholders).
|
||||
*/
|
||||
function users_search_sql($search, $u = 'u', $searchanywhere = true, array $extrafields = array(),
|
||||
array $exclude = array(), array $includeonly = array()) {
|
||||
global $DB, $CFG;
|
||||
$params = array();
|
||||
$tests = array();
|
||||
|
||||
if ($u) {
|
||||
$u .= '.';
|
||||
}
|
||||
|
||||
// If we have a $search string, put a field LIKE '$search%' condition on each field.
|
||||
if ($search) {
|
||||
$conditions = array(
|
||||
$DB->sql_fullname($u . 'firstname', $u . 'lastname'),
|
||||
$conditions[] = $u . 'lastname'
|
||||
);
|
||||
foreach ($extrafields as $field) {
|
||||
$conditions[] = $u . $field;
|
||||
}
|
||||
if ($searchanywhere) {
|
||||
$searchparam = '%' . $search . '%';
|
||||
} else {
|
||||
$searchparam = $search . '%';
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($conditions as $key => $condition) {
|
||||
$conditions[$key] = $DB->sql_like($condition, ":con{$i}00", false, false);
|
||||
$params["con{$i}00"] = $searchparam;
|
||||
$i++;
|
||||
}
|
||||
$tests[] = '(' . implode(' OR ', $conditions) . ')';
|
||||
}
|
||||
|
||||
// Add some additional sensible conditions.
|
||||
$tests[] = $u . "id <> :guestid";
|
||||
$params['guestid'] = $CFG->siteguest;
|
||||
$tests[] = $u . 'deleted = 0';
|
||||
$tests[] = $u . 'confirmed = 1';
|
||||
|
||||
// If we are being asked to exclude any users, do that.
|
||||
if (!empty($exclude)) {
|
||||
list($usertest, $userparams) = $DB->get_in_or_equal($exclude, SQL_PARAMS_NAMED, 'ex', false);
|
||||
$tests[] = $u . 'id ' . $usertest;
|
||||
$params = array_merge($params, $userparams);
|
||||
}
|
||||
|
||||
// If we are validating a set list of userids, add an id IN (...) test.
|
||||
if (!empty($includeonly)) {
|
||||
list($usertest, $userparams) = $DB->get_in_or_equal($includeonly, SQL_PARAMS_NAMED, 'val');
|
||||
$tests[] = $u . 'id ' . $usertest;
|
||||
$params = array_merge($params, $userparams);
|
||||
}
|
||||
|
||||
// In case there are no tests, add one result (this makes it easier to combine
|
||||
// this with an existing query as you can always add AND $sql).
|
||||
if (empty($tests)) {
|
||||
$tests[] = '1 = 1';
|
||||
}
|
||||
|
||||
// Combing the conditions and return.
|
||||
return array(implode(' AND ', $tests), $params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -43,6 +43,121 @@ class datalib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($this->normalise_sql($expected), $this->normalise_sql($actual));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a test of the user search SQL with database users.
|
||||
*/
|
||||
public function test_users_search_sql() {
|
||||
global $DB;
|
||||
|
||||
// Set up test users.
|
||||
$this->resetAfterTest(true);
|
||||
$user1 = array(
|
||||
'username' => 'usernametest1',
|
||||
'idnumber' => 'idnumbertest1',
|
||||
'firstname' => 'First Name User Test 1',
|
||||
'lastname' => 'Last Name User Test 1',
|
||||
'email' => 'usertest1@email.com',
|
||||
'address' => '2 Test Street Perth 6000 WA',
|
||||
'phone1' => '01010101010',
|
||||
'phone2' => '02020203',
|
||||
'icq' => 'testuser1',
|
||||
'skype' => 'testuser1',
|
||||
'yahoo' => 'testuser1',
|
||||
'aim' => 'testuser1',
|
||||
'msn' => 'testuser1',
|
||||
'department' => 'Department of user 1',
|
||||
'institution' => 'Institution of user 1',
|
||||
'description' => 'This is a description for user 1',
|
||||
'descriptionformat' => FORMAT_MOODLE,
|
||||
'city' => 'Perth',
|
||||
'url' => 'http://moodle.org',
|
||||
'country' => 'au'
|
||||
);
|
||||
$user1 = self::getDataGenerator()->create_user($user1);
|
||||
$user2 = array(
|
||||
'username' => 'usernametest2',
|
||||
'idnumber' => 'idnumbertest2',
|
||||
'firstname' => 'First Name User Test 2',
|
||||
'lastname' => 'Last Name User Test 2',
|
||||
'email' => 'usertest2@email.com',
|
||||
'address' => '222 Test Street Perth 6000 WA',
|
||||
'phone1' => '01010101010',
|
||||
'phone2' => '02020203',
|
||||
'icq' => 'testuser1',
|
||||
'skype' => 'testuser1',
|
||||
'yahoo' => 'testuser1',
|
||||
'aim' => 'testuser1',
|
||||
'msn' => 'testuser1',
|
||||
'department' => 'Department of user 2',
|
||||
'institution' => 'Institution of user 2',
|
||||
'description' => 'This is a description for user 2',
|
||||
'descriptionformat' => FORMAT_MOODLE,
|
||||
'city' => 'Perth',
|
||||
'url' => 'http://moodle.org',
|
||||
'country' => 'au'
|
||||
);
|
||||
$user2 = self::getDataGenerator()->create_user($user2);
|
||||
|
||||
// Search by name (anywhere in text).
|
||||
list($sql, $params) = users_search_sql('User Test 2', '');
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Search by (most of) full name.
|
||||
list($sql, $params) = users_search_sql('First Name User Test 2 Last Name User', '');
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Search by name (start of text) valid or not.
|
||||
list($sql, $params) = users_search_sql('User Test 2', '', false);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertEquals(0, count($results));
|
||||
list($sql, $params) = users_search_sql('First Name User Test 2', '', false);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Search by extra fields included or not (address).
|
||||
list($sql, $params) = users_search_sql('Test Street', '', true);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertEquals(0, count($results));
|
||||
list($sql, $params) = users_search_sql('Test Street', '', true, array('address'));
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertEquals(2, count($results));
|
||||
|
||||
// Exclude user.
|
||||
list($sql, $params) = users_search_sql('User Test', '', true, array(), array($user1->id));
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Include only user.
|
||||
list($sql, $params) = users_search_sql('User Test', '', true, array(), array(), array($user1->id));
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertTrue(array_key_exists($user1->id, $results));
|
||||
$this->assertFalse(array_key_exists($user2->id, $results));
|
||||
|
||||
// Join with another table and use different prefix.
|
||||
set_user_preference('amphibian', 'frog', $user1);
|
||||
set_user_preference('amphibian', 'salamander', $user2);
|
||||
list($sql, $params) = users_search_sql('User Test 1', 'qq');
|
||||
$results = $DB->get_records_sql("
|
||||
SELECT
|
||||
up.id, up.value
|
||||
FROM
|
||||
{user} qq
|
||||
JOIN {user_preferences} up ON up.userid = qq.id
|
||||
WHERE
|
||||
up.name = :prefname
|
||||
AND $sql", array_merge(array('prefname' => 'amphibian'), $params));
|
||||
$this->assertEquals(1, count($results));
|
||||
foreach ($results as $record) {
|
||||
$this->assertEquals('frog', $record->value);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_users_order_by_sql_simple() {
|
||||
list($sort, $params) = users_order_by_sql();
|
||||
$this->assert_same_sql('lastname, firstname, id', $sort);
|
||||
|
@ -434,63 +434,8 @@ abstract class user_selector_base {
|
||||
* this uses ? style placeholders.
|
||||
*/
|
||||
protected function search_sql($search, $u) {
|
||||
global $DB, $CFG;
|
||||
$params = array();
|
||||
$tests = array();
|
||||
|
||||
if ($u) {
|
||||
$u .= '.';
|
||||
}
|
||||
|
||||
// If we have a $search string, put a field LIKE '$search%' condition on each field.
|
||||
if ($search) {
|
||||
$conditions = array(
|
||||
$DB->sql_fullname($u . 'firstname', $u . 'lastname'),
|
||||
$conditions[] = $u . 'lastname'
|
||||
);
|
||||
foreach ($this->extrafields as $field) {
|
||||
$conditions[] = $u . $field;
|
||||
}
|
||||
if ($this->searchanywhere) {
|
||||
$searchparam = '%' . $search . '%';
|
||||
} else {
|
||||
$searchparam = $search . '%';
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($conditions as $key=>$condition) {
|
||||
$conditions[$key] = $DB->sql_like($condition, ":con{$i}00", false, false);
|
||||
$params["con{$i}00"] = $searchparam;
|
||||
$i++;
|
||||
}
|
||||
$tests[] = '(' . implode(' OR ', $conditions) . ')';
|
||||
}
|
||||
|
||||
// Add some additional sensible conditions
|
||||
$tests[] = $u . "id <> :guestid";
|
||||
$params['guestid'] = $CFG->siteguest;
|
||||
$tests[] = $u . 'deleted = 0';
|
||||
$tests[] = $u . 'confirmed = 1';
|
||||
|
||||
// If we are being asked to exclude any users, do that.
|
||||
if (!empty($this->exclude)) {
|
||||
list($usertest, $userparams) = $DB->get_in_or_equal($this->exclude, SQL_PARAMS_NAMED, 'ex', false);
|
||||
$tests[] = $u . 'id ' . $usertest;
|
||||
$params = array_merge($params, $userparams);
|
||||
}
|
||||
|
||||
// If we are validating a set list of userids, add an id IN (...) test.
|
||||
if (!empty($this->validatinguserids)) {
|
||||
list($usertest, $userparams) = $DB->get_in_or_equal($this->validatinguserids, SQL_PARAMS_NAMED, 'val');
|
||||
$tests[] = $u . 'id ' . $usertest;
|
||||
$params = array_merge($params, $userparams);
|
||||
}
|
||||
|
||||
if (empty($tests)) {
|
||||
$tests[] = '1 = 1';
|
||||
}
|
||||
|
||||
// Combing the conditions and return.
|
||||
return array(implode(' AND ', $tests), $params);
|
||||
return users_search_sql($search, 'u', $this->searchanywhere, $this->extrafields,
|
||||
$this->exclude, $this->validatinguserids);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user