FormBuilder::handleInputElement

protected FormBuilder::handleInputElement($form_id, &$element, FormStateInterface &$form_state)

Adds the #name and #value properties of an input element before rendering.

File

core/lib/Drupal/Core/Form/FormBuilder.php, line 1149

Class

FormBuilder
Provides form building and processing.

Namespace

Drupal\Core\Form

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
protected function handleInputElement($form_id, &$element, FormStateInterface &$form_state) {
  if (!isset($element['#name'])) {
    $name = array_shift($element['#parents']);
    $element['#name'] = $name;
    if ($element['#type'] == 'file') {
      // To make it easier to handle files in file.inc, we place all
      // file fields in the 'files' array. Also, we do not support
      // nested file names.
      // @todo Remove this files prefix now?
      $element['#name'] = 'files[' . $element['#name'] . ']';
    }
    elseif (count($element['#parents'])) {
      $element['#name'] .= '[' . implode('][', $element['#parents']) . ']';
    }
    array_unshift($element['#parents'], $name);
  }
 
  // Setting #disabled to TRUE results in user input being ignored regardless
  // of how the element is themed or whether JavaScript is used to change the
  // control's attributes. However, it's good UI to let the user know that
  // input is not wanted for the control. HTML supports two attributes for:
  // this: http://www.w3.org/TR/html401/interact/forms.html#h-17.12. If a form
  // wants to start a control off with one of these attributes for UI
  // purposes, only, but still allow input to be processed if it's submitted,
  // it can set the desired attribute in #attributes directly rather than
  // using #disabled. However, developers should think carefully about the
  // accessibility implications of doing so: if the form expects input to be
  // enterable under some condition triggered by JavaScript, how would someone
  // who has JavaScript disabled trigger that condition? Instead, developers
  // should consider whether a multi-step form would be more appropriate
  // (#disabled can be changed from step to step). If one still decides to use
  // JavaScript to affect when a control is enabled, then it is best for
  // accessibility for the control to be enabled in the HTML, and disabled by
  // JavaScript on document ready.
  if (!empty($element['#disabled'])) {
    if (!empty($element['#allow_focus'])) {
      $element['#attributes']['readonly'] = 'readonly';
    }
    else {
      $element['#attributes']['disabled'] = 'disabled';
    }
  }
 
  // With JavaScript or other easy hacking, input can be submitted even for
  // elements with #access=FALSE or #disabled=TRUE. For security, these must
  // not be processed. Forms that set #disabled=TRUE on an element do not
  // expect input for the element, and even forms submitted with
  // self::submitForm() must not be able to get around this. Forms that set
  // #access=FALSE on an element usually allow access for some users, so forms
  // submitted with self::submitForm() may bypass access restriction and be
  // treated as high-privilege users instead.
  $process_input = empty($element['#disabled']) && (($form_state->isProgrammed() && $form_state->isBypassingProgrammedAccessChecks()) || ($form_state->isProcessingInput() && (!isset($element['#access']) || $element['#access'])));
 
  // Set the element's #value property.
  if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
    // @todo Once all elements are converted to plugins in
    //   https://www.drupal.org/node/2311393, rely on
    //   $element['#value_callback'] directly.
    $value_callable = !empty($element['#value_callback']) ? $element['#value_callback'] : 'form_type_' . $element['#type'] . '_value';
    if (!is_callable($value_callable)) {
      $value_callable = '\Drupal\Core\Render\Element\FormElement::valueCallback';
    }
 
    if ($process_input) {
      // Get the input for the current element. NULL values in the input need
      // to be explicitly distinguished from missing input. (see below)
      $input_exists = NULL;
      $input = NestedArray::getValue($form_state->getUserInput(), $element['#parents'], $input_exists);
      // For browser-submitted forms, the submitted values do not contain
      // values for certain elements (empty multiple select, unchecked
      // checkbox). During initial form processing, we add explicit NULL
      // values for such elements in FormState::$input. When rebuilding the
      // form, we can distinguish elements having NULL input from elements
      // that were not part of the initially submitted form and can therefore
      // use default values for the latter, if required. Programmatically
      // submitted forms can submit explicit NULL values when calling
      // self::submitForm() so we do not modify FormState::$input for them.
      if (!$input_exists && !$form_state->isRebuilding() && !$form_state->isProgrammed()) {
        // Add the necessary parent keys to FormState::$input and sets the
        // element's input value to NULL.
        NestedArray::setValue($form_state->getUserInput(), $element['#parents'], NULL);
        $input_exists = TRUE;
      }
      // If we have input for the current element, assign it to the #value
      // property, optionally filtered through $value_callback.
      if ($input_exists) {
        // Skip all value callbacks except safe ones like text if the CSRF
        // token was invalid.
        if (!$form_state->hasInvalidToken() || $this->valueCallableIsSafe($value_callable)) {
          $element['#value'] = call_user_func_array($value_callable, array(&$element, $input, &$form_state));
        }
        else {
          $input = NULL;
        }
 
        if (!isset($element['#value']) && isset($input)) {
          $element['#value'] = $input;
        }
      }
      // Mark all posted values for validation.
      if (isset($element['#value']) || (!empty($element['#required']))) {
        $element['#needs_validation'] = TRUE;
      }
    }
    // Load defaults.
    if (!isset($element['#value'])) {
      // Call #type_value without a second argument to request default_value
      // handling.
      $element['#value'] = call_user_func_array($value_callable, array(&$element, FALSE, &$form_state));
 
      // Final catch. If we haven't set a value yet, use the explicit default
      // value. Avoid image buttons (which come with garbage value), so we
      // only get value for the button actually clicked.
      if (!isset($element['#value']) && empty($element['#has_garbage_value'])) {
        $element['#value'] = isset($element['#default_value']) ? $element['#default_value'] : '';
      }
    }
  }
 
  // Determine which element (if any) triggered the submission of the form and
  // keep track of all the clickable buttons in the form for
  // \Drupal\Core\Form\FormState::cleanValues(). Enforce the same input
  // processing restrictions as above.
  if ($process_input) {
    // Detect if the element triggered the submission via Ajax.
    if ($this->elementTriggeredScriptedSubmission($element, $form_state)) {
      $form_state->setTriggeringElement($element);
    }
 
    // If the form was submitted by the browser rather than via Ajax, then it
    // can only have been triggered by a button, and we need to determine
    // which button within the constraints of how browsers provide this
    // information.
    if (!empty($element['#is_button'])) {
      // All buttons in the form need to be tracked for
      // \Drupal\Core\Form\FormState::cleanValues() and for the
      // self::doBuildForm() code that handles a form submission containing no
      // button information in \Drupal::request()->request.
      $buttons = $form_state->getButtons();
      $buttons[] = $element;
      $form_state->setButtons($buttons);
      if ($this->buttonWasClicked($element, $form_state)) {
        $form_state->setTriggeringElement($element);
      }
    }
  }
 
  // Set the element's value in $form_state->getValues(), but only, if its key
  // does not exist yet (a #value_callback may have already populated it).
  if (!NestedArray::keyExists($form_state->getValues(), $element['#parents'])) {
    $form_state->setValueForElement($element, $element['#value']);
  }
}
doc_Drupal
2025-01-10 15:47:30
Comments
Leave a Comment

Please login to continue.