Form API Quickstart Guide
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><!-- $Id: forms_api.html,v 1.22 2009/12/13 21:33:05 rfay Exp $ -->
<title>Form API Quickstart Guide</title></head>
<body>
<h1>Form API Quickstart Guide</h1>
<p>The Drupal Form API is a powerful leap forward. It also allows for
almost unlimited possibilities for custom theming, validation, and
execution of forms. Even better, ANY form (even those in core) can be
altered in almost any way imaginable--elements can be removed, added,
and rearranged. This page is certainly not a comprehensive guide to
this functionality, but should provide a good working foundation with
which to do the most basic form creation, theming, validation, and
execution. For programming details on form elements and their
properties, please see the <a href="http://api.drupal.org/api/file/developer/topics/forms_api_reference.html/7">Forms API Reference</a>.</p>
<h2>Creating Forms</h2>
<p>Form elements are now declared in array fashion, with the
hierarchical structure of the form elements themselves as array
elements (which can be nested), and each form elements
properties/attributes listed as array elements in key/value pairs--the
key being the name of the property/attribute, and the value being the
value of the property/attribute. For example, here's how to go about
constructing a textfield form element:</p>
<div class="codeblock">
<p><code><font color="#000000"> <font color="#0000bb"><?php<br />
$form</font><font color="#007700">[</font><font color="#dd0000">'foo'</font><font color="#007700">] = array(<br />
</font><font color="#dd0000"> '#type' </font><font color="#007700">=> </font><font color="#dd0000">'textfield'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'bar'</font><font color="#007700">),<br />
</font><font color="#dd0000">'#default_value' </font><font color="#007700">=> </font><font color="#0000bb">$object</font><font color="#007700">[</font><font color="#dd0000">'foo'</font><font color="#007700">],<br />
</font></font></code><code><font color="#000000"><font color="#dd0000">'#size' </font><font color="#007700">=> </font><font color="#0000bb">60</font><font color="#007700">,<br />
</font></font></code><code><font color="#000000"><font color="#dd0000">'#maxlength' </font><font color="#007700">=> </font><font color="#0000bb">64</font><font color="#007700">, </font><font color="#dd0000"><br />
'#description' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'baz'</font><font color="#007700">),<br />
</font></font></code><code><font color="#000000"><font color="#007700">);<br />
</font><font color="#0000bb">?></font> </font> </code></p>
</div>
<p>and a submit button:</p>
<div class="codeblock">
<p><code><font color="#000000"> <font color="#0000bb"><?php<br />
$form</font><font color="#007700">[</font><font color="#dd0000">'submit'</font><font color="#007700">] = array(</font><font color="#dd0000"><br />
'#type' </font><font color="#007700">=> </font><font color="#dd0000">'submit'</font><font color="#007700">,<br />
</font></font></code><code><font color="#000000"><font color="#dd0000">'#value' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Save'</font><font color="#007700">),<br />
</font></font></code><code><font color="#000000"><font color="#007700">);<br />
</font><font color="#0000bb">?></font> </font> </code></p>
</div>
<p>a few things to note:</p>
<ol>
<li>The element's <code>name</code> property is declared in the <code>$form</code> array, at the very end of the array tree. For example, if an element in the form tree was structured like this:<br />
<br />
<div class="codeblock"><code><font color="#000000"> <font color="#0000bb"><?php<br />
$form</font><font color="#007700">[</font><font color="#dd0000">'account_settings'</font><font color="#007700">][</font><font color="#dd0000">'username'</font><font color="#007700">]<br />
</font><font color="#0000bb">?></font> </font> </code></div>
<br />
...then that element's name property is 'username'--this is the key it will be available under in <code>$form_state['values']</code>,
in your validation and submission functions, as the form code flattens
the array in this fashion before it passes the key/value pairs. NOTE:
if you wish to have the full tree structure passed to <code>$form_state['values']</code>, this is possible, and will be discussed later.</li>
<li>The type of form element is declared as an attribute with the <code>'#type'</code> property.</li>
<li>Properties/attributes keys are declared with surrounding quotes, beginning with a # sign. Values are strings.</li>
<li>The
order of the properties/attributes doesn't matter, and any attributes
that you don't need don't need to be declared. Many
properties/attributes also have a default fallback value if not
explicitly declared.</li>
<li>Don't use the <code>'#value'</code> attribute for any form elements that can be changed by the user. Use the <code>'#default_value'</code> attribute instead. Don't put values from <code>$form_state['values']</code> (or <code>$_POST</code>) here! FormsAPI will deal with that for you; only put the <strong>original</strong> value of the field here.</li>
</ol>
<p>One great advantages of this system is that the explicitly named keys make deciphering the form element much easier.</p>
<p>Let's take a look at a working piece of code using the API:</p>
<div class="codeblock">
<p><code><font color="#000000"> <font color="#0000bb"><?php<br />
</font><font color="#007700">function </font><font color="#0000bb">test_form</font><font color="#007700">($form, &</font><font color="#0000bb">$form_state</font><font color="#007700">) {<br />
</font><font color="#ff8000">// Access log settings:<br />
</font><font color="#0000bb">$options </font><font color="#007700">= array(</font><font color="#dd0000">'1' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Enabled'</font><font color="#007700">), </font><font color="#dd0000">'0' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Disabled'</font><font color="#007700">));<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'access'</font><font color="#007700">] = array(</font><font color="#dd0000"><br />
'#type' </font><font color="#007700">=> </font><font color="#dd0000">'fieldset'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Access log settings'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#tree' </font><font color="#007700">=> </font><font color="#0000bb">TRUE</font><font color="#007700">,<br />
</font></font></code><code><font color="#000000"><font color="#007700">);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'access'</font><font color="#007700">][</font><font color="#dd0000">'log'</font><font color="#007700">] = array(</font><font color="#dd0000"><br />
'#type' </font><font color="#007700">=> </font><font color="#dd0000">'radios'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Log'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#default_value' </font><font color="#007700">=> </font><font color="#0000bb">variable_get</font><font color="#007700">(</font><font color="#dd0000">'log'</font><font color="#007700">, </font><font color="#0000bb">0</font><font color="#007700">), </font><font color="#dd0000"><br />
'#options' </font><font color="#007700">=> </font><font color="#0000bb">$options</font><font color="#007700">, </font><font color="#dd0000"><br />
'#description' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'The log.'</font><font color="#007700">),<br />
);<br />
</font><font color="#0000bb">$period </font><font color="#007700">= </font><font color="#0000bb">drupal_map_assoc</font><font color="#007700">(array(</font><font color="#0000bb">3600</font><font color="#007700">, </font><font color="#0000bb">10800</font><font color="#007700">, </font><font color="#0000bb">21600</font><font color="#007700">, </font><font color="#0000bb">32400</font><font color="#007700">, </font><font color="#0000bb">43200</font><font color="#007700">, </font><font color="#0000bb">86400</font><font color="#007700">, </font><font color="#0000bb">172800</font><font color="#007700">, </font><font color="#0000bb">259200</font><font color="#007700">, </font><font color="#0000bb">604800</font><font color="#007700">, </font><font color="#0000bb">1209600</font><font color="#007700">, </font><font color="#0000bb">2419200</font><font color="#007700">, </font><font color="#0000bb">4838400</font><font color="#007700">, </font><font color="#0000bb">9676800</font><font color="#007700">), </font><font color="#dd0000">'format_interval'</font><font color="#007700">);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'access'</font><font color="#007700">][</font><font color="#dd0000">'timer'</font><font color="#007700">] = array(<br />
</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'select'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Discard logs older than'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#default_value' </font><font color="#007700">=> </font><font color="#0000bb">variable_get</font><font color="#007700">(</font><font color="#dd0000">'timer'</font><font color="#007700">, </font><font color="#0000bb">259200</font><font color="#007700">), </font><font color="#dd0000"><br />
'#options' </font><font color="#007700">=> </font><font color="#0000bb">$period</font><font color="#007700">, </font><font color="#dd0000"><br />
'#description' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'The timer.'</font><font color="#007700">),<br />
);<br />
</font><font color="#ff8000">// Description<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'details'</font><font color="#007700">] = array(<br />
</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'fieldset'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Details'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#collapsible' </font><font color="#007700">=> </font><font color="#0000bb">TRUE</font><font color="#007700">, </font><font color="#dd0000"><br />
'#collapsed' </font><font color="#007700">=> </font><font color="#0000bb">TRUE,<br />
</font><font color="#007700">);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'details'</font><font color="#007700">][</font><font color="#dd0000">'description'</font><font color="#007700">] = array(<br />
</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'textarea'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Describe it'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#default_value' </font><font color="#007700">=> </font><font color="#0000bb">variable_get</font><font color="#007700">(</font><font color="#dd0000">'description'</font><font color="#007700">, </font><font color="#dd0000">''</font><font color="#007700">), </font><font color="#dd0000"><br />
'#cols' </font><font color="#007700">=> </font><font color="#0000bb">60</font><font color="#007700">, </font><font color="#dd0000"><br />
'#rows' </font><font color="#007700">=> </font><font color="#0000bb">5</font><font color="#007700">, </font><font color="#dd0000"><br />
'#description' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Log description.'</font><font color="#007700">),<br />
);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'details'</font><font color="#007700">][</font><font color="#dd0000">'admin'</font><font color="#007700">] = array(</font><font color="#dd0000"><br />
'#type' </font><font color="#007700">=> </font><font color="#dd0000">'checkbox'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Only admin can view'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#default_value' </font><font color="#007700">=> </font><font color="#0000bb">variable_get</font><font color="#007700">(</font><font color="#dd0000">'admin'</font><font color="#007700">, </font><font color="#0000bb">0</font><font color="#007700">),<br />
);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'name'</font><font color="#007700">] = array(</font><font color="#dd0000"><br />
'#type' </font><font color="#007700">=> </font><font color="#dd0000">'textfield'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Name'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#size' </font><font color="#007700">=> </font><font color="#0000bb">30</font><font color="#007700">, </font><font color="#dd0000"><br />
'#maxlength' </font><font color="#007700">=> </font><font color="#0000bb">64</font><font color="#007700">, </font><font color="#dd0000"><br />
'#description' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Enter the name for this group of settings'</font><font color="#007700">),<br />
);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'hidden'</font><font color="#007700">] = array(</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'value'</font><font color="#007700">, </font><font color="#dd0000">'#value' </font><font color="#007700">=> </font><font color="#dd0000">'is_it_here'</font><font color="#007700">);<br />
</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'submit'</font><font color="#007700">] = array(</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'submit'</font><font color="#007700">, </font><font color="#dd0000">'#value' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Save'</font><font color="#007700">));<br />
return </font><font color="#0000bb">$form</font><font color="#007700">;<br />
}<br />
<br />
<font color="#007700">function </font><font color="#0000bb">test_page</font><font color="#007700">() {<br />
return </font><font color="#0000bb">drupal_get_form</font><font color="#007700">(</font><font color="#dd0000">'test_form'</font><font color="#007700">)</font><font color="#007700">;<br />
}<br />
</font><font color="#0000bb">?></font> </font></font></code></p>
</div>
<p><font color="#000000">This example demonstrates how form elements
can be built in a hierarchical fashion by expanding and layering the
form array. There are two functions involved - the function that builds
the form, and another that renders the form using <code>drupal_get_form()</code>. Note that the form builder function always takes <code>$form_state</code>
as its first argument, though for basic usage (as here) it is not used.
Also note that the test_page() function that renders the form is
returning the rendered HTML output, which is what you would need to do
if test_page() is the page callback from a hook_menu() implementation,
for example.</font></p>
<p><font color="#000000">Notice that the first layer is made up of two
form groups, 'access', and 'details', and that inside each of these
groups, one layer down, are some individual form elements. Order of
construction is important here, as the form building code will default
to the constructed order of the <code>$form</code> array when it builds the form (this can be overridden, and will be discussed later in the custom theming section). </font></p>
<p><font color="#000000">For form groups, the <code>'#type'</code> parameter is set to <code>'fieldset'</code>, and notice how the <code>'details'</code> form group is made into a collapsed form group with the addition of a few attributes.</font></p>
<p><font color="#000000">All groups/elements are been built into the master <code>$form</code> array by the builder function.</font></p>
<p><font color="#000000">The <code>drupal_get_form</code> function is the "key" function in the Form API. Note that in its basic usage, it takes just one argument, a string which
is both the form ID and also the name of the function that builds the <code>$form</code>
array. Because the form ID is generally also the name of a function, it
must be a valid PHP variable name. It should start with a letter or
underscore, followed by any number of letters, numbers, or underscores;
spaces and hyphens are not allowed. <code>drupal_get_form</code> can take optional additional arguments, which will be simply passed on to the <code>$form</code> builder function.</font></p>
<code><font color="#000000">drupal_get_form</font></code><font color="#000000"> does the following:
</font><ul>
<font color="#000000"> <li>Starts the entire form-building process by getting the <code>$form</code> from the builder function</li>
<li>Translates the <code>$form['name']</code> items into actual form elements</li>
<li>Performs any validation and "clean-up" that needs to be done, and calls custom validation functions if declared</li>
<li>Submits the form if a submit function is declared, and the form has been submitted</li>
<li>Calls any custom theming functions that have been declared</li>
<li>Returns an HTML string which contains the actual form.</li>
</font></ul>
<p><font color="#000000">For more detailed information, also see the API page for <code>drupal_get_form()</code></font></p>
<p><font color="#000000"><em>An important thing to note:</em> notice that <code>$form['access']</code> has a <code>'#tree' => TRUE</code> attribute. this setting retains the full tree structure for all elements under it when it is passed to <code>$form_state['values']</code>. you must explicitly declare this anywhere you wish to retain an array's full hierarchy when it is passed.</font></p>
<h2><font color="#000000">Theming Forms</font></h2>
<p><font color="#000000">The API makes custom theming of all forms
(including those found in core) possible. This custom theming becomes
possible when all hard coded theming elements have been abstracted, so
that they can be overridden at time of form generation. The abstraction
is accomplished using one of the following methods:</font></p>
<ol>
<font color="#000000"> <li>Adding <code>'#theme'</code> attributes to
the form and/or elements. This allows you to specify which theme
function will be used to render the form or elements, overriding the
default theming function.</li>
<li>Including any markup directly as an element in the $form array:
<ul>
<li>There are <code>'#prefix'</code> and <code>'#suffix'</code> attributes, and these will place the declared markup either before or after the form element in question. for example:
<div class="codeblock"><code><font color="#000000"> <font color="#0000bb"><?php<br />
$form</font><font color="#007700">[</font><font color="#dd0000">'access'</font><font color="#007700">] = array(</font><font color="#dd0000"><br />
'#type' </font><font color="#007700">=> </font><font color="#dd0000">'fieldset'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#title' </font><font color="#007700">=> </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Access log settings'</font><font color="#007700">), </font><font color="#dd0000"><br />
'#prefix' </font><font color="#007700">=> </font><font color="#dd0000">'<div class="foo">'</font><font color="#007700">, </font><font color="#dd0000"><br />
'#suffix' </font><font color="#007700">=> </font><font color="#dd0000">'</div>',<br />
</font><font color="#007700">);<br />
</font><font color="#0000bb">?></font> </font> </code></div>
<p>...will
place the div tags before and after the entire form group (meaning the
form elements of the group will also be enclosed in the div). if you
were to put those attributes in one of the form elements inside that
form group, then they would only wrap that particular element, etc.</p>
</li>
<li>There is a <code>'#markup'</code>
type which you can place anywhere in the form, and its value will be
output directly in its specified location in the forms hierarchy when
the form is rendered. example:<br />
<br />
<div class="codeblock"><code><font color="#000000"> <font color="#0000bb"><?php<br />
$form</font><font color="#007700">[</font><font color="#dd0000">'div_tag'</font><font color="#007700">] = array(</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'markup'</font><font color="#007700">, </font><font color="#dd0000">'#markup' </font><font color="#007700">=> </font><font color="#dd0000">'<div class="foo">'</font><font color="#007700">);<br />
</font><font color="#0000bb">?></font> </font> </code></div>
<p>This markup form element can then be accessed/altered through its name in the array, 'div_tag'</p>
<p><em>NOTE:</em> it's not necessary to explicitly declare the #type at all, since #type will default to 'markup' if none is declared.</p>
</li>
</ul>
</li>
<li>Break
out any markup into a separate theme function. This is the preferred
method if the markup has any degree of complication. it is accomplished
by creating a theme function with <em>theme_</em> prepended to the
name of the form ID that is to be themed. in cases where you want to
use the same theming function for more than one form, you can include
the optional callback arg in <code>drupal_get_form</code>--in which case the third arg of <code>drupal_get_form</code>
will be a string containing the name of the callback function which the
form building code will call, and the theming function will be <em>theme_</em> prepended to the name of the callback.
<p>example:</p>
<p>For our above form, we could create a custom theming function as follows:</p>
<div class="codeblock"><code><font color="#000000"> <font color="#0000bb"><?php<br />
</font><font color="#007700">function </font><font color="#0000bb">theme_test_form</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">) {<br />
</font><font color="#0000bb">$output </font><font color="#007700">= </font><font color="#dd0000">''</font><font color="#007700">;<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#0000bb">drupal_render</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'name'</font><font color="#007700">]);<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#dd0000">'<div class="foo">'</font><font color="#007700">;<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#0000bb">drupal_render</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'access'</font><font color="#007700">]);<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#dd0000">'<div class="bar">'</font><font color="#007700">;<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#0000bb">drupal_render</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">[</font><font color="#dd0000">'details'</font><font color="#007700">]);<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#dd0000">'</div></div>'</font><font color="#007700">;<br />
</font><font color="#0000bb">$output </font><font color="#007700">.= </font><font color="#0000bb">drupal_render</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">);<br />
return </font><font color="#0000bb">$output</font><font color="#007700">;<br />
}<br />
</font><font color="#0000bb">?></font> </font> </code></div>
<p>A few things to note:</p>
<ol>
<li>The theme function has one argument, which is the form array that it will theme</li>
<li>You build and return an output string just as you would do in a regular theming function</li>
<li>Form elements are rendered using the <code>drupal_render</code> function</li>
<li>If you call <code>drupal_render</code>
and pass it an array of elements (as in a fieldset), it will render all
the elements in the passed array, in the order in which they were built
in the form array.</li>
<li>While the default order of rendering
for a form is the order in which it was built, you can override that in
the theme function by calling <code>drupal_render</code> for any element in the place where you would like it to be rendered. In the above example, this was done with <code>$form['name']</code>.</li>
<li>The rendering code keeps track of which elements have been rendered, and will only allow them to be rendered once. Notice that <code>drupal_render</code>
is called for the entire form array at the very end of the theming
function, but it will only render the remaining unrendered element,
which in this case is the submit button. calling <code>drupal_render($form)</code>
is a common way to end a theming function, as it will then render any
submit buttons and/or hidden fields that have been declared in the form
in a single call.</li>
</ol>
</li>
</font></ol>
<h2><font color="#000000">Validating Forms</font></h2>
<p><font color="#000000">The form API has general form validation which
it performs on all submitted forms. If there is additional validation
you wish to perform on a submitted form, you can create a validation
function. the name of the validation function is the form ID with <em>_validate</em> appended to it. the function has two args: <code>$form</code> and <code>$form_state</code>. <code>$form</code> is the form array of the executed form, and <code>$form_state['values']</code>
contains the form values which you may perform validation on. (Note -
in more advanced usage, several forms may share a _validate or _submit
function - so if the form's ID is needed, it can be retrieved from <code>$form['form_id']['#value']</code>, or <code>$form_state['values']['form_id']</code>.)</font></p>
<p><font color="#000000">Here's an example validation function for our example code:</font></p>
<div class="codeblock"><code><font color="#000000"><font color="#000000"> <font color="#0000bb"><?php<br />
</font><font color="#007700">function </font><font color="#0000bb">test_form_validate</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">, </font><font color="#0000bb">&$form_state</font><font color="#007700">) {<br />
if (</font><font color="#0000bb">$form_state['values']</font><font color="#007700">[</font><font color="#dd0000">'name'</font><font color="#007700">] == </font><font color="#dd0000">''</font><font color="#007700">) {<br />
</font><font color="#0000bb">form_set_error</font><font color="#007700">(</font><font color="#dd0000">''</font><font color="#007700">, </font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'You must select a name for this group of settings.'</font><font color="#007700">));<br />
}<br />
}<br />
</font><font color="#0000bb">?></font> </font> </font></code></div>
<h2><font color="#000000">Submitting Forms</font></h2>
<p><font color="#000000">The normal method of submitting forms with the
API is through the use of a form submit function. This has the same
naming convention and arguments as the validation function, except <em>_submit</em> is appended instead. Any forms which are submitted from a button of <code>type => 'submit'</code> will be passed to their corresponding submit function if it is available. </font></p>
<p><font color="#000000">example:</font></p>
<div class="codeblock"><code><font color="#000000"><font color="#000000"> <font color="#0000bb"><?php<br />
</font><font color="#007700">function </font><font color="#0000bb">test_form_submit</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">, </font><font color="#0000bb">&$form_state</font><font color="#007700">) {<br />
</font><font color="#0000bb">db_query</font><font color="#007700">(</font><font color="#dd0000">"INSERT INTO {table} (name, log, hidden) VALUES ('%s', %d, '%s')"</font><font color="#007700">, </font><font color="#0000bb">$form_state['values']</font><font color="#007700">[</font><font color="#dd0000">'name'</font><font color="#007700">], </font><font color="#0000bb">$form_state['values']</font><font color="#007700">[</font><font color="#dd0000">'access'</font><font color="#007700">][</font><font color="#dd0000">'log'</font><font color="#007700">], </font><font color="#0000bb">$form_state['values']</font><font color="#007700">[</font><font color="#dd0000">'hidden'</font><font color="#007700">]);<br />
</font><font color="#0000bb">drupal_set_message</font><font color="#007700">(</font><font color="#0000bb">t</font><font color="#007700">(</font><font color="#dd0000">'Your form has been saved.'</font><font color="#007700">));<br />
}<br /></font><font color="#0000bb">?></font> </font> </font></code></div>
<p><font color="#000000">a few things to note: </font></p>
<ol>
<font color="#000000"> <li>A submit function is called only if a submit button was present and exists in the $_POST, and validation did not fail.
</li>
<li>The <code>$form_state['values']</code> array will not usually have the same hierarchical structure as the constructed <code>$form</code>
array (due to the flattening discussed previously), so be aware of what
arrays have been flattened, and what arrays have retained their
hierarchy by use of the <code>tree => TRUE</code> attribute. notice
above that 'statistics_enable_access_log' belongs to a tree'd array,
and the full array structure must be used to access the value.</li>
<li>If a form has a submit function, then hidden form values are not needed. Instead, any values that you need to pass to <code>$form_state['values']</code> can be declared in the <code>$form</code> array as such:<br />
<br />
<div class="codeblock"><code><font color="#000000"> <font color="#0000bb"><?php<br />
$form</font><font color="#007700">[</font><font color="#dd0000">'foo'</font><font color="#007700">] = array(</font><font color="#dd0000">'#type' </font><font color="#007700">=> </font><font color="#dd0000">'value'</font><font color="#007700">, </font><font color="#dd0000">'#value' </font><font color="#007700">=> </font><font color="#dd0000">'bar'</font><font color="#007700">)<br />
</font><font color="#0000bb">?></font> </font> </code></div>
<p>This is accessed in <code>$form_state['values']['foo']</code>, with a value of <em>bar</em>. This method is preferred because the values are not sent to the browser.</p>
</li>
<li>To determine where the user should be sent after the form is processed, the _submit function can place a path or URL in <code>$form_state['redirect']</code> which will be the target of a drupal_goto; every form is redirected after a submit. If you store nothing in <code>$form_state['redirect']</code>, the form will simply be redirected to itself after a submit. It is polite to use <code><font color="#0000bb">drupal_set_message()</font></code> to explain to the user that the submission was successful.
</li>
</font></ol>
<h2><font color="#000000">Understanding the Flow</font></h2>
<p><font color="#000000">An important concept with Form API compared to using raw HTML forms (as in Drupal 4.6 and before) is that the <code><font color="#0000bb">drupal_get_form()</font></code>
function handles both presenting and responding to the form. What this
means is that the $form array you construct in your function will be
built first when the form is presented, and again when the form is
submitted.</font></p>
<p><font color="#000000">The practical upshot to this is that many developers immediately find themselves asking the question of <em>"where does my data get stored?"</em>.
The answer is simply that it doesn't. You put your $form data together,
perhaps loading your object from the database and filling in
#default_values, the form builder then checks this against what was
posted. What you gain from this, however, is that the FormsAPI can deal
with your data securely. Faking a POST is much harder since it won't
let values that weren't actually on the form come through to the
$form_state['values'] in your submit function, and in your 'select'
types, it will check to ensure that the value actually existed in the
select and reject the form if it was not. In addition, Drupal adds, by
default, a security token to each form that will protect against
cross-site forgery.
</font></p></body></html>