Community Documentation

Form API Internal Workflow Illustration

Last updated May 16, 2012. Created by KarenS on August 7, 2007.
Edited by steinmb, tim.plunkett, fago, add1sun. Log in to edit this page.

This workflow actually includes some of the nodeapi hooks as well as FAPI workflow to help illustrate the places where form elements can be manipulated.

FAPI workflow

Comments

This workflow leaves off

This workflow leaves off what happens after Save. In the normal workflow, it does a drupal_goto (back to the page you're looking on).

-- Merlin

[Point the finger: Assign Blame!]
[Read my writing: ehalseymiles.com]
[Read my Coding blog: Angry Donuts]

-- Merlin

[Read my writing: ehalseymiles.com]
[Read my Coding blog: Angry Donuts]

Hi Merlin, Thanks for the

Hi Merlin,

Thanks for the feedback. Does the drupal_goto() call the same URL as was originally visited, by default? Is there any control over that with a FAPI property?

I'll check with KarenS what to do, as she has documentation-fu.

Cheers,
J-P

--
J-P Stacey, senior developer, Torchbox Ltd.

Yes, and there are ways to

Yes, and there are ways to control it:

The submit function can return the destination to go to

$form['#redirect'] -- set to the destination or to NULL to disable redirects

-- Merlin

[Read my writing: ehalseymiles.com]
[Read my Coding blog: Angry Donuts]

-- Merlin

[Read my writing: ehalseymiles.com]
[Read my Coding blog: Angry Donuts]

what about hook_prepare?

This seems great (just printed off a copy) but it seems to be missing hook_prepare, no?

Jake
---
School and university yearbooks

great chart. one note:

great chart. one note: drupal_retrieve_form($form_id) doesn't necessarily call hook_form(), but any form building function like $form_id. or, if that doesn't exist, a result of hook_forms():

<?php
function drupal_retrieve_form($form_id) {
 
// ...
  // We first check to see if there's a function named after the $form_id.
  // If there is, we simply pass the arguments on to it to get the form.
 
if (!function_exists($form_id)) {
   
// In cases where many form_ids need to share a central builder function,
    // such as the node editing form, modules can implement hook_forms(). It
    // maps one or more form_ids to the correct builder functions.
    //
    // We cache the results of that hook to save time, but that only works
    // for modules that know all their form_ids in advance. (A module that
    // adds a small 'rate this comment' form to each comment in a list
    // would need a unique form_id for each one, for example.)
    //
    // So, we call the hook if $forms isn't yet populated, OR if it doesn't
    // yet have an entry for the requested form_id.
   
if (!isset($forms) || !isset($forms[$form_id])) {
     
$forms = module_invoke_all('forms', $saved_args);
    }
   
$form_definition = $forms[$form_id];
    if (isset(
$form_definition['callback arguments'])) {
     
$args = array_merge($form_definition['callback arguments'], $args);
    }
    if (isset(
$form_definition['callback'])) {
     
$callback = $form_definition['callback'];
    }
  }
 
// If $callback was returned by a hook_forms() implementation, call it.
  // Otherwise, call the function named after the form id.
 
$form = call_user_func_array(isset($callback) ? $callback : $form_id, $args);
 
// ...
}
?>

#after_build

In the workflow '#afterbuild' should be '#after_build' with an underscore.

Corrections and omissions

A correction on the diagram: "presave" is called just before saving the node, and once it's done, one of "update" (if the node has been edited), "insert" (if the node has just been created), or "delete" (if the node has just been deleted) is called. This diagram caused me some confusion when I expected form elements to be saved if I changed them in hook_nodeapi in "insert", since it shows that the node is only saved after the "insert", which it is not. The diagram also leaves out when "update", "load", "prepare", "view" and "alter" are called in hook_nodeapi (for a full list of possible actions implemented in hook_nodeapi, take a look at http://api.drupal.org/api/function/hook_nodeapi/6 )

A helpful description of which action runs when is found in hook_hook_info():
'presave' runs 'When either saving a new post or updating an existing post'
'insert' runs 'After saving a new post'
'update' runs 'After saving an updated post'
'delete' runs 'After deleting a post'
'view' runs 'When content is viewed by an authenticated user'

How to create a profile when

How to create a profile when the form is submitted
http://drupal.org/node/759588

When is #default_value copied to #value?

I noticed that when I want to edit a node, and that node has a custom element in its editing form (custom as in defined by me), the custom element does not have its #default_value copied into #value by the time it reaches the theme function (I set a breakpoint just when it reached the theme function). Here's what I'm doing:


/*
* Implementation of hook_elements()
*/
function stringtree_elements() {
  $type['stringtree'] = array(
    '#input' => TRUE, 
    '#submit' => array('stringtree_submit'),
  );
}

/*
* Implementation of hook_theme()
*/
function stringtree_theme() {
  $theme = array();
  $theme['stringtree'] = array( 'arguments' => array('element' => NULL));
  return $theme;
}

/**
* Theme function for the stringtree element, using a simple textarea.
*
*/
function _theme_stringtree_textarea($element) {
  return theme('textarea', $element);
}

And the form that uses this 'stringtree' element:

function doctemplate_form(&$node, $form_state) {
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => 'Title',
    '#default_value' => $node->title,
    '#required' => TRUE,
  );
  $form['body'] = array(
    '#type' => 'stringtree',   // here's the problem, see below
    '#title' => 'Code',
    '#default_value' => $node->body,
    '#required' => TRUE,
    '#rows' => 20,
  );
  return $form;
}

Nothing fancy here. I open the browser, go to the form to create a node of type 'doctemplate', I add a bunch of text into the 'stringtree' element of the form (which, as the theme function says, is a boring textarea). I click save, it gets into the database. When I go to the "Edit" tab, though, only the Title field actually has contents. The Code field (which uses my 'stringtree') is empty.

Even stranger: if, in the 'doctemplate_form()' function, I replace 'stringtree' with 'textarea' and refresh the page, the text in $node->body fills the textarea. Why doesn't it happen for the 'stringtree'? As I said, I placed a breakpoint in the theme_stringtree() function, and the $element array had no #value field (only #default_value).

Any suggestions? I started stepping through all the process followed by the form API, watching the form while having 'textarea' for the Code field, trying to see when exactly the #value appears, but I'm still not done yet :)

Found it

It was this piece, from form.inc@886:

  if (isset($form['#input']) && $form['#input']) {
    _form_builder_handle_input_element($form_id, $form, $form_state, $complete_form);
  }

This didn't get called, because my element had no $form['#input'], and I didn't understand why. Guess what. I wasn't returning $type in hook_elements(). See code in previous comment. Stupid.

Should this be rather in a forum? Please tell me if so, and I'll remove it from this page.

validation

This doesn't mention element validation. What happens first, element or form, and is this different for D7?

The other Andrew Morton

nice

thank you for this chart. this is awesome!

Drupal 7 form processing flow chart

I'm looking for a processing flow diagram for form generation in Drupal 7. Can anyone help with a link?