function FormBuilder::handleInputElement
Same name in other branches
- 9 core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::handleInputElement()
- 8.9.x core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::handleInputElement()
- 10 core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::handleInputElement()
Adds the #name and #value properties of an input element before rendering.
1 call to FormBuilder::handleInputElement()
- FormBuilder::doBuildForm in core/
lib/ Drupal/ Core/ Form/ FormBuilder.php - Builds and processes all elements in the structured form array.
File
-
core/
lib/ Drupal/ Core/ Form/ FormBuilder.php, line 1167
Class
- FormBuilder
- Provides form building and processing.
Namespace
Drupal\Core\FormCode
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, 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: https://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']) && !in_array($element['#type'], [
'item',
'value',
], TRUE) && ($form_state->isProgrammed() && $form_state->isBypassingProgrammedAccessChecks() || $form_state->isProcessingInput() && (!isset($element['#access']) || ($element['#access'] instanceof AccessResultInterface && $element['#access']->isAllowed() || $element['#access'] === TRUE)));
// Set the element's #value property.
if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
$value_callable = $element['#value_callback'] ?? NULL;
if (!is_callable($value_callable)) {
$value_callable = '\\Drupal\\Core\\Render\\Element\\FormElementBase::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, [
&$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, [
&$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'] = $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']);
}
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.