Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.944 diff -u -p -r1.944 user.module --- modules/user/user.module 29 Nov 2008 09:33:51 -0000 1.944 +++ modules/user/user.module 15 Dec 2008 14:33:45 -0000 @@ -133,65 +133,160 @@ function user_external_login($account, $ } /** - * 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 add to the query. + * @param $reset + * Whether to reset the internal cache. * * @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. */ -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; - } - - foreach ($array as $key => $value) { - if ($key == 'uid' || $key == 'status') { - $query[] = "$key = %d"; - $params[] = $value; - } - elseif ($key == 'pass') { - $query[] = "pass = '%s'"; - $params[] = $value; +function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) { + static $user_cache = array(); + if ($reset) { + $user_cache = array(); + } + + $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) { + $users += array_intersect_key($user_cache, $passed_uids); + // If any users were loaded, remove them from the $uids still to load. } - else { - $query[]= "LOWER($key) = LOWER('%s')"; - $params[] = $value; + // If only conditions is passed, load all users from the cache. Users + // which don't match conditions will be removed later. + elseif ($conditions) { + $users = $user_cache; + } + } + + // Remove any loaded users from the array if they don't match $conditions. + if ($conditions) { + foreach ($users as $user) { + $user_values = (array) $user; + if (isset($conditions['name']) && strcasecmp($conditions['name'], $user_values['name'] !== 0)) { + unset($users[$user->uid]); + } + if (isset($conditions['mail']) && strcasecmp($conditions['mail'], $user_values['mail'] !== 0)) { + unset($users[$user->uid]); + } + elseif (array_diff_assoc($conditions, $user_values)) { + unset($users[$user->uid]); + } } } - $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'); + $user_fields = drupal_schema_fields_sql('users'); + $query->fields('u', $user_fields); - $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) { + 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->conditions('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(); + foreach ($result as $record) { + $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'; + } + } + $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 (' . db_placeholders(array_keys($queried_users)) . ')', array_keys($queried_users)); + foreach ($result as $record) { + $queried_users[$record->uid]->roles[$record->rid] = $record->name; + } + + // Invoke hook_user_load() on the users loaded from the database + // and add them to the static cache. + if (!empty($queried_users)) { + foreach (module_implements('user_load') as $module) { + $function = $module . '_user_load'; + $function($queried_users); + } + $users += $queried_users; + $user_cache += $queried_users; } - user_module_invoke('load', $array, $user); } - 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 $conditions + * An associative array of attributes to search for in selecting the + * user, such as user name or e-mail address. + * + * @return + * A fully-loaded $user object upon successful user load or FALSE if user + * cannot be loaded. + */ +function user_load($conditions = array(), $reset = FALSE) { + $uids = array(); + + if (is_numeric($conditions)) { + $uids = array($conditions); + $conditions = array(); + } + elseif (isset($conditions['uid'])) { + $uids = array($conditions['uid']); + unset($conditions['uid']); + } + $users = user_load_multiple($uids, $conditions, $reset); + return reset($users); } /**