diff --git a/core/core.api.php b/core/core.api.php index c582370cfe722a1eff322cbd41185073f7e2b87c..6415c4f10c522156ed3583d6f8c27934191f417a 100644 --- a/core/core.api.php +++ b/core/core.api.php @@ -1961,7 +1961,7 @@ function hook_mail($key, &$message, $params) { $context = $params['context']; $variables = array( '%site_name' => \Drupal::config('system.site')->get('name'), - '%username' => user_format_name($account), + '%username' => $account->getDisplayName(), ); if ($context['hook'] == 'taxonomy') { $entity = $params['entity']; diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 0f6a6c6421fb4539cff35fa9ecc57dd2fa792672..0b1f6337b019de36112f57a071d9be08a9ac5d86 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -314,7 +314,7 @@ function drupal_get_path($type, $name) { * names or link URLs into translated text. Variable substitution looks like * this: * @code - * $text = t("@name's blog", array('@name' => user_format_name($account))); + * $text = t("@name's blog", array('@name' => $account->getDisplayName())); * @endcode * Basically, you can put variables like @name into your string, and t() will * substitute their sanitized values at translation time. (See the diff --git a/core/lib/Drupal/Core/Session/AccountInterface.php b/core/lib/Drupal/Core/Session/AccountInterface.php index 96aeb2d4a3aa2824fe506d46bad80f29fbfd4caf..36b390a7085c78a86414b02de28e5cb88cb66872 100644 --- a/core/lib/Drupal/Core/Session/AccountInterface.php +++ b/core/lib/Drupal/Core/Session/AccountInterface.php @@ -106,19 +106,49 @@ public function getPreferredLangcode($fallback_to_default = TRUE); public function getPreferredAdminLangcode($fallback_to_default = TRUE); /** - * Returns the username of this account. + * Returns the unaltered login name of this account. + * + * @return string + * An unsanitized plain-text string with the name of this account that is + * used to log in. Only display this name to admins and to the user who owns + * this account, and only in the context of the name used to login. For + * any other display purposes, use + * \Drupal\Core\Session\AccountInterface::getDisplayName() instead. + * + * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0. + * Use \Drupal\Core\Session\AccountInterface::getAccountName() or + * \Drupal\user\UserInterface::getDisplayName() instead. + */ + public function getUsername(); + + /** + * Returns the unaltered login name of this account. + * + * @return string + * An unsanitized plain-text string with the name of this account that is + * used to log in. Only display this name to admins and to the user who owns + * this account, and only in the context of the name used to login. For + * any other display purposes, use + * \Drupal\Core\Session\AccountInterface::getDisplayName() instead. + */ + public function getAccountName(); + + /** + * Returns the display name of this account. * * By default, the passed-in object's 'name' property is used if it exists, or - * else, the site-defined value for the 'anonymous' variable. However, a module - * may override this by implementing + * else, the site-defined value for the 'anonymous' variable. However, a + * module may override this by implementing * hook_user_format_name_alter(&$name, $account). * * @see hook_user_format_name_alter() * - * @return - * An unsanitized string with the username to display. + * @return string|\Drupal\Component\Utility\SafeStringInterface + * Either a string that will be auto-escaped on output or a + * SafeStringInterface object that is already HTML escaped. Either is safe + * to be printed within HTML fragments. */ - public function getUsername(); + public function getDisplayName(); /** * Returns the email address of this account. diff --git a/core/lib/Drupal/Core/Session/AccountProxy.php b/core/lib/Drupal/Core/Session/AccountProxy.php index ff5c4f4b513e48f4c82bb4a353d2eb151b17f887..4d6db573a70d6745b0f2fe6d2d51cb852504a6fb 100644 --- a/core/lib/Drupal/Core/Session/AccountProxy.php +++ b/core/lib/Drupal/Core/Session/AccountProxy.php @@ -119,7 +119,21 @@ public function getPreferredAdminLangcode($fallback_to_default = TRUE) { * {@inheritdoc} */ public function getUsername() { - return $this->getAccount()->getUsername(); + return $this->getAccountName(); + } + + /** + * {@inheritdoc} + */ + public function getAccountName() { + return $this->getAccount()->getAccountName(); + } + + /** + * {@inheritdoc} + */ + public function getDisplayName() { + return $this->getAccount()->getDisplayName(); } /** diff --git a/core/lib/Drupal/Core/Session/UserSession.php b/core/lib/Drupal/Core/Session/UserSession.php index ce4b5081dc093c854b50ec82c663ede023c360c3..55f49381960f0e04f90eaf3de68bb9aa6a098a17 100644 --- a/core/lib/Drupal/Core/Session/UserSession.php +++ b/core/lib/Drupal/Core/Session/UserSession.php @@ -42,7 +42,7 @@ class UserSession implements AccountInterface { * * @var string */ - public $name; + public $name = ''; /** * The preferred language code of the account. @@ -160,6 +160,20 @@ function getPreferredAdminLangcode($fallback_to_default = TRUE) { * {@inheritdoc} */ public function getUsername() { + return $this->getAccountName(); + } + + /** + * {@inheritdoc} + */ + public function getAccountName() { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getDisplayName() { $name = $this->name ?: \Drupal::config('user.settings')->get('anonymous'); \Drupal::moduleHandler()->alter('user_format_name', $name, $this); return $name; diff --git a/core/modules/action/src/Plugin/Action/EmailAction.php b/core/modules/action/src/Plugin/Action/EmailAction.php index e56a88708992dcfd90e36315947b726f8ba71590..252428c13677c802f83508bd0848347a8b565cc3 100644 --- a/core/modules/action/src/Plugin/Action/EmailAction.php +++ b/core/modules/action/src/Plugin/Action/EmailAction.php @@ -185,7 +185,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#default_value' => $this->configuration['message'], '#cols' => '80', '#rows' => '20', - '#description' => t('The message that should be sent. You may include placeholders like [node:title], [user:name], and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.'), + '#description' => t('The message that should be sent. You may include placeholders like [node:title], [user:account-name], [user:display-name] and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.'), ); return $form; } diff --git a/core/modules/action/src/Plugin/Action/MessageAction.php b/core/modules/action/src/Plugin/Action/MessageAction.php index c87b6060a8fe428f3bd8388a6353729f3132bd9b..3da24ef16d96af74594cf3911520496ed05359e1 100644 --- a/core/modules/action/src/Plugin/Action/MessageAction.php +++ b/core/modules/action/src/Plugin/Action/MessageAction.php @@ -78,7 +78,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#default_value' => $this->configuration['message'], '#required' => TRUE, '#rows' => '8', - '#description' => t('The message to be displayed to the current user. You may include placeholders like [node:title], [user:name], and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.'), + '#description' => t('The message to be displayed to the current user. You may include placeholders like [node:title], [user:account-name], [user:display-name] and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.'), ); return $form; } diff --git a/core/modules/comment/src/Tests/CommentPreviewTest.php b/core/modules/comment/src/Tests/CommentPreviewTest.php index ae92de083a28d82087b47942bd7bef828b011e29..644f89b5727e9e915e79adb57b7bb75cf4ba0d3b 100644 --- a/core/modules/comment/src/Tests/CommentPreviewTest.php +++ b/core/modules/comment/src/Tests/CommentPreviewTest.php @@ -54,7 +54,7 @@ function testCommentPreview() { \Drupal::state()->set('user_hooks_test_user_format_name_alter_safe', TRUE); $this->drupalPostForm('node/' . $this->node->id(), $edit, t('Preview')); - $this->assertTrue(SafeMarkup::isSafe($this->webUser->getUsername()), 'Username is marked safe'); + $this->assertTrue(SafeMarkup::isSafe($this->webUser->getDisplayName()), 'Username is marked safe'); $this->assertNoEscaped('' . $this->webUser->id() . ''); $this->assertRaw('' . $this->webUser->id() . ''); diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module index 98f1dbd5655b8b3e24d4fe96c6d3758ab5d68630..bebc1413ca1ab7f33f5d9b936dccbbe51d604d26 100644 --- a/core/modules/contact/contact.module +++ b/core/modules/contact/contact.module @@ -126,7 +126,7 @@ function contact_mail($key, &$message, $params) { '!subject' => $contact_message->getSubject(), '!form' => !empty($params['contact_form']) ? $params['contact_form']->label() : NULL, '!form-url' => \Drupal::url('', [], ['absolute' => TRUE, 'language' => $language]), - '!sender-name' => user_format_name($sender), + '!sender-name' => $sender->getDisplayName(), ); if ($sender->isAuthenticated()) { $variables['!sender-url'] = $sender->url('canonical', array('absolute' => TRUE, 'language' => $language)); @@ -154,7 +154,7 @@ function contact_mail($key, &$message, $params) { case 'user_mail': case 'user_copy': $variables += array( - '!recipient-name' => user_format_name($params['recipient']), + '!recipient-name' => $params['recipient']->getDisplayName(), '!recipient-edit-url' => $params['recipient']->url('edit-form', array('absolute' => TRUE, 'language' => $language)), ); $message['subject'] .= t('[!site-name] !subject', $variables, $options); diff --git a/core/modules/contact/src/Controller/ContactController.php b/core/modules/contact/src/Controller/ContactController.php index b6b9020fdc5cd9189670e138f7268e514a7f6332..fb6830d49bf6dd84ba92a13f3f07c69cfea58068 100644 --- a/core/modules/contact/src/Controller/ContactController.php +++ b/core/modules/contact/src/Controller/ContactController.php @@ -117,7 +117,7 @@ public function contactPersonalPage(UserInterface $user) { )); $form = $this->entityFormBuilder()->getForm($message); - $form['#title'] = $this->t('Contact @username', array('@username' => $user->getUsername())); + $form['#title'] = $this->t('Contact @username', array('@username' => $user->getDisplayName())); $form['#cache']['contexts'][] = 'user.permissions'; return $form; } diff --git a/core/modules/file/src/Tests/FileTokenReplaceTest.php b/core/modules/file/src/Tests/FileTokenReplaceTest.php index 0f771d0cb8c0cd6b72b7095a697c4e58629baf07..93a6c67a87dc8a4abdc432721bb160e442ca7012 100644 --- a/core/modules/file/src/Tests/FileTokenReplaceTest.php +++ b/core/modules/file/src/Tests/FileTokenReplaceTest.php @@ -56,7 +56,7 @@ function testFileTokenReplacement() { $tests['[file:created:short]'] = format_date($file->getCreatedTime(), 'short', '', NULL, $language_interface->getId()); $tests['[file:changed]'] = format_date($file->getChangedTime(), 'medium', '', NULL, $language_interface->getId()); $tests['[file:changed:short]'] = format_date($file->getChangedTime(), 'short', '', NULL, $language_interface->getId()); - $tests['[file:owner]'] = Html::escape(user_format_name($this->adminUser)); + $tests['[file:owner]'] = Html::escape($this->adminUser->getDisplayName()); $tests['[file:owner:uid]'] = $file->getOwnerId(); $base_bubbleable_metadata = BubbleableMetadata::createFromObject($file); diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 39ef507d3df3e2c90b1b934a860b16fc5d5146e5..be8ff0f2469dfe5a70e78c8f3c2dcf4b7c0f66a6 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -456,7 +456,7 @@ function template_preprocess_forums(&$variables) { } $forum_submitted = array('#theme' => 'forum_submitted', '#topic' => (object) array( 'uid' => $topic->getOwnerId(), - 'name' => $topic->getOwner()->getUsername(), + 'name' => $topic->getOwner()->getDisplayName(), 'created' => $topic->getCreatedTime(), )); $variables['topics'][$id]->submitted = drupal_render($forum_submitted); diff --git a/core/modules/node/src/Plugin/views/row/Rss.php b/core/modules/node/src/Plugin/views/row/Rss.php index e73d527285f3db6efd9a20c180a5b9e669f50acd..2967ccecaa9676c5e4c286b158b1581fd191ef09 100644 --- a/core/modules/node/src/Plugin/views/row/Rss.php +++ b/core/modules/node/src/Plugin/views/row/Rss.php @@ -121,7 +121,7 @@ public function render($row) { ), array( 'key' => 'dc:creator', - 'value' => $node->getOwner()->getUsername(), + 'value' => $node->getOwner()->getDisplayName(), ), array( 'key' => 'guid', diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index ae6b9cb4e4f63a49738cda00284bb12ffc86f3cd..33a3e92a2bd5b7ad3c3826c76c3725de06b0f64c 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -378,7 +378,7 @@ function rdf_preprocess_user(&$variables) { '#attributes' => array( 'about' => $account->url(), 'property' => $name_mapping['properties'], - 'content' => $account->getUsername(), + 'content' => $account->getDisplayName(), 'lang' => '', ), ); diff --git a/core/modules/shortcut/src/Form/SwitchShortcutSet.php b/core/modules/shortcut/src/Form/SwitchShortcutSet.php index ce7cc318dda51c796e2b02cd3804110b7846c589..9faa922b7475a29eea3a662741e3f5534c8ae225 100644 --- a/core/modules/shortcut/src/Form/SwitchShortcutSet.php +++ b/core/modules/shortcut/src/Form/SwitchShortcutSet.php @@ -207,7 +207,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { /* @var \Drupal\shortcut\Entity\ShortcutSet $set */ $set = $this->shortcutSetStorage->load($form_state->getValue('set')); $replacements = array( - '%user' => $this->user->label(), + '%user' => $this->user->getDisplayName(), '%set_name' => $set->label(), ); drupal_set_message($account_is_user ? $this->t('You are now using the %set_name shortcut set.', $replacements) : $this->t('%user is now using the %set_name shortcut set.', $replacements)); diff --git a/core/modules/user/config/install/user.mail.yml b/core/modules/user/config/install/user.mail.yml index 436ff53b8cb7b6f724587b8142e0e361ca9874a8..18e9eea01949383580f54109e01de69147bcb416 100644 --- a/core/modules/user/config/install/user.mail.yml +++ b/core/modules/user/config/install/user.mail.yml @@ -1,28 +1,28 @@ cancel_confirm: - body: "[user:name],\n\nA request to cancel your account has been made at [site:name].\n\nYou may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:\n\n[user:cancel-url]\n\nNOTE: The cancellation of your account is not reversible.\n\nThis link expires in one day and nothing will happen if it is not used.\n\n-- [site:name] team" - subject: 'Account cancellation request for [user:name] at [site:name]' + body: "[user:display-name],\n\nA request to cancel your account has been made at [site:name].\n\nYou may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:\n\n[user:cancel-url]\n\nNOTE: The cancellation of your account is not reversible.\n\nThis link expires in one day and nothing will happen if it is not used.\n\n-- [site:name] team" + subject: 'Account cancellation request for [user:display-name] at [site:name]' password_reset: - body: "[user:name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYou may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.\n\n-- [site:name] team" - subject: 'Replacement login information for [user:name] at [site:name]' + body: "[user:display-name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYou may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.\n\n-- [site:name] team" + subject: 'Replacement login information for [user:display-name] at [site:name]' register_admin_created: - body: "[user:name],\n\nA site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team" + body: "[user:display-name],\n\nA site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team" subject: 'An administrator created an account for you at [site:name]' register_no_approval_required: - body: "[user:name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team" - subject: 'Account details for [user:name] at [site:name]' + body: "[user:display-name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team" + subject: 'Account details for [user:display-name] at [site:name]' register_pending_approval: - body: "[user:name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team" - subject: 'Account details for [user:name] at [site:name] (pending admin approval)' + body: "[user:display-name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team" + subject: 'Account details for [user:display-name] at [site:name] (pending admin approval)' register_pending_approval_admin: - body: "[user:name] has applied for an account.\n\n[user:edit-url]" - subject: 'Account details for [user:name] at [site:name] (pending admin approval)' + body: "[user:display-name] has applied for an account.\n\n[user:edit-url]" + subject: 'Account details for [user:display-name] at [site:name] (pending admin approval)' status_activated: - body: "[user:name],\n\nYour account at [site:name] has been activated.\n\nYou may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team" - subject: 'Account details for [user:name] at [site:name] (approved)' + body: "[user:display-name],\n\nYour account at [site:name] has been activated.\n\nYou may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:account-name]\npassword: Your password\n\n-- [site:name] team" + subject: 'Account details for [user:display-name] at [site:name] (approved)' status_blocked: - body: "[user:name],\n\nYour account on [site:name] has been blocked.\n\n-- [site:name] team" - subject: 'Account details for [user:name] at [site:name] (blocked)' + body: "[user:display-name],\n\nYour account on [site:account-name] has been blocked.\n\n-- [site:name] team" + subject: 'Account details for [user:display-name] at [site:name] (blocked)' status_canceled: - body: "[user:name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team" - subject: 'Account details for [user:name] at [site:name] (canceled)' + body: "[user:display-name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team" + subject: 'Account details for [user:display-name] at [site:name] (canceled)' langcode: en diff --git a/core/modules/user/src/AccountSettingsForm.php b/core/modules/user/src/AccountSettingsForm.php index 6cdc238090a8b8da3a992528e1df4759dc198b4a..b76897d8db63d91756b1c7375cde6b1bb82a3a09 100644 --- a/core/modules/user/src/AccountSettingsForm.php +++ b/core/modules/user/src/AccountSettingsForm.php @@ -201,7 +201,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { ); // These email tokens are shared for all settings, so just define // the list once to help ensure they stay in sync. - $email_token_help = $this->t('Available variables are: [site:name], [site:url], [user:name], [user:mail], [site:login-url], [site:url-brief], [user:edit-url], [user:one-time-login-url], [user:cancel-url].'); + $email_token_help = $this->t('Available variables are: [site:name], [site:url], [user:display-name], [user:account-name], [user:mail], [site:login-url], [site:url-brief], [user:edit-url], [user:one-time-login-url], [user:cancel-url].'); $form['email_admin_created'] = array( '#type' => 'details', diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php index 3716d011ca7cf76f8cd6918fccb0a4cb9230bf09..ce0d20ecae8bee39596455400a233595ddd62d7e 100644 --- a/core/modules/user/src/Entity/User.php +++ b/core/modules/user/src/Entity/User.php @@ -362,7 +362,21 @@ public function isAnonymous() { * {@inheritdoc} */ public function getUsername() { - $name = $this->get('name')->value ?: \Drupal::config('user.settings')->get('anonymous'); + return $this->getAccountName(); + } + + /** + * {@inheritdoc} + */ + public function getAccountName() { + return $this->get('name')->value ?: ''; + } + + /** + * {@inheritdoc} + */ + public function getDisplayName() { + $name = $this->getAccountName() ?: \Drupal::config('user.settings')->get('anonymous'); \Drupal::moduleHandler()->alter('user_format_name', $name, $this); return $name; } @@ -411,7 +425,10 @@ public static function getAnonymousUser() { $entity_type = $entity_manager->getDefinition('user'); $class = $entity_type->getClass(); - static::$anonymousUser = new $class(['uid' => [LanguageInterface::LANGCODE_DEFAULT => 0]], $entity_type->id()); + static::$anonymousUser = new $class([ + 'uid' => [LanguageInterface::LANGCODE_DEFAULT => 0], + 'name' => [LanguageInterface::LANGCODE_DEFAULT => ''], + ], $entity_type->id()); } return clone static::$anonymousUser; } diff --git a/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php b/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php index e2dd03d3fb04c1c5fefba7474a7f890b194167ec..a1679cbc30da5deed80e1b48b096acbb88378101 100644 --- a/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php +++ b/core/modules/user/src/Plugin/EntityReferenceSelection/UserSelection.php @@ -202,7 +202,7 @@ public function entityQueryAlter(SelectInterface $query) { $value_part->condition('anonymous_name', $condition['value'], $condition['operator']); $value_part->compile($this->connection, $query); $or->condition(db_and() - ->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => user_format_name($this->userStorage->load(0)))) + ->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => \Drupal::config('user.settings')->get('anonymous'))) ->condition('base_table.uid', 0) ); $query->condition($or); diff --git a/core/modules/user/src/Plugin/Field/FieldFormatter/UserNameFormatter.php b/core/modules/user/src/Plugin/Field/FieldFormatter/UserNameFormatter.php index cf99225a881a5df3e4e0944363bfdfbb7422088f..1886ed91385693ca4c5fe79df9aba32910b78e5f 100644 --- a/core/modules/user/src/Plugin/Field/FieldFormatter/UserNameFormatter.php +++ b/core/modules/user/src/Plugin/Field/FieldFormatter/UserNameFormatter.php @@ -72,7 +72,7 @@ public function viewElements(FieldItemListInterface $items) { } else { $elements[$delta] = [ - '#markup' => $user->getUsername(), + '#markup' => $user->getDisplayName(), '#cache' => [ 'tags' => $user->getCacheTags(), ], diff --git a/core/modules/user/src/Plugin/Search/UserSearch.php b/core/modules/user/src/Plugin/Search/UserSearch.php index 2e657c3ae3b0e33d14a8ece80b9d53398145c6d3..a0fb3b49f0daa4b2095c8fe90e492b9f4397d59f 100644 --- a/core/modules/user/src/Plugin/Search/UserSearch.php +++ b/core/modules/user/src/Plugin/Search/UserSearch.php @@ -148,7 +148,7 @@ public function execute() { foreach ($accounts as $account) { $result = array( - 'title' => $account->getUsername(), + 'title' => $account->getDisplayName(), 'link' => $account->url('canonical', array('absolute' => TRUE)), ); if ($this->currentUser->hasPermission('administer users')) { diff --git a/core/modules/user/src/Tests/Field/UserNameFormatterTest.php b/core/modules/user/src/Tests/Field/UserNameFormatterTest.php index 2c9447d0c89b861d169e527e082dd8c0babf4254..fab8cd91341670441c94f262683698b3cca1b83c 100644 --- a/core/modules/user/src/Tests/Field/UserNameFormatterTest.php +++ b/core/modules/user/src/Tests/Field/UserNameFormatterTest.php @@ -87,7 +87,17 @@ public function testFormatter() { $this->assertEqual(spl_object_hash($user), spl_object_hash($result[0]['#account'])); $result = $user->{$this->fieldName}->view(['type' => 'user_name', 'settings' => ['link_to_entity' => FALSE]]); - $this->assertEqual($user->getUsername(), $result[0]['#markup']); + $this->assertEqual($user->getDisplayName(), $result[0]['#markup']); + + $user = User::getAnonymousUser(); + + $result = $user->{$this->fieldName}->view(['type' => 'user_name']); + $this->assertEqual('username', $result[0]['#theme']); + $this->assertEqual(spl_object_hash($user), spl_object_hash($result[0]['#account'])); + + $result = $user->{$this->fieldName}->view(['type' => 'user_name', 'settings' => ['link_to_entity' => FALSE]]); + $this->assertEqual($user->getDisplayName(), $result[0]['#markup']); + $this->assertEqual($this->config('user.settings')->get('anonymous'), $result[0]['#markup']); } } diff --git a/core/modules/user/src/Tests/UserCancelTest.php b/core/modules/user/src/Tests/UserCancelTest.php index 648f56ff57035dafacea5c15b5c139453301fe8c..6c2034d7ecdc2048fb3da6d3efaf60bc24766037 100644 --- a/core/modules/user/src/Tests/UserCancelTest.php +++ b/core/modules/user/src/Tests/UserCancelTest.php @@ -367,7 +367,7 @@ function testUserAnonymize() { $storage->resetCache(array($comment->id())); $test_comment = $storage->load($comment->id()); $this->assertTrue(($test_comment->getOwnerId() == 0 && $test_comment->isPublished()), 'Comment of the user has been attributed to anonymous user.'); - $this->assertEqual($test_comment->getAuthorName(), $anonymous_user->getUsername(), 'Comment of the user has been attributed to anonymous user name.'); + $this->assertEqual($test_comment->getAuthorName(), $anonymous_user->getDisplayName(), 'Comment of the user has been attributed to anonymous user name.'); // Confirm that the confirmation message made it through to the end user. $this->assertRaw(t('%name has been deleted.', array('%name' => $account->getUsername())), "Confirmation message displayed to user."); diff --git a/core/modules/user/src/Tests/UserEditedOwnAccountTest.php b/core/modules/user/src/Tests/UserEditedOwnAccountTest.php index 65282c0cf83d9afb719c49e434a17ad228960239..017ca85bb29031f29b38d313f5b5ebc435fd40b7 100644 --- a/core/modules/user/src/Tests/UserEditedOwnAccountTest.php +++ b/core/modules/user/src/Tests/UserEditedOwnAccountTest.php @@ -16,6 +16,13 @@ */ class UserEditedOwnAccountTest extends WebTestBase { + /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('user_form_test'); + function testUserEditedOwnAccount() { // Change account setting 'Who can register accounts?' to Administrators // only. diff --git a/core/modules/user/src/Tests/UserEntityCallbacksTest.php b/core/modules/user/src/Tests/UserEntityCallbacksTest.php index a56e6cab273130747bd982fcc2ebc76e2f5a0eca..ce7726a20fc0dc438d797e48ff2944b97ef2a347 100644 --- a/core/modules/user/src/Tests/UserEntityCallbacksTest.php +++ b/core/modules/user/src/Tests/UserEntityCallbacksTest.php @@ -22,7 +22,7 @@ class UserEntityCallbacksTest extends WebTestBase { * * @var array */ - public static $modules = array('user'); + public static $modules = array('user', 'user_hooks_test'); /** * An authenticated user to use for testing. @@ -55,6 +55,14 @@ function testLabelCallback() { $name = $this->randomMachineName(); $this->config('user.settings')->set('anonymous', $name)->save(); $this->assertEqual($this->anonymous->label(), $name, 'The variable anonymous should be used for name of uid 0'); + $this->assertEqual($this->anonymous->getDisplayName(), $name, 'The variable anonymous should be used for display name of uid 0'); + $this->assertEqual($this->anonymous->getUserName(), '', 'The raw anonymous user name should be empty string'); + + // Set to test the altered username. + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); + + $this->assertEqual($this->account->getDisplayName(), '' . $this->account->id() . '', 'The user display name should be altered.'); + $this->assertEqual($this->account->getUsername(), $this->account->name->value, 'The user name should not be altered.'); } } diff --git a/core/modules/user/src/Tests/UserTokenReplaceTest.php b/core/modules/user/src/Tests/UserTokenReplaceTest.php index 661ce2fa35cb519a4965a1ba577e48e8115064a4..ad5d2966d00343cf6dafb39c36335e7042dd12eb 100644 --- a/core/modules/user/src/Tests/UserTokenReplaceTest.php +++ b/core/modules/user/src/Tests/UserTokenReplaceTest.php @@ -26,8 +26,11 @@ class UserTokenReplaceTest extends WebTestBase { * * @var array */ - public static $modules = array('language'); + public static $modules = array('language', 'user_hooks_test'); + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); ConfigurableLanguage::createFromLangcode('de')->save(); @@ -44,6 +47,8 @@ function testUserTokenReplacement() { 'language' => $language_interface, ); + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); + // Create two users and log them in one after another. $user1 = $this->drupalCreateUser(array()); $user2 = $this->drupalCreateUser(array()); @@ -57,7 +62,9 @@ function testUserTokenReplacement() { // Generate and test sanitized tokens. $tests = array(); $tests['[user:uid]'] = $account->id(); - $tests['[user:name]'] = Html::escape(user_format_name($account)); + $tests['[user:name]'] = Html::escape($account->getAccountName()); + $tests['[user:account-name]'] = Html::escape($account->getAccountName()); + $tests['[user:display-name]'] = $account->getDisplayName(); $tests['[user:mail]'] = Html::escape($account->getEmail()); $tests['[user:url]'] = $account->url('canonical', $url_options); $tests['[user:edit-url]'] = $account->url('edit-form', $url_options); @@ -65,12 +72,16 @@ function testUserTokenReplacement() { $tests['[user:last-login:short]'] = format_date($account->getLastLoginTime(), 'short', '', NULL, $language_interface->getId()); $tests['[user:created]'] = format_date($account->getCreatedTime(), 'medium', '', NULL, $language_interface->getId()); $tests['[user:created:short]'] = format_date($account->getCreatedTime(), 'short', '', NULL, $language_interface->getId()); - $tests['[current-user:name]'] = Html::escape(user_format_name($global_account)); + $tests['[current-user:name]'] = Html::escape($global_account->getAccountName()); + $tests['[current-user:account-name]'] = Html::escape($global_account->getAccountName()); + $tests['[current-user:display-name]'] = $global_account->getDisplayName(); $base_bubbleable_metadata = BubbleableMetadata::createFromObject($account); $metadata_tests = []; $metadata_tests['[user:uid]'] = $base_bubbleable_metadata; $metadata_tests['[user:name]'] = $base_bubbleable_metadata; + $metadata_tests['[user:account-name]'] = $base_bubbleable_metadata; + $metadata_tests['[user:display-name]'] = $base_bubbleable_metadata; $metadata_tests['[user:mail]'] = $base_bubbleable_metadata; $metadata_tests['[user:url]'] = $base_bubbleable_metadata; $metadata_tests['[user:edit-url]'] = $base_bubbleable_metadata; @@ -86,6 +97,8 @@ function testUserTokenReplacement() { $metadata_tests['[user:created]'] = $bubbleable_metadata; $metadata_tests['[user:created:short]'] = $bubbleable_metadata; $metadata_tests['[current-user:name]'] = $base_bubbleable_metadata->merge(BubbleableMetadata::createFromObject($global_account)->addCacheContexts(['user'])); + $metadata_tests['[current-user:account-name]'] = $base_bubbleable_metadata->merge(BubbleableMetadata::createFromObject($global_account)->addCacheContexts(['user'])); + $metadata_tests['[current-user:display-name]'] = $base_bubbleable_metadata->merge(BubbleableMetadata::createFromObject($global_account)->addCacheContexts(['user'])); // Test to make sure that we generated something for each token. $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); @@ -101,14 +114,14 @@ function testUserTokenReplacement() { $anonymous_user = User::load(0); $tests = []; $tests['[user:uid]'] = t('not yet assigned'); - $tests['[user:name]'] = Html::escape(user_format_name($anonymous_user)); + $tests['[user:display-name]'] = $anonymous_user->getDisplayName(); $base_bubbleable_metadata = BubbleableMetadata::createFromObject($anonymous_user); $metadata_tests = []; $metadata_tests['[user:uid]'] = $base_bubbleable_metadata; $bubbleable_metadata = clone $base_bubbleable_metadata; $bubbleable_metadata->addCacheableDependency(\Drupal::config('user.settings')); - $metadata_tests['[user:name]'] = $bubbleable_metadata; + $metadata_tests['[user:display-name]'] = $bubbleable_metadata; foreach ($tests as $input => $expected) { $bubbleable_metadata = new BubbleableMetadata(); @@ -119,9 +132,13 @@ function testUserTokenReplacement() { // Generate and test unsanitized tokens. $tests = []; - $tests['[user:name]'] = user_format_name($account); + $tests['[user:name]'] = $account->getAccountName(); + $tests['[user:account-name]'] = $account->getAccountName(); + $tests['[user:display-name]'] = $account->getDisplayName(); $tests['[user:mail]'] = $account->getEmail(); - $tests['[current-user:name]'] = user_format_name($global_account); + $tests['[current-user:account-name]'] = $global_account->getAccountname(); + $tests['[current-user:name]'] = $global_account->getAccountName(); + $tests['[current-user:display-name]'] = $global_account->getDisplayName(); foreach ($tests as $input => $expected) { $output = $token_service->replace($input, array('user' => $account), array('langcode' => $language_interface->getId(), 'sanitize' => FALSE)); diff --git a/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php b/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php index 922501f08073f31defa83349fb8b2a6cd3299757..d75215774239738920edc05781cc536fef124e56 100644 --- a/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php +++ b/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php @@ -29,7 +29,8 @@ public function testUserName() { /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); - $this->drupalLogin($this->drupalCreateUser(array('access user profiles'))); + $new_user = $this->drupalCreateUser(array('access user profiles')); + $this->drupalLogin($new_user); // Set defaults. $view = Views::getView('test_views_handler_field_user_name'); @@ -48,24 +49,18 @@ public function testUserName() { }); $this->assertTrue(strpos($render, $anon_name) !== FALSE, 'For user 0 it should use the default anonymous name by default.'); - $username = $this->randomMachineName(); - $view->result[0]->_entity->setUsername($username); - $view->result[0]->_entity->uid->value = 1; - $render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) { - return $view->field['name']->advancedRender($view->result[0]); + $render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $new_user) { + return $view->field['name']->advancedRender($view->result[$new_user->id()]); }); - $this->assertTrue(strpos($render, $username) !== FALSE, 'If link to user is checked the username should be part of the output.'); - $this->assertTrue(strpos($render, 'user/1') !== FALSE, 'If link to user is checked the link to the user should appear as well.'); + $this->assertTrue(strpos($render, $new_user->getDisplayName()) !== FALSE, 'If link to user is checked the username should be part of the output.'); + $this->assertTrue(strpos($render, 'user/' . $new_user->id()) !== FALSE, 'If link to user is checked the link to the user should appear as well.'); $view->field['name']->options['link_to_user'] = FALSE; $view->field['name']->options['type'] = 'string'; - $username = $this->randomMachineName(); - $view->result[0]->_entity->setUsername($username); - $view->result[0]->_entity->uid->value = 1; - $render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) { - return $view->field['name']->advancedRender($view->result[0]); + $render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $new_user) { + return $view->field['name']->advancedRender($view->result[$new_user->id()]); }); - $this->assertEqual($render, $username, 'If the user is not linked the username should be printed out for a normal user.'); + $this->assertEqual($render, $new_user->getDisplayName(), 'If the user is not linked the username should be printed out for a normal user.'); } diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_views_handler_field_user_name.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_views_handler_field_user_name.yml index 13f59595d869e0f61675b501becbe727d7f86aaa..fe96f4e5b8b268b5bbad2bbb3d2a0a16e7e3de1e 100644 --- a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_views_handler_field_user_name.yml +++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_views_handler_field_user_name.yml @@ -51,6 +51,12 @@ display: type: default row: type: fields + sorts: + uid: + id: uid + table: users + field: uid + plugin_id: standard display_plugin: default display_title: Master id: default diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php index c4d5fe94375c299a88f185c1ee8a2610391a1430..26e7f5a678f04cfcb2d4ce1dfa6d0816278f5f11 100644 --- a/core/modules/user/user.api.php +++ b/core/modules/user/user.api.php @@ -107,17 +107,17 @@ function hook_user_cancel_methods_alter(&$methods) { /** * Alter the username that is displayed for a user. * - * Called by user_format_name() to allow modules to alter the username that's - * displayed. Can be used to ensure user privacy in situations where + * Called by $account->getDisplayName() to allow modules to alter the username + * that is displayed. Can be used to ensure user privacy in situations where * $account->name is too revealing. * * @param string $name - * The string that user_format_name() will return. + * The string that $account->getDisplayName() will return. * - * @param object $account + * @param $account * The account object passed to user_format_name(). * - * @see user_format_name() + * @see $account->getDisplayName() */ function hook_user_format_name_alter(&$name, $account) { // Display the user's uid instead of name. diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 73b94139997b1a552ea9120a67d4c5da863747d8..a19acc65daecc1ea0d418b833063ed278ce6e658 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -416,12 +416,12 @@ function user_preprocess_block(&$variables) { * An unsanitized string with the username to display. * * @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. - * Use \Drupal\Core\Session\AccountInterface::getUsername(). + * Use \Drupal\Core\Session\AccountInterface::getDisplayName(). * * @todo Remove usage in https://www.drupal.org/node/2311219. */ function user_format_name(AccountInterface $account) { - return $account->getUsername(); + return $account->getDisplayName(); } /** @@ -469,7 +469,8 @@ function template_preprocess_username(&$variables) { // unsanitized version, in case other preprocess functions want to implement // their own shortening logic or add markup. If they do so, they must ensure // that $variables['name'] is safe for printing. - $name = $variables['name_raw'] = $account->getUsername(); + $name = $account->getDisplayName(); + $variables['name_raw'] = $account->getUsername(); if (Unicode::strlen($name) > 20) { $name = Unicode::truncate($name, 15, FALSE, TRUE); $variables['truncated'] = TRUE; @@ -738,8 +739,8 @@ function _user_cancel($edit, $account, $method) { } $account->block(); $account->save(); - drupal_set_message(t('%name has been disabled.', array('%name' => $account->getUsername()))); - $logger->notice('Blocked user: %name %email.', array('%name' => $account->getUsername(), '%email' => '<' . $account->getEmail() . '>')); + drupal_set_message(t('%name has been disabled.', array('%name' => $account->getDisplayName()))); + $logger->notice('Blocked user: %name %email.', array('%name' => $account->getAccountName(), '%email' => '<' . $account->getEmail() . '>')); break; case 'user_cancel_reassign': @@ -749,8 +750,8 @@ function _user_cancel($edit, $account, $method) { _user_mail_notify('status_canceled', $account); } $account->delete(); - drupal_set_message(t('%name has been deleted.', array('%name' => $account->getUsername()))); - $logger->notice('Deleted user: %name %email.', array('%name' => $account->getUsername(), '%email' => '<' . $account->getEmail() . '>')); + drupal_set_message(t('%name has been deleted.', array('%name' => $account->getDisplayName()))); + $logger->notice('Deleted user: %name %email.', array('%name' => $account->getAccountName(), '%email' => '<' . $account->getEmail() . '>')); break; } @@ -1362,7 +1363,7 @@ function user_toolbar() { '#type' => 'toolbar_item', 'tab' => array( '#type' => 'link', - '#title' => $user->getUsername(), + '#title' => $user->getDisplayName(), '#url' => Url::fromRoute('user.page'), '#attributes' => array( 'title' => t('My account'), @@ -1407,7 +1408,7 @@ function user_toolbar() { function user_logout() { $user = \Drupal::currentUser(); - \Drupal::logger('user')->notice('Session closed for %name.', array('%name' => $user->getUsername())); + \Drupal::logger('user')->notice('Session closed for %name.', array('%name' => $user->getAccountName())); \Drupal::moduleHandler()->invokeAll('user_logout', array($user)); diff --git a/core/modules/user/user.tokens.inc b/core/modules/user/user.tokens.inc index 9cb61f6c9f4c622aa3c409bd047b98acb9ba9ce9..087724e70f4999122b5a78436a7dfecda3aebfe0 100644 --- a/core/modules/user/user.tokens.inc +++ b/core/modules/user/user.tokens.inc @@ -30,9 +30,17 @@ function user_token_info() { 'description' => t("The unique ID of the user account."), ); $user['name'] = array( - 'name' => t("Name"), + 'name' => t("Deprecated: User Name"), + 'description' => t("Deprecated: Use account-name or display-name instead."), + ); + $user['account-name'] = array( + 'name' => t("Account Name"), 'description' => t("The login name of the user account."), ); + $user['display-name'] = array( + 'name' => t("Display Name"), + 'description' => t("The display name of the user account."), + ); $user['mail'] = array( 'name' => t("Email"), 'description' => t("The email address of the user account."), @@ -92,12 +100,20 @@ function user_tokens($type, $tokens, array $data, array $options, BubbleableMeta $replacements[$original] = $account->id() ?: t('not yet assigned'); break; + case 'display-name': + $replacements[$original] = $account->getDisplayName(); + if ($account->isAnonymous()) { + $bubbleable_metadata->addCacheableDependency(\Drupal::config('user.settings')); + } + break; + case 'name': - $name = user_format_name($account); + case 'account-name': + $display_name = $account->getAccountName(); + $replacements[$original] = $sanitize ? Html::escape($display_name) : $display_name; if ($account->isAnonymous()) { $bubbleable_metadata->addCacheableDependency(\Drupal::config('user.settings')); } - $replacements[$original] = $sanitize ? Html::escape($name) : $name; break; case 'mail':