As Clive said, the tokens are generated from hook_token_info()
and hook_tokens()
. For the User
entity, those hooks are implemented from the User module. Token values aren't available just for email templates, but for every function/method that uses the token service. For example, in a controller, I could use code similar to the following one.
$bubbleable_metadata = new BubbleableMetadata();
$build['#markup'] = $this->tokenService->replace('Tokens: [node:nid] [current-user:uid]', ['node' => $node], [], $bubbleable_metadata);
$bubbleable_metadata->applyTo($build);
As for getting the display name of a user account, that is easy: When user tokens are generated, user_tokens()
gets a user object; calling User::getDisplayName()
on that user object returns its display name.
See the code used from user_tokens()
; in particular, see the following code. (Comments are mine.)
// Retrieves the user object passed to the hook.
$account = $data['user'];
// Generates the value for the display name token.
$replacements[$original] = $account
->getDisplayName();
if ($account->isAnonymous()) {
$bubbleable_metadata->addCacheableDependency(\Drupal::config('user.settings'));
}
It is true there are user tokens available only for email templates, but that are generated from a callback used when replacing tokens in email templates. See user_mail()
and user_mail_tokens()
.
// user_mail()
$token_service = \Drupal::token();
$language_manager = \Drupal::languageManager();
$langcode = $message['langcode'];
$variables = ['user' => $params['account']];
$language = $language_manager->getLanguage($params['account']
->getPreferredLangcode());
$original_language = $language_manager->getConfigOverrideLanguage();
$language_manager->setConfigOverrideLanguage($language);
$mail_config = \Drupal::config('user.mail');
$token_options = [
'langcode' => $langcode,
'callback' => 'user_mail_tokens',
'clear' => TRUE,
];
$message['subject'] .= PlainTextOutput::renderFromHtml($token_service
->replace($mail_config->get($key . '.subject'), $variables, $token_options));
$message['body'][] = $token_service
->replace($mail_config->get($key . '.body'), $variables, $token_options);
function user_mail_tokens(&$replacements, $data, $options) {
if (isset($data['user'])) {
$replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user'], $options);
$replacements['[user:cancel-url]'] = user_cancel_url($data['user'], $options);
}
}
user_mail()
says to Token::replace()
that user_mail_tokens()
must be called after all the tokens are generated, and user_mail_tokens()
replaces [user:one-time-login-url] and [user:one-time-cancel-url] (not replaced from Token::replace()
) with the right values.
Similar code can be used from any module to generate tokens that must be available only in specific context.