You are here

public function FormBuilder::processForm in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::processForm()

Processes a form submission.

This function is the heart of form API. The form gets built, validated and in appropriate cases, submitted and rebuilt.

Parameters

string $form_id: The unique string identifying the current form.

array $form: An associative array containing the structure of the form.

\Drupal\Core\Form\FormStateInterface $form_state: The current state of the form. This includes the current persistent storage data for the form, and any data passed along by earlier steps when displaying a multi-step form. Additional information, like the sanitized \Drupal::request()->request data, is also accumulated here.

Return value

\Symfony\Component\HttpFoundation\RedirectResponse|null

Overrides FormBuilderInterface::processForm

2 calls to FormBuilder::processForm()
FormBuilder::buildForm in core/lib/Drupal/Core/Form/FormBuilder.php
Builds and processes a form for a given form ID.
FormBuilder::submitForm in core/lib/Drupal/Core/Form/FormBuilder.php
Retrieves, populates, and processes a form.

File

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

Class

FormBuilder
Provides form building and processing.

Namespace

Drupal\Core\Form

Code

public function processForm($form_id, &$form, FormStateInterface &$form_state) {
  $form_state
    ->setValues([]);

  // With GET, these forms are always submitted if requested.
  if ($form_state
    ->isMethodType('get') && $form_state
    ->getAlwaysProcess()) {
    $input = $form_state
      ->getUserInput();
    if (!isset($input['form_build_id'])) {
      $input['form_build_id'] = $form['#build_id'];
    }
    if (!isset($input['form_id'])) {
      $input['form_id'] = $form_id;
    }
    if (!isset($input['form_token']) && isset($form['#token'])) {
      $input['form_token'] = $this->csrfToken
        ->get($form['#token']);
    }
    $form_state
      ->setUserInput($input);
  }

  // self::doBuildForm() finishes building the form by calling element
  // #process functions and mapping user input, if any, to #value properties,
  // and also storing the values in $form_state->getValues(). We need to
  // retain the unprocessed $form in case it needs to be cached.
  $unprocessed_form = $form;
  $form = $this
    ->doBuildForm($form_id, $form, $form_state);

  // Only process the input if we have a correct form submission.
  if ($form_state
    ->isProcessingInput()) {

    // Form values for programmed form submissions typically do not include a
    // value for the submit button. But without a triggering element, a
    // potentially existing #limit_validation_errors property on the primary
    // submit button is not taken account. Therefore, check whether there is
    // exactly one submit button in the form, and if so, automatically use it
    // as triggering_element.
    $buttons = $form_state
      ->getButtons();
    if ($form_state
      ->isProgrammed() && !$form_state
      ->getTriggeringElement() && count($buttons) == 1) {
      $form_state
        ->setTriggeringElement(reset($buttons));
    }
    $this->formValidator
      ->validateForm($form_id, $form, $form_state);

    // If there are no errors and the form is not rebuilding, submit the form.
    if (!$form_state
      ->isRebuilding() && !FormState::hasAnyErrors()) {
      $submit_response = $this->formSubmitter
        ->doSubmitForm($form, $form_state);

      // If this form was cached, delete it from the cache after submission.
      if ($form_state
        ->isCached()) {
        $this
          ->deleteCache($form['#build_id']);
      }

      // If the form submission directly returned a response, return it now.
      if ($submit_response) {
        return $submit_response;
      }
    }

    // Don't rebuild or cache form submissions invoked via self::submitForm().
    if ($form_state
      ->isProgrammed()) {
      return;
    }

    // If $form_state->isRebuilding() has been set and input has been
    // processed without validation errors, we are in a multi-step workflow
    // that is not yet complete. A new $form needs to be constructed based on
    // the changes made to $form_state during this request. Normally, a submit
    // handler sets $form_state->isRebuilding() if a fully executed form
    // requires another step. However, for forms that have not been fully
    // executed (e.g., Ajax submissions triggered by non-buttons), there is no
    // submit handler to set $form_state->isRebuilding(). It would not make
    // sense to redisplay the identical form without an error for the user to
    // correct, so we also rebuild error-free non-executed forms, regardless
    // of $form_state->isRebuilding().
    // @todo Simplify this logic; considering Ajax and non-HTML front-ends,
    //   along with element-level #submit properties, it makes no sense to
    //   have divergent form execution based on whether the triggering element
    //   has #executes_submit_callback set to TRUE.
    if (($form_state
      ->isRebuilding() || !$form_state
      ->isExecuted()) && !FormState::hasAnyErrors()) {

      // Form building functions (e.g., self::handleInputElement()) may use
      // $form_state->isRebuilding() to determine if they are running in the
      // context of a rebuild, so ensure it is set.
      $form_state
        ->setRebuild();
      $form = $this
        ->rebuildForm($form_id, $form_state, $form);
    }
  }

  // After processing the form, the form builder or a #process callback may
  // have called $form_state->setCached() to indicate that the form and form
  // state shall be cached. But the form may only be cached if
  // $form_state->disableCache() is not called. Only cache $form as it was
  // prior to self::doBuildForm(), because self::doBuildForm() must run for
  // each request to accommodate new user input. Rebuilt forms are not cached
  // here, because self::rebuildForm() already takes care of that.
  if (!$form_state
    ->isRebuilding() && $form_state
    ->isCached()) {
    $this
      ->setCache($form['#build_id'], $unprocessed_form, $form_state);
  }
}