drupal_build_form

Versions
7
drupal_build_form($form_id, &$form_state)

Build and process a form based on a form id.

The form may also be retrieved from the cache if the form was built in a previous page-load. The form is then passed on for processing, validation and submission if there is proper input.

See also

drupal_redirect_form()

Parameters

$form_id The unique string identifying the desired form. If a function with that name exists, it is called to build the form array. Modules that need to generate the same form (or very similar forms) using different $form_ids can implement hook_forms(), which maps different $form_id values to the proper form constructor function. Examples may be found in node_forms(), search_forms(), and user_forms().

&$form_state An array which stores information about the form. This is passed as a reference so that the caller can use it to examine what in the form changed when the form submission process is complete. The following parameters may be set in $form_state to affect how the form is rendered:

  • build_info: A keyed array of build information that is necessary to rebuild the form from cache when the original context may no longer be available:

    • args: An array of arguments to pass to the form builder.
    • file: An optional include file that contains the form and is automatically loaded by form_get_cache(). Defaults to the current menu router item's 'file' definition, if existent.
  • storage: An array that may be used to store information related to the processed data in the form, which can be accessed and used within the same page request, but also persist across multiple steps in a multi-step form.
  • rebuild: Normally, after the entire form processing is completed and submit handlers ran, 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. Also, if a form validation handler has set 'rebuild' to TRUE and a validation error occurred, then the form is rebuilt prior to being returned, enabling form elements to be altered, as appropriate to the particular validation error.
  • input: An array of input that corresponds to $_POST or $_GET, depending on the 'method' chosen (see below).
  • method: The HTTP form method to use for finding the input for this form. May be 'post' or 'get'. Defaults to 'post'. Note that 'get' method forms do not use form ids so are always considered to be submitted, which can have unexpected effects. The 'get' method should only be used on forms that do not change data, as that is exclusively the domain of post.
  • no_redirect: If set to TRUE the form will NOT perform a drupal_goto(), even if 'redirect' is set.
  • cache: If set to TRUE the original, unprocessed form structure will be cached, which allows to rebuild the entire form from cache.
  • no_cache: If set to TRUE the form will NOT be cached, even if 'cache' is set.
  • always_process: If TRUE and the method is GET, a form_id is not necessary. This should only be used on RESTful GET forms that do NOT write data, as this could lead to security issues. It is useful so that searches do not need to have a form_id in their query arguments to trigger the search.
  • must_validate: Ordinarily, a form is only validated once but there are times when a form is resubmitted internally and should be validated again. Setting this to TRUE will force that to happen. This is most likely to occur during AHAH or AJAX operations.
  • wrapper_callback: Modules that wish to pre-populate certain forms with common elements, such as back/next/save buttons in multi-step form wizards, may define a form builder function name that returns a form structure, which is passed on to the actual form builder function. Such implementations may either define the 'wrapper_callback' via hook_forms() or have to invoke drupal_build_form() (instead of drupal_get_form()) on their own in a custom menu callback to prepare $form_state accordingly.

Further $form_state properties controlling the redirection behavior after form submission may be found in drupal_redirect_form().

Return value

The rendered form or NULL, depending upon the $form_state flags that were set.

Related topics

▾ 3 functions call drupal_build_form()

drupal_get_form in includes/form.inc
Wrapper for drupal_build_form() for use when $form_state is not needed.
form_test_wrapper_callback in modules/simpletest/tests/form_test.module
Menu callback; Invokes a form builder function with a wrapper callback.
install_run_task in ./install.php
Run an individual installation task.

Code

includes/form.inc, line 159

<?php
function drupal_build_form($form_id, &$form_state) {
  // Ensure some defaults; if already set they will not be overridden.
  $form_state += form_state_defaults();

  if (!isset($form_state['input'])) {
    $form_state['input'] = $form_state['method'] == 'get' ? $_GET : $_POST;
  }

  $cacheable = FALSE;

  if (isset($_SESSION['batch_form_state'])) {
    // We've been redirected here after a batch processing : the form has
    // already been processed, so we grab the post-process $form_state value
    // and move on to form display. See _batch_finished() function.
    $form_state = $_SESSION['batch_form_state'];
    unset($_SESSION['batch_form_state']);
  }
  else {
    // If the incoming input contains a form_build_id, we'll check the
    // cache for a copy of the form in question. If it's there, we don't
    // have to rebuild the form to proceed. In addition, if there is stored
    // form_state data from a previous step, we'll retrieve it so it can
    // be passed on to the form processing code.
    if (isset($form_state['input']['form_id']) && $form_state['input']['form_id'] == $form_id && !empty($form_state['input']['form_build_id'])) {
      $form = form_get_cache($form_state['input']['form_build_id'], $form_state);
    }

    // If the previous bit of code didn't result in a populated $form
    // object, we're hitting the form for the first time and we need
    // to build it from scratch.
    if (!isset($form)) {
      // Record the filepath of the include file containing the original form,
      // so the form builder callbacks can be loaded when the form is being
      // rebuilt from cache on a different path (such as 'system/ajax').
      // @see form_get_cache()
      // menu_get_item() is not available at installation time.
      if (!isset($form_state['build_info']['file']) && !defined('MAINTENANCE_MODE')) {
        $item = menu_get_item();
        if (!empty($item['file'])) {
          $form_state['build_info']['file'] = $item['file'];
        }
      }

      $form = drupal_retrieve_form($form_id, $form_state);
      $form_build_id = 'form-' . md5(uniqid(mt_rand(), TRUE));
      $form['#build_id'] = $form_build_id;

      // Fix the form method, if it is 'get' in $form_state, but not in $form.
      if ($form_state['method'] == 'get' && !isset($form['#method'])) {
        $form['#method'] = 'get';
      }

      drupal_prepare_form($form_id, $form, $form_state);
      // Store a copy of the unprocessed form for caching and indicate that it
      // is cacheable in case $form_state['cache'] is set.
      $original_form = $form;
      $cacheable = TRUE;
    }

    // Now that we know we have a form, we'll process it (validating,
    // submitting, and handling the results returned by its submission
    // handlers. Submit handlers accumulate data in the form_state by
    // altering the $form_state variable, which is passed into them by
    // reference.
    drupal_process_form($form_id, $form, $form_state);

    // After processing the form, the form builder or a #process callback may
    // have set $form_state['cache'] to indicate that the original form and the
    // $form_state shall be cached. But the form may only be cached if the
    // special 'no_cache' property is not set to TRUE.
    if ($cacheable && !empty($form_state['cache']) && empty($form_state['no_cache'])) {
      form_set_cache($form_build_id, $original_form, $form_state);
    }
  }

  // Most simple, single-step forms will be finished by this point --
  // drupal_process_form() usually redirects to another page (or to
  // a 'fresh' copy of the form) once processing is complete. If one
  // of the form's handlers has set $form_state['redirect'] to FALSE,
  // the form will simply be re-rendered with the values still in its
  // fields.
  //
  // If $form_state['rebuild'] has been set and the form has been submitted, we
  // know that we're in a multi-part process of some sort and the form's
  // workflow is not complete. We need to construct a fresh copy of the form,
  // passing in the latest $form_state in addition to any other variables passed
  // into drupal_get_form().
  if ($form_state['rebuild'] && $form_state['submitted'] && !form_get_errors()) {
    $form = drupal_rebuild_form($form_id, $form_state);
  }

  // Don't override #theme if someone already set it.
  if (!isset($form['#theme'])) {
    drupal_theme_initialize();
    $registry = theme_get_registry();
    if (isset($registry[$form_id])) {
      $form['#theme'] = $form_id;
    }
  }

  return $form;
}
?>
Login or register to post comments
 
 

All source code and documentation on this site is released under the terms of the GNU General Public License, version 2 and later. Drupal is a registered trademark of Dries Buytaert.