<?php /** * @file */ use Drupal\user\Entity\User; use Drupal\user\UserInterface; use Drupal\Core\Session\AccountInterface; /** * Implements hook_help(). */ function alt_login_help($route_name, $route_match) { if ($route_name == 'help.page.alt_login') { return t("Allows login with various aliases, and formats the user's display name."); } } /** * Implements hook_user_format_name_alter(). * * Manipulate the user display name according to settings. Since results of this * hook aren't cached, a static reduces calls to the token system. * * @note there's no easy way to dedupe accounts' display names. */ function alt_login_user_format_name_alter(&$name, AccountInterface $account) { if ($account->isAnonymous() or ($account instanceof UserInterface and $account->isNew())) { // This will be the configured 'anonymous' value return; } static $names = []; $uid = $account->id(); if (!isset($names[$uid])) { // Anonymous users if (\Drupal::currentUser()->isAnonymous()) { $anon = \Drupal::config('alt_login.settings')->get('display_anon'); $names[$uid] = \Drupal::token() ->replace($anon, ['user' => $account], ['clear' => true]); } // Do the replacement if the module is configured. elseif ($template = \Drupal::config('alt_login.settings')->get('display')) { $user = $account instanceOf UserInterface ? $account : User::load($uid); $names[$uid] = \Drupal::token()->replace( $template, ['user' => $user], ['clear' => TRUE] ); } // If the above didn't produce a string, fall back to the username. if (empty($names[$uid])) { $names[$uid] = $account->getAccountName(); } } $name = $names[$uid]; } /** * Implements hook_module_implements_alter(). * * Ensure that this is the last module to format the username. */ function alt_login_module_implements_alter(&$implementations, $hook) { if ($hook == 'user_format_name_alter') { unset($implementations['alt_login']); $implementations['alt_login'] = FALSE; } } /** * Implements hook_form_alter(). */ function alt_login_form_alter(&$form, $form_state, $form_id) { // Show all the login options on the user form. $user_forms = ['user_form', 'user_create_form', 'user_register_form', 'user_admin_form']; if (in_array($form_id, $user_forms)) { // Rewrite the username field to be clearer. $user = $form_state->getFormObject()->getEntity(); $aliases = alt_login_get_aliases($user); $namefield = &$form['account']['name']; if (empty($aliases['username'])) { if ($user->isNew()) { $namefield['#access'] = FALSE; $namefield['#value'] = user_password(8); } elseif (count($aliases) == 1) { $namefield = [ '#type' => 'markup', '#markup' => t("Login using '%name'", ['%name' => reset($aliases)]), '#description' => t('This is determined by @descriptions.', ['@descriptions' => implode(', ', alt_login_active_descriptions())]), '#weight' => -1 ]; } else { $namefield['#access'] = FALSE; $form['account']['aliases'] = [ '#title' => t('Log in with these aliases'), '#theme' => 'item_list', '#items' => $aliases, '#weight' => -1 ]; } } else {// If the username plugin IS used. unset($aliases['username']); if (count($aliases)) { $namefield['#description'] = t('You can also login with: @alts', ['@alts' => implode(', ', $aliases)]); } } $form['account']['roles']['#weight'] = 2; $form['#validate'][] = 'alt_login_validate_dedupe_aliases'; } // Add a validation callback to login fields to allow alternative login names elseif (in_array($form_id, ['user_login_form', 'user_login_block'])) { $aliases = alt_login_get_aliases(User::load(0)); $form['name']['#title'] = implode(', ', $aliases); unset($form['name']['#description']); $form['name']['#element_validate'][] = 'alt_login_login_name_element_validate'; } } /** * Element validation callback for login form name field. * * Look up the real user name from the given login id and replace it ready for * the form-level validation. */ function alt_login_login_name_element_validate(&$element, $form_state) { $name = alt_login_convert_alias($element['#value']); $form_state->setValue('name', $name); } /** * Utility * * Look up the given alias and return the real username for logging in. * * @param string $alias * * @return string | NULL */ function alt_login_convert_alias($alias) { foreach (\Drupal::service('alt_login.method_manager')->activePlugins() as $plugin) { if ($plugin->applies($alias)) { if ($user = $plugin->getUserFromAlias($alias)) { return $user->getAccountName(); } } } // ' ' is an invalid username which will not break the sql query. return ' '; } /** * Get all the alternative login strings for the given user * * @param Userinterface $user * * @return string[] */ function alt_login_get_aliases(UserInterface $user) { $alts = []; if ($user->isAuthenticated()) { foreach (\Drupal::service('alt_login.method_manager')->activePlugins() as $plugin_id => $plugin) { $alts[$plugin_id] = $plugin->getAlias($user); } } else { $labels = \Drupal::service('alt_login.method_manager')->getOptions(); foreach (\Drupal::service('alt_login.method_manager')->activePlugins() as $plugin_id => $def) { $alts[$plugin_id] = $labels[$plugin_id]; } } return $alts; } /** * Implements hook_tokens_alter(). * * Replace the username with any aliases. */ function alt_login_tokens_alter(&$replacements, array $context, $bubbleable_metadata) { if ($context['type'] == 'user' and isset($context['data']['user']) and isset($replacements['[user:name]'])) { $replacements['[user:name]'] = implode(t(' OR '), alt_login_get_aliases($context['data']['user'])); } } /** * Implements hook_user_presave(). */ function alt_login_user_presave(UserInterface $account) { if ($account->isNew()) { // Awkwardly, users migrating in are have isNew = true. if ($account->getCreatedTime() < Drupal::time()->getRequestTime()) { return; } // Contrive a username if the username isn't otherwise used. // use the first part of the email and extend with _1 in case of dupulicates. $plugins = \Drupal::Config('alt_login.settings')->get('aliases'); if (!in_array('username', $plugins)) { $new_name = substr($account->getEmail(), 0, strpos($account->getEmail(), '@')); \Drupal::entityQuery('user')->condition('name', "$new_name%", 'LIKE')->execute(); $lastname = \Drupal::database()->select('users_field_data', 'u') ->fields('u', ['name']) ->condition('name', "$new_name%", 'LIKE') ->range(0, 1) ->orderBy('name', 'DESC') ->execute()->fetchField(); if ($lastname && preg_match('/^.*(_[0-9]+)*$/', $lastname, $matches)) { $inc=1; if (isset($matches[1])) { $inc = $matches[1]++; } $new_name .= '_'.$inc; } $account->setUsername($new_name); // Note that the the User RegisterForm logs user creation with another name. \Drupal::logger('Alt Login')->notice('New user name set to '.$new_name); } } } /** * User form validation callback. */ function alt_login_validate_dedupe_aliases($form, $form_state) { $user = $form_state->getFormObject()->buildEntity($form, $form_state); foreach (\Drupal::service('alt_login.method_manager')->activePlugins() as $plugin) { if ($field_name = $plugin->dedupeAlias($user)) { $form_state->setErrorByName($field_name, t('This alias is already taken.')); } } } /** * Utility * * Could be useful for exporting. * * @param UserInterface $user * @param string $plugin_id * * @return string */ function alt_login_get_alias(UserInterface $user, $plugin_id) { return \Drupal::service('alt_login.method_manager') ->createInstance($plugin_id) ->getAlias($user); } /** * Utility * * Load all the active plugins() * * @return AltLoginMethodInterface[] * * @deprecated */ function alt_login_active_plugins() { @trigger_error("alt_login_active_plugins() is deprecated. User Drupal\alt_login\AltLoginMethodManager::activePlugins()", E_USER_DEPRECATED); return \Drupal::service('alt_login.method_manager')->activePlugins(); } function alt_login_active_descriptions() { $plugin_manager = \Drupal::service('alt_login.method_manager'); foreach (\Drupal::Config('alt_login.settings')->get('aliases') as $plugin_id) { $def = $plugin_manager->getDefinition($plugin_id); $descriptions[] = $def['description']; } return $descriptions; } /** * Implements hook_alt_login_info_alter(). * * Check for the address module and put username last */ function alt_login_alt_login_info_alter(&$definitions) { if (isset($definitions['username'])) { $def = $definitions['username']; unset($definitions['username']); $definitions['username'] = $def; } //this should really be implemented using the plugin annotation if (!\Drupal::moduleHandler()->moduleExists('address')) { unset($definitions['address_name']); } }