View source
<?php
namespace Drupal\user;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityConstraintViolationListInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Url;
use Drupal\language\ConfigurableLanguageManagerInterface;
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin;
use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class AccountForm extends ContentEntityForm implements TrustedCallbackInterface {
protected $languageManager;
public function __construct(EntityRepositoryInterface $entity_repository, LanguageManagerInterface $language_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
parent::__construct($entity_repository, $entity_type_bundle_info, $time);
$this->languageManager = $language_manager;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('entity.repository'), $container
->get('language_manager'), $container
->get('entity_type.bundle.info'), $container
->get('datetime.time'));
}
public function form(array $form, FormStateInterface $form_state) {
$account = $this->entity;
$user = $this
->currentUser();
$config = \Drupal::config('user.settings');
$form['#cache']['tags'] = $config
->getCacheTags();
$language_interface = \Drupal::languageManager()
->getCurrentLanguage();
$register = $account
->isAnonymous();
$admin_create = $register && $account
->access('create');
$self_register = $register && !$admin_create;
$form['account'] = [
'#type' => 'container',
'#weight' => -10,
];
$form['account']['mail'] = [
'#type' => 'email',
'#title' => $this
->t('Email address'),
'#description' => $this
->t('A valid email address. All emails from the system will be sent to this address. The email address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by email.'),
'#required' => !(!$account
->getEmail() && $user
->hasPermission('administer users')),
'#default_value' => !$register ? $account
->getEmail() : '',
];
$form['account']['name'] = [
'#type' => 'textfield',
'#title' => $this
->t('Username'),
'#maxlength' => UserInterface::USERNAME_MAX_LENGTH,
'#description' => $this
->t("Several special characters are allowed, including space, period (.), hyphen (-), apostrophe ('), underscore (_), and the @ sign."),
'#required' => TRUE,
'#attributes' => [
'class' => [
'username',
],
'autocorrect' => 'off',
'autocapitalize' => 'off',
'spellcheck' => 'false',
],
'#default_value' => !$register ? $account
->getAccountName() : '',
'#access' => $account->name
->access('edit'),
];
if (!$register) {
$form['account']['pass'] = [
'#type' => 'password_confirm',
'#size' => 25,
'#description' => $this
->t('To change the current user password, enter the new password in both fields.'),
];
if (!$form_state
->get('user_pass_reset') && ($token = $this
->getRequest()
->get('pass-reset-token'))) {
$session_key = 'pass_reset_' . $account
->id();
$user_pass_reset = isset($_SESSION[$session_key]) && hash_equals($_SESSION[$session_key], $token);
$form_state
->set('user_pass_reset', $user_pass_reset);
}
if ($user
->id() == $account
->id()) {
$form['account']['current_pass'] = [
'#type' => 'password',
'#title' => $this
->t('Current password'),
'#size' => 25,
'#access' => !$form_state
->get('user_pass_reset'),
'#weight' => -5,
'#attributes' => [
'autocomplete' => 'off',
],
];
$form_state
->set('user', $account);
if (!$form_state
->get('user_pass_reset')) {
$form['account']['current_pass']['#description'] = $this
->t('Required if you want to change the %mail or %pass below. <a href=":request_new_url" title="Send password reset instructions via email.">Reset your password</a>.', [
'%mail' => $form['account']['mail']['#title'],
'%pass' => $this
->t('Password'),
':request_new_url' => Url::fromRoute('user.pass')
->toString(),
]);
}
}
}
elseif (!$config
->get('verify_mail') || $admin_create) {
$form['account']['pass'] = [
'#type' => 'password_confirm',
'#size' => 25,
'#description' => $this
->t('Provide a password for the new account in both fields.'),
'#required' => TRUE,
];
}
if (!$register) {
foreach ([
'mail',
'name',
'pass',
] as $key) {
if (isset($form['account'][$key])) {
$form['account'][$key]['#attributes']['autocomplete'] = 'off';
}
}
}
if (!$self_register) {
$status = $account
->get('status')->value;
}
else {
$status = $config
->get('register') == UserInterface::REGISTER_VISITORS ? 1 : 0;
}
$form['account']['status'] = [
'#type' => 'radios',
'#title' => $this
->t('Status'),
'#default_value' => $status,
'#options' => [
$this
->t('Blocked'),
$this
->t('Active'),
],
'#access' => $account->status
->access('edit'),
];
$roles = array_map([
'\\Drupal\\Component\\Utility\\Html',
'escape',
], user_role_names(TRUE));
$form['account']['roles'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Roles'),
'#default_value' => !$register ? $account
->getRoles() : [],
'#options' => $roles,
'#access' => $roles && $user
->hasPermission('administer permissions'),
];
$form['account']['roles'][RoleInterface::AUTHENTICATED_ID] = [
'#default_value' => TRUE,
'#disabled' => TRUE,
];
$form['account']['notify'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Notify user of new account'),
'#access' => $admin_create,
];
$user_preferred_langcode = $register ? $language_interface
->getId() : $account
->getPreferredLangcode();
$user_preferred_admin_langcode = $register ? $language_interface
->getId() : $account
->getPreferredAdminLangcode(FALSE);
$user_language_added = FALSE;
if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) {
$negotiator = $this->languageManager
->getNegotiator();
$user_language_added = $negotiator && $negotiator
->isNegotiationMethodEnabled(LanguageNegotiationUser::METHOD_ID, LanguageInterface::TYPE_INTERFACE);
}
$form['language'] = [
'#type' => $this->languageManager
->isMultilingual() ? 'details' : 'container',
'#title' => $this
->t('Language settings'),
'#open' => TRUE,
'#access' => !$self_register,
];
$form['language']['preferred_langcode'] = [
'#type' => 'language_select',
'#title' => $this
->t('Site language'),
'#languages' => LanguageInterface::STATE_CONFIGURABLE,
'#default_value' => $user_preferred_langcode,
'#description' => $user_language_added ? $this
->t("This account's preferred language for emails and site presentation.") : $this
->t("This account's preferred language for emails."),
'#pre_render' => [
'user_langcode' => [
$this,
'alterPreferredLangcodeDescription',
],
],
];
$show_admin_language = FALSE;
if (($account
->hasPermission('access administration pages') || $account
->hasPermission('view the administration theme')) && $this->languageManager instanceof ConfigurableLanguageManagerInterface) {
$negotiator = $this->languageManager
->getNegotiator();
$show_admin_language = $negotiator && $negotiator
->isNegotiationMethodEnabled(LanguageNegotiationUserAdmin::METHOD_ID);
}
$form['language']['preferred_admin_langcode'] = [
'#type' => 'language_select',
'#title' => $this
->t('Administration pages language'),
'#languages' => LanguageInterface::STATE_CONFIGURABLE,
'#default_value' => $user_preferred_admin_langcode,
'#access' => $show_admin_language,
'#empty_option' => $this
->t('- No preference -'),
'#empty_value' => '',
];
if ($register) {
$form['#entity_builders']['sync_user_langcode'] = '::syncUserLangcode';
}
$system_date_config = \Drupal::config('system.date');
$form['timezone'] = [
'#type' => 'details',
'#title' => t('Locale settings'),
'#open' => TRUE,
'#weight' => 6,
'#access' => $system_date_config
->get('timezone.user.configurable'),
];
if ($self_register && $system_date_config
->get('timezone.user.default') != UserInterface::TIMEZONE_SELECT) {
$form['timezone']['#access'] = FALSE;
}
$form['timezone']['timezone'] = [
'#type' => 'select',
'#title' => t('Time zone'),
'#default_value' => $account
->getTimezone() ?: $system_date_config
->get('timezone.default'),
'#options' => system_time_zones($account
->id() != $user
->id(), TRUE),
'#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'),
];
$user_input = $form_state
->getUserInput();
if (!$account
->getTimezone() && $account
->id() == $user
->id() && empty($user_input['timezone'])) {
$form['timezone']['#attached']['library'][] = 'core/drupal.timezone';
$form['timezone']['timezone']['#attributes'] = [
'class' => [
'timezone-detect',
],
];
}
return parent::form($form, $form_state, $account);
}
public static function trustedCallbacks() {
return [
'alterPreferredLangcodeDescription',
];
}
public function alterPreferredLangcodeDescription(array $element) {
if (isset($element['#description'])) {
$element['#description'] .= ' ' . $this
->t("This is also assumed to be the primary language of this account's profile information.");
}
return $element;
}
public function syncUserLangcode($entity_type_id, UserInterface $user, array &$form, FormStateInterface &$form_state) {
$user
->getUntranslated()->langcode = $user->preferred_langcode;
}
public function buildEntity(array $form, FormStateInterface $form_state) {
if (is_string(key($form_state
->getValue('roles')))) {
$form_state
->setValue('roles', array_keys(array_filter($form_state
->getValue('roles'))));
}
$account = parent::buildEntity($form, $form_state);
foreach ([
'preferred_langcode',
'preferred_admin_langcode',
] as $field_name) {
if ($form_state
->getValue($field_name) === '') {
$account->{$field_name} = NULL;
}
}
$current_pass = trim($form_state
->getValue('current_pass'));
if (strlen($current_pass) > 0) {
$account
->setExistingPassword($current_pass);
}
$account->_skipProtectedUserFieldConstraint = $form_state
->get('user_pass_reset');
return $account;
}
protected function getEditedFieldNames(FormStateInterface $form_state) {
return array_merge([
'name',
'pass',
'mail',
'timezone',
'langcode',
'preferred_langcode',
'preferred_admin_langcode',
], parent::getEditedFieldNames($form_state));
}
protected function flagViolations(EntityConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
$field_names = [
'name',
'pass',
'mail',
'timezone',
'langcode',
'preferred_langcode',
'preferred_admin_langcode',
];
foreach ($violations
->getByFields($field_names) as $violation) {
list($field_name) = explode('.', $violation
->getPropertyPath(), 2);
$form_state
->setErrorByName($field_name, $violation
->getMessage());
}
parent::flagViolations($violations, $form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
$user = $this
->getEntity($form_state);
if (isset($_SESSION['pass_reset_' . $user
->id()])) {
unset($_SESSION['pass_reset_' . $user
->id()]);
}
}
}