| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- <?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));
- }
- }
- // User autocomplete fields.
- 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;
- }
|