3 namespace Drupal\Core\Render\Element;
5 use Drupal\Core\Form\FormStateInterface;
8 * Provides a form element for double-input of passwords.
10 * Formats as a pair of password fields, which do not validate unless the two
11 * entered passwords match.
14 * - #size: The size of the input element in characters.
18 * $form['pass'] = array(
19 * '#type' => 'password_confirm',
20 * '#title' => $this->t('Password'),
25 * @see \Drupal\Core\Render\Element\Password
27 * @FormElement("password_confirm")
29 class PasswordConfirm extends FormElement {
34 public function getInfo() {
35 $class = get_class($this);
40 [$class, 'processPasswordConfirm'],
42 '#theme_wrappers' => ['form_element'],
49 public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
50 if ($input === FALSE) {
51 $element += ['#default_value' => []];
52 return $element['#default_value'] + ['pass1' => '', 'pass2' => ''];
54 $value = ['pass1' => '', 'pass2' => ''];
55 // Throw out all invalid array keys; we only allow pass1 and pass2.
56 foreach ($value as $allowed_key => $default) {
57 // These should be strings, but allow other scalars since they might be
58 // valid input in programmatic form submissions. Any nested array values
60 if (isset($input[$allowed_key]) && is_scalar($input[$allowed_key])) {
61 $value[$allowed_key] = (string) $input[$allowed_key];
68 * Expand a password_confirm field into two text boxes.
70 public static function processPasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
72 '#type' => 'password',
73 '#title' => t('Password'),
74 '#value' => empty($element['#value']) ? NULL : $element['#value']['pass1'],
75 '#required' => $element['#required'],
76 '#attributes' => ['class' => ['password-field', 'js-password-field']],
77 '#error_no_message' => TRUE,
80 '#type' => 'password',
81 '#title' => t('Confirm password'),
82 '#value' => empty($element['#value']) ? NULL : $element['#value']['pass2'],
83 '#required' => $element['#required'],
84 '#attributes' => ['class' => ['password-confirm', 'js-password-confirm']],
85 '#error_no_message' => TRUE,
87 $element['#element_validate'] = [[get_called_class(), 'validatePasswordConfirm']];
88 $element['#tree'] = TRUE;
90 if (isset($element['#size'])) {
91 $element['pass1']['#size'] = $element['pass2']['#size'] = $element['#size'];
98 * Validates a password_confirm element.
100 public static function validatePasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
101 $pass1 = trim($element['pass1']['#value']);
102 $pass2 = trim($element['pass2']['#value']);
103 if (strlen($pass1) > 0 || strlen($pass2) > 0) {
104 if (strcmp($pass1, $pass2)) {
105 $form_state->setError($element, t('The specified passwords do not match.'));
108 elseif ($element['#required'] && $form_state->getUserInput()) {
109 $form_state->setError($element, t('Password field is required.'));
112 // Password field must be converted from a two-element array into a single
113 // string regardless of validation results.
114 $form_state->setValueForElement($element['pass1'], NULL);
115 $form_state->setValueForElement($element['pass2'], NULL);
116 $form_state->setValueForElement($element, $pass1);