diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-03-14 23:01:38 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-03-14 23:01:38 +0000 |
commit | 3b3050959952ceae617b59246f364f4b0edd2dcd (patch) | |
tree | b7cc39b97156ee0f346334d1e8dd78b5662c40e7 /modules/user/user.module | |
parent | 8a0d326a8e134ad4261b9575ce073f9e44b72f60 (diff) | |
download | brdo-3b3050959952ceae617b59246f364f4b0edd2dcd.tar.gz brdo-3b3050959952ceae617b59246f364f4b0edd2dcd.tar.bz2 |
#347250 by catch, drewish, and Berdir: Add function for loading multiple users in one request.
Diffstat (limited to 'modules/user/user.module')
-rw-r--r-- | modules/user/user.module | 241 |
1 files changed, 177 insertions, 64 deletions
diff --git a/modules/user/user.module b/modules/user/user.module index 76fd2834d..d63f27cbd 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -160,77 +160,191 @@ function user_external_login($account, $edit = array()) { } /** - * Fetch a user object. + * Load multiple users based on certain conditions. * - * @param $array - * An associative array of attributes to search for in selecting the - * user, such as user name or e-mail address. + * This function should be used whenever you need to load more than one user + * from the database. Users are loaded into memory and will not require + * database access if loaded again during the same page request. * + * @param $uids + * An array of user IDs. + * @param $conditions + * An array of conditions to match against the {users} table. These + * should be supplied in the form array('field_name' => 'field_value'). + * @param $reset + * A boolean indicating that the internal cache should be reset. Use this if + * loading a user object which has been altered during the page request. * @return - * A fully-loaded $user object upon successful user load or FALSE if user - * cannot be loaded. + * An array of user objects, indexed by uid. + * + * @see user_load() + * @see user_load_by_mail() + * @see user_load_by_name() */ -function user_load($array = array()) { - // Dynamically compose a SQL query: - $query = array(); - $params = array(); - - if (is_numeric($array)) { - $array = array('uid' => $array); - } - elseif (!is_array($array)) { - return FALSE; +function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) { + static $user_cache = array(); + if ($reset) { + $user_cache = array(); } - foreach ($array as $key => $value) { - if ($key == 'uid' || $key == 'status') { - $query[] = "$key = %d"; - $params[] = $value; - } - elseif ($key == 'pass') { - $query[] = "pass = '%s'"; - $params[] = $value; - } - else { - $query[]= "LOWER($key) = LOWER('%s')"; - $params[] = $value; + $users = array(); + + // Create a new variable which is either a prepared version of the $uids + // array for later comparison with the user cache, or FALSE if no $uids were + // passed. The $uids array is reduced as items are loaded from cache, and we + // need to know if it's empty for this reason to avoid querying the database + // when all requested users are loaded from cache. + $passed_uids = !empty($uids) ? array_flip($uids) : FALSE; + + // Load any available users from the internal cache. + if ($user_cache) { + if ($uids && !$conditions) { + $users += array_intersect_key($user_cache, $passed_uids); + // If any users were loaded, remove them from the $uids still to load. + $uids = array_keys(array_diff_key($passed_uids, $users)); } } - $result = db_query('SELECT * FROM {users} u WHERE ' . implode(' AND ', $query), $params); - if ($user = db_fetch_object($result)) { - $user = drupal_unpack($user); + // Load any remaining users from the database, this is necessary if we have + // $uids still to load, or if $conditions was passed without $uids. + if ($uids || ($conditions && !$passed_uids)) { + $query = db_select('users', 'u')->fields('u'); - $user->roles = array(); - if ($user->uid) { - $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; + // If the $uids array is populated, add those to the query. + if ($uids) { + $query->condition('u.uid', $uids, 'IN'); } - else { - $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; + // If the conditions array is populated, add those to the query. + if ($conditions) { + // TODO D7: Using LIKE() to get a case insensitive comparison because Crell + // and chx promise that dbtng will map it to ILIKE in postgres. + if (isset($conditions['name'])) { + $query->condition('u.name', $conditions['name'], 'LIKE'); + unset($conditions['name']); + } + if (isset($conditions['mail'])) { + $query->condition('u.mail', $conditions['mail'], 'LIKE'); + unset($conditions['mail']); + } + foreach ($conditions as $field => $value) { + $query->condition('u.' . $field, $value); + } } - $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid); - while ($role = db_fetch_object($result)) { - $user->roles[$role->rid] = $role->name; + $result = $query->execute(); + + $queried_users = array(); + // Build an array of user picture IDs so that these can be fetched later. + $picture_fids = array(); + foreach ($result as $record) { + $picture_fids[] = $record->picture; + $queried_users[$record->uid] = drupal_unpack($record); + $queried_users[$record->uid]->roles = array(); + if ($record->uid) { + $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; + } + else { + $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user'; + } } - // Attach fields. - // TODO D7 : not sure the 3rd param ($types) is needed. - field_attach_load('user', array($user->uid => $user)); + if (!empty($queried_users)) { + // Add any additional roles from the database. + $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users))); + foreach ($result as $record) { + $queried_users[$record->uid]->roles[$record->rid] = $record->name; + } - if (!empty($user->picture) && ($file = file_load($user->picture))) { - $user->picture = $file; - } - else { - $user->picture = NULL; - } + // Add the full file objects for user pictures if enabled. + if (!empty($picture_fids) && variable_get('user_pictures', 1) == 1) { + $pictures = file_load_multiple($picture_fids); + foreach ($queried_users as $account) { + if (!empty($account->picture) && isset($pictures[$account->picture])) { + $account->picture = $pictures[$account->picture]; + } + else { + $account->picture = NULL; + } + } + } + + // Invoke hook_user_load() on the users loaded from the database + // and add them to the static cache. + foreach (module_implements('user_load') as $module) { + $function = $module . '_user_load'; + $function($queried_users); + } - user_module_invoke('load', $array, $user); + // TODO D7 : not sure the 3rd param ($types) is needed. + field_attach_load('user', $queried_users); + + $users = $users + $queried_users; + $user_cache = $user_cache + $queried_users; + } } - else { - $user = FALSE; + + // Ensure that the returned array is ordered the same as the original $uids + // array if this was passed in and remove any invalid uids. + if ($passed_uids) { + // Remove any invalid uids from the array. + $passed_uids = array_intersect_key($passed_uids, $users); + foreach ($users as $user) { + $passed_uids[$user->uid] = $user; + } + $users = $passed_uids; } - return $user; + return $users; +} + + +/** + * Fetch a user object. + * + * @param $uid + * Integer specifying the user id. + * @param $reset + * A boolean indicating that the internal cache should be reset. + * @return + * A fully-loaded $user object upon successful user load or FALSE if user + * cannot be loaded. + * + * @see user_load_multiple() + */ +function user_load($uid, $reset = FALSE) { + $users = user_load_multiple(array($uid), array(), $reset); + return reset($users); +} + +/** + * Fetch a user object by email address. + * + * @param $mail + * String with the account's e-mail address. + * @return + * A fully-loaded $user object upon successful user load or FALSE if user + * cannot be loaded. + * + * @see user_load_multiple() + */ +function user_load_by_mail($mail) { + $users = user_load_multiple(array(), array('mail' => $mail)); + return reset($users); +} + +/** + * Fetch a user object by account name. + * + * @param $name + * String with the account's user name. + * @return + * A fully-loaded $user object upon successful user load or FALSE if user + * cannot be loaded. + * + * @see user_load_multiple() + */ +function user_load_by_name($name) { + $users = user_load_multiple(array(), array('name' => $name)); + return reset($users); } /** @@ -374,7 +488,7 @@ function user_save($account, $edit = array(), $category = 'account') { field_attach_update('user', $obj); // Refresh user object. - $user = user_load(array('uid' => $account->uid)); + $user = user_load($account->uid, TRUE); // Send emails after we have the new user object. if (isset($edit['status']) && $edit['status'] != $account->status) { @@ -404,7 +518,7 @@ function user_save($account, $edit = array(), $category = 'account') { } // Build the initial user object. - $user = user_load(array('uid' => $edit['uid'])); + $user = user_load($edit['uid'], TRUE); $obj = (object) $edit; field_attach_insert('user', $obj); @@ -438,7 +552,7 @@ function user_save($account, $edit = array(), $category = 'account') { } // Build the finished user object. - $user = user_load(array('uid' => $edit['uid'])); + $user = user_load($edit['uid'], TRUE); } return $user; @@ -1291,7 +1405,6 @@ function user_menu() { 'access callback' => 'user_edit_access', 'access arguments' => array(1), 'type' => MENU_LOCAL_TASK, - 'load arguments' => array('%map', '%index'), ); $items['user/%user_category/edit/account'] = array( @@ -1554,8 +1667,8 @@ function user_authenticate($form_values = array()) { db_query("UPDATE {users} SET pass = '%s' WHERE uid = %d", $new_hash, $account->uid); } } - $account = user_load(array('uid' => $account->uid, 'status' => 1)); - $user = $account; + $users = user_load_multiple(array($account->uid), array('status' => '1')); + $user = reset($users); user_authenticate_finalize($form_values); return $user; } @@ -1608,7 +1721,7 @@ function user_login_submit($form, &$form_state) { function user_external_login_register($name, $module) { global $user; - $existing_user = user_load(array('name' => $name)); + $existing_user = user_load_by_name($name); if (isset($existing_user->uid)) { $user = $existing_user; } @@ -1799,7 +1912,7 @@ function user_edit_form(&$form_state, $uid, $edit, $register = FALSE) { function user_cancel($edit, $uid, $method) { global $user; - $account = user_load(array('uid' => $uid)); + $account = user_load($uid); if (!$account) { drupal_set_message(t('The user account %id does not exist.', array('%id' => $uid)), 'error'); @@ -2110,7 +2223,7 @@ function user_user_operations($form_state = array()) { */ function user_user_operations_unblock($accounts) { foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); + $account = user_load($uid); // Skip unblocking user if they are already unblocked. if ($account !== FALSE && $account->status == 0) { user_save($account, array('status' => 1)); @@ -2123,7 +2236,7 @@ function user_user_operations_unblock($accounts) { */ function user_user_operations_block($accounts) { foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); + $account = user_load($uid); // Skip blocking user if they are already blocked. if ($account !== FALSE && $account->status == 1) { user_save($account, array('status' => 0)); @@ -2142,7 +2255,7 @@ function user_multiple_role_edit($accounts, $operation, $rid) { switch ($operation) { case 'add_role': foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); + $account = user_load($uid); // Skip adding the role to the user if they already have it. if ($account !== FALSE && !isset($account->roles[$rid])) { $roles = $account->roles + array($rid => $role_name); @@ -2152,7 +2265,7 @@ function user_multiple_role_edit($accounts, $operation, $rid) { break; case 'remove_role': foreach ($accounts as $uid) { - $account = user_load(array('uid' => (int)$uid)); + $account = user_load($uid); // Skip removing the role from the user if they already don't have it. if ($account !== FALSE && isset($account->roles[$rid])) { $roles = array_diff($account->roles, array($rid => $role_name)); |