protected FormBuilder::handleInputElement($form_id, &$element, FormStateInterface &$form_state)
Adds the #name and #value properties of an input element before rendering.
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']); } }
© 2001–2016 by the original authors
Licensed under the GNU General Public License, version 2 and later.
Drupal is a registered trademark of Dries Buytaert.
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Form!FormBuilder.php/function/FormBuilder::handleInputElement/8.1.x