realname.module in Real Name 7
Same filename and directory in other branches
Provides token-based name displays for users.
@todo Add a 'view realname' permission enabled by default @todo Allow users to login with their real name @todo Disable the username field
File
realname.moduleView source
<?php
/**
* @file
* Provides token-based name displays for users.
*
* @todo Add a 'view realname' permission enabled by default
* @todo Allow users to login with their real name
* @todo Disable the username field
*/
/**
* @defgroup realname Real name API
*/
/**
* Implements hook_help().
*/
function realname_help($path, $arg) {
switch ($path) {
// Main module help for the Realname module.
case 'admin/config/people/realname':
case 'admin/help#realname':
return '<p>' . t("A Real Name is what the site developer decides that users' names should look like. It is constructed from various tokens that are available within the site.") . '</p>';
}
}
/**
* Implements hook_permission().
*/
function realname_permission() {
return array(
'administer realname' => array(
'title' => t('Administer Real Name'),
'description' => t('Allows users to administer realname settings.'),
),
);
}
/**
* Implements hook_menu().
*/
function realname_menu() {
$items['admin/config/people/realname'] = array(
'title' => 'Real name',
'description' => 'Use tokens to configure how user names are displayed.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'realname_settings_form',
),
'access arguments' => array(
'administer realname',
),
'file' => 'realname.admin.inc',
);
$items['realname/autocomplete'] = array(
'page callback' => 'realname_autocomplete',
'page arguments' => array(
'',
'',
2,
),
'access arguments' => array(
'access user profiles',
),
'type' => MENU_CALLBACK,
);
$items['realname/autocomplete/%/%/%'] = array(
'page callback' => 'realname_autocomplete',
'page arguments' => array(
2,
3,
4,
),
'access callback' => 'realname_autocomplete_access_callback',
'access arguments' => array(
2,
3,
4,
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_menu_alter().
*
* Replace user autocomplete with realname autocomplete.
*/
function realname_menu_alter(&$items) {
// Implement realname autocomplete.
$items['user/autocomplete']['page callback'] = 'realname_autocomplete';
$items['user/autocomplete']['page arguments'] = array(
'',
'',
2,
);
}
/**
* Implements hook_field_extra_fields().
*/
function realname_field_extra_fields() {
$fields['user']['user']['display']['realname'] = array(
'label' => t('Real name'),
'description' => t('Real name'),
'weight' => -1,
);
return $fields;
}
/**
* Implements hook_username_alter().
*/
function realname_username_alter(&$name, $account) {
static $in_username_alter = FALSE;
if (empty($account->uid)) {
// Don't alter anonymous users or objects that do not have any user ID.
return;
}
// Real name was loaded/generated via hook_user_load(), so re-use it.
if (isset($account->realname)) {
if (drupal_strlen($account->realname)) {
// Only if the real name is a non-empty string is $name actually altered.
$name = $account->realname;
}
return;
}
// Real name was not yet available for the account so we need to generate it.
// Because tokens may call format_username() we need to prevent recursion.
if (!$in_username_alter) {
$in_username_alter = TRUE;
// If $account->realname was undefined, then the user account object was
// not properly loaded. We must enforce calling user_load().
if ($realname_account = user_load($account->uid)) {
realname_username_alter($name, $realname_account);
}
$in_username_alter = FALSE;
}
}
/**
* Implements hook_user_load().
*/
function realname_user_load($accounts) {
$realnames = realname_load_multiple($accounts);
foreach ($realnames as $uid => $realname) {
$accounts[$uid]->realname = $realname;
}
}
/**
* Implements hook_user_update().
*/
function realname_user_update(&$edit, $account, $category) {
// Since user data may have changed, update the realname and its cache.
$realnames =& drupal_static('realname_load_multiple', array());
$realnames[$account->uid] = realname_update($account);
}
/**
* Implements hook_profile2_update().
*/
function realname_profile2_update($profile) {
$account = user_load($profile->uid);
if (is_object($account)) {
realname_update($account);
}
}
/**
* Implements hook_user_delete().
*/
function realname_user_delete($account) {
realname_delete($account->uid);
}
/**
* Implements hook_user_view().
*/
function realname_user_view($account, $view_mode, $langcode) {
if (user_view_access($account)) {
$markup = l($account->realname, 'user/' . $account->uid);
}
else {
$markup = check_plain($account->realname);
}
$account->content['realname'] = array(
'#entity_type' => 'custom',
'#bundle' => 'custom',
'#field_type' => 'text',
'#theme' => 'field',
'#field_name' => 'realname',
'#title' => t('Real name'),
'#label_display' => 'inline',
'#items' => array(
TRUE,
),
0 => array(
'#markup' => $markup,
),
);
}
/**
* Implements hook_user_operations().
*/
function realname_user_operations() {
$operations['realname_update'] = array(
'label' => t('Update real name'),
'callback' => 'realname_user_operations_realname_update',
);
return $operations;
}
/**
* Callback function for admin mass generating user real names.
*
* @param array $uids
* An array of user IDs.
*/
function realname_user_operations_realname_update(array $uids) {
$accounts = user_load_multiple($uids);
foreach ($accounts as $account) {
realname_update($account);
}
}
/**
* Implements hook_action_info().
*/
function realname_action_info() {
$info['realname_action_realname_update'] = array(
'type' => 'user',
'label' => t('Update real name'),
'configurable' => FALSE,
);
return $info;
}
/**
* Implements hook_rules_action_info().
*/
function realname_rules_action_info() {
$items['user_realname_update'] = array(
'label' => t('Update real name'),
'base' => 'realname_action_realname_update',
'parameter' => array(
'account' => array(
'type' => 'user',
'label' => t('User'),
'save' => FALSE,
),
),
'group' => t('User'),
'access callback' => 'rules_user_integration_access',
);
return $items;
}
/**
* Action callback to update a user's realname.
*/
function realname_action_realname_update($account, $context = array()) {
realname_update($account);
}
/**
* Implements hook_views_api().
*/
function realname_views_api() {
return array(
'api' => 3,
);
}
/**
* @addtogroup realname
* @{
*/
/**
* Loads a real name.
*
* @param object $account
* A user account object.
*
* @return mixed
* The user's generated real name.
*/
function realname_load($account) {
$realnames = realname_load_multiple(array(
$account->uid => $account,
));
return reset($realnames);
}
/**
* Loads multiple real names.
*
* @param array $accounts
* An array of user account objects keyed by user ID.
*
* @return array
* An array of real names keyed by user ID.
*/
function realname_load_multiple(array $accounts) {
$realnames =& drupal_static(__FUNCTION__, array());
if ($new_accounts = array_diff_key($accounts, $realnames)) {
// Attempt to fetch realnames from the database first.
$realnames += db_query("SELECT uid, realname FROM {realname} WHERE uid IN (:uids)", array(
':uids' => array_keys($new_accounts),
))
->fetchAllKeyed();
// For each account that was not present in the database, generate its
// real name.
foreach ($new_accounts as $uid => $account) {
if (!isset($realnames[$uid])) {
$realnames[$uid] = realname_update($account);
}
}
}
return array_intersect_key($realnames, $accounts);
}
/**
* Update the realname for a user account.
*
* @param object $account
* A user account object.
*
* @return string
* A string with the real name.
*
* @see hook_realname_pattern_alter()
* @see hook_realname_alter()
* @see hook_realname_update()
*/
function realname_update($account) {
// Get the default pattern and allow other modules to alter it.
$pattern = variable_get('realname_pattern', '[user:name-raw]');
drupal_alter('realname_pattern', $pattern, $account);
// Perform token replacement on the real name pattern.
$realname = token_replace($pattern, array(
'user' => $account,
), array(
'clear' => TRUE,
'sanitize' => FALSE,
));
// Remove any HTML tags.
$realname = strip_tags(decode_entities($realname));
// Remove double spaces (if a token had no value).
$realname = preg_replace('/ {2,}/', ' ', $realname);
// Allow other modules to alter the generated realname.
drupal_alter('realname', $realname, $account);
// The name must be trimmed to 255 characters before inserting into the
// database.
$realname = truncate_utf8(trim($realname), 255);
// Save to the database and the static cache.
db_merge('realname')
->key(array(
'uid' => $account->uid,
))
->fields(array(
'realname' => $realname,
'created' => REQUEST_TIME,
))
->execute();
// Allow modules to react to the realname being updated.
module_invoke_all('realname_update', $realname, $account);
// Only if the real name is a non-empty string the name is altered.
if (drupal_strlen($realname)) {
$account->realname = $realname;
}
// Clear the entity cache.
entity_get_controller('user')
->resetCache(array(
$account->uid,
));
return $realname;
}
/**
* Delete a real name.
*
* @param int $uid
* A user ID.
*/
function realname_delete($uid) {
return realname_delete_multiple(array(
$uid,
));
}
/**
* Delete multiple real names.
*
* @param array $uids
* An array of user IDs.
*/
function realname_delete_multiple(array $uids) {
db_delete('realname')
->condition('uid', $uids, 'IN')
->execute();
drupal_static_reset('realname_load_multiple');
entity_get_controller('user')
->resetCache($uids);
}
/**
* Delete all real names.
*/
function realname_delete_all() {
db_truncate('realname')
->execute();
drupal_static_reset('realname_load_multiple');
entity_get_controller('user')
->resetCache();
}
/**
* @} End of "addtogroup realname".
*/
/**
* Menu callback.
*
* Retrieve a JSON object containing autocomplete suggestions
* for existing users based on their generated real names.
*/
function realname_autocomplete($field_name, $entity_type, $bundle_name, $string = '') {
$instance = field_info_instance($entity_type, $field_name, $bundle_name);
$matches = array();
// User entityreference autocomplete fields.
if ($instance['widget']['type'] == 'entityreference_autocomplete' && !empty($string)) {
$query = db_select('users', 'u');
$query
->leftJoin('realname', 'rn', 'u.uid = rn.uid');
$query
->fields('u', array(
'uid',
'name',
));
if ($instance['widget']['settings']['match_operator'] == 'CONTAINS') {
$query
->condition(db_or()
->condition('rn.realname', '%' . db_like($string) . '%', 'LIKE')
->condition('u.name', '%' . db_like($string) . '%', 'LIKE'));
}
else {
$query
->condition(db_or()
->condition('rn.realname', db_like($string) . '%', 'LIKE')
->condition('u.name', db_like($string) . '%', 'LIKE'));
}
$query
->range(0, 10);
$uids = $query
->execute()
->fetchCol();
$accounts = user_load_multiple($uids);
foreach ($accounts as $account) {
$matches[t('!account (@uid)', array(
'!account' => format_username($account),
'@uid' => $account->uid,
))] = t('!realname (@username)', array(
'!realname' => format_username($account),
'@username' => $account->name,
));
}
}
elseif (!empty($string)) {
$query = db_select('users', 'u');
$query
->leftJoin('realname', 'rn', 'u.uid = rn.uid');
$query
->fields('u', array(
'uid',
'name',
));
$query
->condition(db_or()
->condition('rn.realname', db_like($string) . '%', 'LIKE')
->condition('u.name', db_like($string) . '%', 'LIKE'));
$query
->range(0, 10);
$uids = $query
->execute()
->fetchCol();
$accounts = user_load_multiple($uids);
foreach ($accounts as $account) {
$matches[$account->name] = t('!realname (@username)', array(
'!realname' => format_username($account),
'@username' => $account->name,
));
}
}
drupal_json_output($matches);
}
/**
* Menu Access callback for the autocomplete widget.
*
* @param string $field_name
* The name of the entity-reference field.
* @param string $entity_type
* The entity type.
* @param string $bundle_name
* The bundle name.
*
* @return bool
* True if user can access this menu item.
*/
function realname_autocomplete_access_callback($field_name, $entity_type, $bundle_name) {
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle_name);
if (!$field || !$instance || $field['type'] != 'entityreference' || !field_access('edit', $field, $entity_type)) {
return FALSE;
}
return TRUE;
}
/**
* Implements hook_widget_form_alter().
*
* Overrides entityreference autocomplete fields that point to an entity
* of type 'user'.
*/
function realname_field_widget_form_alter(&$element, &$form_state, $context) {
if ($context['field']['type'] == 'entityreference') {
if ($context['field']['settings']['target_type'] == 'user') {
$element['target_id']['#autocomplete_path'] = 'realname/autocomplete/' . $context['field']['field_name'] . '/' . $context['instance']['entity_type'] . '/' . $context['instance']['bundle'];
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function realname_form_user_admin_settings_alter(&$form, &$form_state, $form_id) {
$form['email_admin_created']['user_mail_register_admin_created_body']['#element_validate'][] = 'realname_username_raw_token_validate';
$form['email_no_approval_required']['user_mail_register_no_approval_required_body']['#element_validate'][] = 'realname_username_raw_token_validate';
$form['email_activated']['settings']['user_mail_status_activated_body']['#element_validate'][] = 'realname_username_raw_token_validate';
}
/**
* E-mail settings form validation callback.
*/
function realname_username_raw_token_validate(&$element, &$form_state) {
$value = isset($element['#value']) ? $element['#value'] : $element['#default_value'];
// Warns the site administrator that [user:name-raw], required to log in, is
// missing. You can force the deactivation of this message by setting the
// variable `realname_suppress_user_name_mail_validation` to TRUE (or any
// value that converts to TRUE, like '1').
if (!variable_get('realname_suppress_user_name_mail_validation', FALSE) && strpos($value, '[user:name-raw]') === FALSE) {
drupal_set_message(t('The %element-title does not contain the <code>[user:name-raw]</code> token, which is necessary when using username for login.', array(
'%element-title' => $element['#title'],
)), 'warning');
}
return $element;
}