<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii">
<TITLE>Message</TITLE>

<META content="MSHTML 6.00.2900.2963" name=GENERATOR></HEAD>
<BODY>
<DIV><FONT face=Verdana size=2>Greetings, folks! There's been talk for the past 
week or so about the 'pull model' patch for Forms API that chx rolled. It's been 
committed after some furious rounds of polishing, and it removes many barriers 
for advanced use of the Forms API. It DOES, however, require some 
conversion/updates to existing functions that generate and display forms. Here's 
the quick and easy guide to the changes.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>1) What changed and why?<BR>Previously, Forms API 
used a 'push model.' You built an array of form elements, then called 
drupal_get_form($form_id, $form) to 'push' it into the API for processing and 
rendering. This worked OK for many situations, but also made it terribly 
cumbersome for programmatically submitting forms (for import/export). It also 
made workflow-oriented systems that chained multiple forms together a lot more 
hacky and kludgy than necessary.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>Now, the Forms API uses a 'pull model.' You call 
drupal_get_form($form_id), and it 'pulls' the form from a builder function, then 
processes and renders it as appropriate. That means that existing modules need 
to separate their form-building code from their general page and content 
rendering code -- most already do this, but it's an important distinction, and 
making it 'official' allows the system to treat forms more 
consistently.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>2) So, how do I convert my code?<BR>By default, 
Forms API will check for a function that shares the same name as the form's ID. 
For example:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>&lt;?php<BR>function 
mymodule_edit_record($record) {<BR>&nbsp; $output = 'This is my edit 
page!';<BR>&nbsp; $form['my_field'] = array(<BR>&nbsp;&nbsp;&nbsp; '#type' =&gt; 
'textfield',<BR>&nbsp;&nbsp;&nbsp; '#title' =&gt; 'Record 
name',<BR>&nbsp;&nbsp;&nbsp; '#default_value' =&gt; $record-&gt;name,<BR>&nbsp; 
);<BR>&nbsp; $output .= drupal_get_form('record_edit_form', $form);<BR>&nbsp; 
return $output;<BR>}<BR>?&gt;</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>Would need to change to the 
following:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>&lt;?php<BR>function 
mymodule_edit_record($record) {<BR>&nbsp; $output = 'This is my edit 
page!';<BR>&nbsp; $output .= drupal_get_form('mymodule_edit_record_form', 
$record);<BR>&nbsp; return $output;<BR>}</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>function mymodule_edit_record_form($record) 
{<BR>&nbsp; $form['my_field'] = array(<BR>&nbsp;&nbsp;&nbsp; '#type' =&gt; 
'textfield',<BR>&nbsp;&nbsp;&nbsp; '#title' =&gt; 'Record 
name',<BR>&nbsp;&nbsp;&nbsp; '#default_value' =&gt; $record-&gt;name,<BR>&nbsp; 
);<BR>&nbsp; return $form;<BR>}<BR>?&gt;</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>Once that 'builder' function is defined, you can 
call drupal_get_form('mymodule_edit_record_form', $record) anywhere in your 
code, and the API will handle retrieving it. In fact, if your form page was 
simple and just consisted of building a form, then returning the results of 
drupal_get_form(), you can now use the following trick when you define the menus 
for your module:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>&lt;?php<BR>function mymodule_menu($may_cache = 
TRUE) {<BR>&nbsp; $items[] = array(<BR>&nbsp;&nbsp;&nbsp; 'path' =&gt; 
'mymodule/form-page',<BR>&nbsp;&nbsp;&nbsp; 'title' =&gt; t('edit a 
record'),<BR>&nbsp;&nbsp;&nbsp; 'callback' =&gt; 
'drupal_get_form',<BR>&nbsp;&nbsp;&nbsp; 'callback arguments' =&gt; 
array('mymodule_form_builder')<BR>&nbsp;&nbsp;&nbsp; 'type' =&gt; 
MENU_LOCAL_TASK<BR>&nbsp; );<BR>&nbsp; return $items;<BR>?&gt;</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>In the above example, instead of putting a custom 
page-generation function in as your callback, and adding a single 
drupal_get_form($form_id) call as its body, you can just tell the menu system to 
call drupal_get_form() with your form ID.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>3) What if I have several forms that use 
different IDs, but share the same layout, submit and validate functions, and so 
on?<BR>We're glad you asked. Modules can now implement hook_forms() to handle 
complex mapping of form IDs to builder functions. It's how node.module maps the 
id for each node type editing form to the central form-building function for the 
node edit screen. Here's an example:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>&lt;?php<BR>function mymodule_hook_forms() 
{<BR>&nbsp; $forms['mymodule_first_form'] = array(<BR>&nbsp;&nbsp;&nbsp; 
'callback' =&gt; 'mymodule_form_builder',<BR>&nbsp;&nbsp;&nbsp; 'callback 
arguments' =&gt; array('some parameter'),<BR>&nbsp; );<BR>&nbsp; 
$forms['mymodule_second_form'] = array(<BR>&nbsp;&nbsp;&nbsp; 'callback' =&gt; 
'mymodule_form_builder',<BR>&nbsp;&nbsp;&nbsp; 'callback arguments' =&gt; 
array('a different parameter'),<BR>&nbsp; );<BR>&nbsp; return 
$forms;<BR>}</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>function mymodule_first_page() {<BR>&nbsp; return 
drupal_get_form('mymodule_first_form');<BR>}</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>function mymodule_second_page() {<BR>&nbsp; 
return drupal_get_form('mymodule_second_form');<BR>}</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>function mymodule_form_builder($param) 
{<BR>&nbsp; $form = array()<BR>&nbsp; // build the form here</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>&nbsp; if ($param == 'some parameter') 
{<BR>&nbsp;&nbsp;&nbsp; // Add another field, change a default 
value...<BR>&nbsp; }<BR>&nbsp; <BR>&nbsp; // This is used the way $callback was 
in 4.7 Forms API: it is used as the prefix for<BR>&nbsp; // _submit() and 
_validate() functions to process the form.<BR>&nbsp; $form['#base'] = 
'mymodule_form';<BR>&nbsp; <BR>&nbsp; return $form;<BR>}<BR>?&gt;</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>In the above code, the mymodule_first_page() and 
mymodule_second_page() functions display slight variations on the same form. 
Because no functions named 'mymodule_first_form' or 'mymodule_second_form' 
exist, Forms API looks to hook_forms() to find the builder function. Each entry 
in the array returned by hook_forms() can also define callback arguments that 
will be passed to the builder function.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>In the mymodule_form_builder() function, the use 
of $form['#base'] is also important to note. It's a lot like the little-used but 
helpful $callback parameter that was used in the 4.7 version of 
drupal_get_form(). If $form['#base'] is set, its value will be used to look up 
the proper submit, validate, and theme functions for the form rather than the 
form's ID.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>In the future, hook_forms() will also allow us to 
capture other meta data about forms like access restrictions, workflow 
information, and so on. For now, though, the callback and optional callback 
arguments are all you need to worry about if you use it.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>4) OK, that's great. How do I programmatically 
submit form data, then?<BR>Aha, the meat of it. Now, it's possible to completely 
circumvent drupal_get_form() and all of its submission, rendering, and 
redirection logic. You just pull up a form using its ID, and populate the new 
$form['#post']['edit'] element with the form values you'd like to submit. Then 
call drupal_process_form(). For example:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>&lt;?php<BR>function mymodule_create_user() 
{<BR>&nbsp; // register a new user<BR>&nbsp; $form = 
drupal_retrieve_form('user_register');<BR>&nbsp; $form['#post']['edit']['name'] 
= 'robo-user';<BR>&nbsp; $form['#post']['edit']['mail'] = <A 
href="mailto:'robouser@example.com'">'robouser@example.com'</A>;<BR>&nbsp; 
$form['#post']['edit']['pass'] = 'password';<BR>&nbsp; 
drupal_process_form('user_register', $form);<BR>&nbsp; <BR>&nbsp; if 
(form_get_errors()) {<BR>&nbsp;&nbsp;&nbsp; // whoops, something went 
wrong!<BR>&nbsp; }<BR>}<BR>?&gt;</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>And that, dear friends, is about it. To 
recap:</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>1) drupal_get_form() now takes a $form_id, NOT a 
$form_id and a $form.<BR>2) You need a builder function with the name of the 
$form_id that returns the fully constructed $form array<BR>3) If your page 
content is JUST a form, you can use drupal_get_form as your menu callback, with 
$form_id as your menu callback argument.<BR>4) If you need to use the same $form 
for multiple $form_ids, use hook_forms()<BR>5) If you want the submit, validate, 
and theme functions to use naming different than the $form_id, set 
$form['#base']<BR>6) Use drupal_retrieve_form(), $form['#post']['edit'], and 
drupal_process_form() to programmatically submit forms.</FONT></DIV>
<DIV>&nbsp;</DIV>
<DIV><FONT face=Verdana size=2>Have fun!</FONT></DIV></BODY></HTML>