/**
  * #after_build of a field collection element.
  *
  * Delays the validation of #required.
  */
 public static function delayRequiredValidation(&$element, FormStateInterface $form_state)
 {
     // If the process_input flag is set, the form and its input is going to be
     // validated. Prevent #required (sub)fields from throwing errors while
     // their non-#required field collection item is empty.
     if ($form_state->isProcessingInput()) {
         static::collectRequiredElements($element, $element['#field_collection_required_elements']);
     }
     return $element;
 }
Ejemplo n.º 2
0
 /**
  * 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']);
     }
 }
Ejemplo n.º 3
0
 /**
  * {@inheritdoc}
  */
 public function isProcessingInput()
 {
     return $this->mainFormState->isProcessingInput();
 }
Ejemplo n.º 4
0
 /**
  * Form element #after_build callback: Updates the entity with submitted data.
  *
  * Updates the internal $this->entity object with submitted values when the
  * form is being rebuilt (e.g. submitted via AJAX), so that subsequent
  * processing (e.g. AJAX callbacks) can rely on it.
  */
 public function afterBuild(array $element, FormStateInterface $form_state)
 {
     // Rebuild the entity if #after_build is being called as part of a form
     // rebuild, i.e. if we are processing input.
     if ($form_state->isProcessingInput()) {
         $this->entity = $this->buildEntity($element, $form_state);
     }
     return $element;
 }
Ejemplo n.º 5
0
 /**
  * {@inheritdoc}
  */
 public function isProcessingInput()
 {
     return $this->decoratedFormState->isProcessingInput();
 }
 /**
  * @covers ::isProcessingInput
  *
  * @dataProvider providerSingleBooleanArgument
  *
  * @param bool $process_input
  */
 public function testIsProcessingInput($process_input)
 {
     $this->decoratedFormState->isProcessingInput()->willReturn($process_input)->shouldBecalled();
     $this->assertSame($process_input, $this->formStateDecoratorBase->isProcessingInput());
 }