38

What is $form_state typically used for in the context of the Form API if it is used as an argument?

Specifically, I'm looking for an example of when it is used.

1 Answer 1

53

$form_state is one of the arguments passed to a form submission handler, or a form validation handler; its main usage is to store the form submitted values (in $form_state['values']), but it also contains values for other purposes.
The documentation for drupal_build_form() shows a list of the values contained in that array, which includes:

  • rebuild: Normally, after the entire form processing is completed and submit handlers have run, a form is considered to be done and drupal_redirect_form() will redirect the user to a new page using a GET request (so a browser refresh does not re-submit the form). However, if 'rebuild' has been set to TRUE, then a new copy of the form is immediately built and sent to the browser, instead of a redirect. This is used for multi-step forms, such as wizards and confirmation forms. Normally, $form_state['rebuild'] is set by a submit handler, since it is usually logic within a submit handler that determines whether a form is done or requires another step. However, a validation handler may already set $form_state['rebuild'] to cause the form processing to bypass submit handlers and rebuild the form instead, even if there are no validation errors.
  • redirect: Used to redirect the form on submission. It may either be a string containing the destination URL, or an array of arguments compatible with drupal_goto(). See drupal_redirect_form() for complete information.
  • cache: If set to TRUE the original, unprocessed form structure will be cached, which allows the entire form to be rebuilt from cache. A typical form workflow involves two page requests; first, a form is built and rendered for the user to fill in. Then, the user fills the form in and submits it, triggering a second page request in which the form must be built and processed. By default, $form and $form_state are built from scratch during each of these page requests. Often, it is necessary or desired to persist the $form and $form_state variables from the initial page request to the one that processes the submission. 'cache' can be set to TRUE to do this. A prominent example is an Ajax-enabled form, in which ajax_process_form() enables form caching for all forms that include an element with the #ajax property. (The Ajax handler has no way to build the form itself, so must rely on the cached version.) Note that the persistence of $form and $form_state happens automatically for (multi-step) forms having the 'rebuild' flag set, regardless of the value for 'cache'.
  • storage: $form_state['storage'] is not a special key, and no specific support is provided for it in the Form API. By tradition it was the location where application-specific data was stored for communication between the submit, validation, and form builder functions, especially in a multi-step-style form. Form implementations may use any key(s) within $form_state (other than the keys listed here and other reserved ones used by Form API internals) for this kind of storage. The recommended way to ensure that the chosen key doesn't conflict with ones used by the Form API or other modules is to use the module name as the key name or a prefix for the key name. For example, the Node module uses $form_state['node'] in node editing forms to store information about the node being edited, and this information stays available across successive clicks of the "Preview" button as well as when the "Save" button is finally clicked.

Other functions that get $form_state as argument are hook_form_alter() and hook_form_FORM_ID_alter().

An example of function that uses $form_state is comment_form_submit(), a form submission handler, which contains the following code.

function comment_form_submit($form, &$form_state) {
  $node = node_load($form_state['values']['nid']);
  $comment = comment_form_submit_build_comment($form, $form_state);
  if (user_access('post comments') && (user_access('administer comments') || $node->comment == COMMENT_NODE_OPEN)) {
    // Save the anonymous user information to a cookie for reuse.
    if (user_is_anonymous()) {
      user_cookie_save(array_intersect_key($form_state['values'], array_flip(array('name', 'mail', 'homepage'))));
    }
    comment_save($comment);
    $form_state['values']['cid'] = $comment->cid;
    
    // Add an entry to the watchdog log.
    watchdog('content', 'Comment posted: %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
    
    // Explain the approval queue if necessary.
    if ($comment->status == COMMENT_NOT_PUBLISHED) {
      if (!user_access('administer comments')) {
        drupal_set_message(t('Your comment has been queued for review by site administrators and will be published after approval.'));
      }
    }
    else {
      drupal_set_message(t('Your comment has been posted.'));
    }
    $query = array();
    // Find the current display page for this comment.
    $page = comment_get_display_page($comment->cid, $node->type);
    if ($page > 0) {
      $query['page'] = $page;
    }
    // Redirect to the newly posted comment.
    $redirect = array('node/' . $node->nid, array(
      'query' => $query,
      'fragment' => 'comment-' . $comment->cid,
    ));
  }
  else {
    watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject), WATCHDOG_WARNING);
    drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject)), 'error');
    // Redirect the user to the node they are commenting on.
    $redirect = 'node/' . $node->nid;
  }
  $form_state['redirect'] = $redirect;
  // Clear the block and page caches so that anonymous users see the comment
 // they have posted.
 cache_clear_all();
}

To understand what $form_state['values'] contains, you need to look at the values added to $form in comment_form(). For example, $form_state contains $form_state['values']['name'] because $form contains $form['author']['name']. Generally, if $form['field'] is a form field, then $form_state will contain $form_state['values']['field'].

2
  • If we want to alter form values or disable multivalue field buttons using hook_form_alter, which variable should be altered $form or $from_state?(when implemented using AJAX or without AJAX). Is $form_state specifically used for ajax?
    – kiranking
    Commented Mar 27, 2015 at 8:35
  • 1
    @kiranking Normally, an AJAX callback returns a part of the $form array; it's the form builder that checks the content of $form_state. This is what I saw in all the AJAX callbacks implemented by modules that do the right thing.
    – avpaderno
    Commented Jun 17, 2016 at 13:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.