Lightning   (It's gonna be fast paced) FAPI   (Expect lots of code) Jumpstart   (Feel the power!) Doug Stumberger drupal.o...
It's a Drupal talk, so… * * No cats were harmed in the creation of these slides.
Don't recognize this? Uh-oh.
Something simple to begin with <ul><li>function  newsletter_subscribe_form ( $form_state ) { </li></ul><ul><li>$form = arr...
Validate & submit <ul><li>Validate </li></ul><ul><ul><li>Default handler: FORMID_validate ($form, &$form_state) </li></ul>...
Passing data to validate & submit <ul><li>Pass values from form definition to validate and submit handlers </li></ul><ul><...
Fieldsets and trees (and access!) <ul><li>Collapsible groupings of form fields </li></ul><ul><ul><li>$form['options'] = ar...
Tabular forms <ul><li>Widely used for admin forms </li></ul><ul><li>function request_form($form_state){ </li></ul><ul><li>...
Tabular forms: theme <ul><li>Use form theming to convert into table markup </li></ul><ul><li>function theme_request_form($...
Custom elements <ul><li>Define a custom element with fields to be merged </li></ul><ul><li>function  fcklite_elements () {...
A custom fckeditor element
Invocation: drupal_get_form <ul><li>Primary means of invoking Drupal forms programmatically </li></ul><ul><li>Manages buil...
drupal_get_form: default values <ul><li>Use your hook_menu wildcards and loaders! </li></ul><ul><ul><li>function  newslett...
Add/edit forms for node types <ul><li>Use hooks to change default behavior for two URLs </li></ul><ul><ul><li>Create URL: ...
Form factories using hook_forms <ul><li>Multiple modules can use the same form function </li></ul><ul><li>Each invocation ...
Modifying forms: hook_form_alter <ul><li>function newsletter_form_alter( &$form , $form_state, $form_id) { </li></ul><ul><...
Theming forms & elements <ul><li>Goal: match the look of a form to its design or layout context </li></ul><ul><li>Leave ma...
#theme…the hammer, er, scalpel <ul><li>Specify theme function on whole form or individual element </li></ul><ul><ul><li>$f...
 
Here, a standard imagefield form becomes both more functional and more consistent in presentation with the rest of the sit...
Multi-step forms <ul><li>Multi-page surveys, wizards, notifications, etc. </li></ul><ul><li>First, conditionalize UI eleme...
Cycle data into next step: form_state <ul><li>Pass data from one step to the next </li></ul><ul><ul><li>Finally, a purpose...
Drupal 7 Changes <ul><li>drupal_get_form returns structured array, not HTML </li></ul><ul><li>Specify text format in texta...
D7: drupal_get_form (#353069) <ul><li>drupal_get_form returns form definition array,  NOT HTML </li></ul><ul><ul><ul><li>D...
D7: Specify text format (#125315) <ul><li>Specify text format for either textfield or textarea elements </li></ul><ul><li>...
D7: Attach CSS & JS (#323112) <ul><li>Attached CSS and Javascript directly in form definition </li></ul><ul><li>function m...
Resources <ul><li>API Reference </li></ul><ul><ul><li>http://api.drupal.org/api/drupal/developer--topics--forms_api_refere...
Appendix
AHAH <ul><li>“ Asynchronous HTML and HTTP” : Javascript-based dynamic behavior similar to AJAX </li></ul><ul><li>“…  the r...
drupal_execute <ul><li>// See user.module, line 2387. </li></ul><ul><li>function  user_register () { </li></ul><ul><li>......
http://drupal.org/node/165104
Upcoming SlideShare
Loading in …5
×

Drupal Lightning FAPI Jumpstart

6,509 views
6,352 views

Published on

Session presented 10/24 at Pacific Northwest Drupal Summit discussing Drupal form API

Published in: Technology, Business
1 Comment
4 Likes
Statistics
Notes
No Downloads
Views
Total views
6,509
On SlideShare
0
From Embeds
0
Number of Embeds
22
Actions
Shares
0
Downloads
97
Comments
1
Likes
4
Embeds 0
No embeds

No notes for slide
  • If this doesn&apos;t look familiar to you, then you&apos;re in for a rough hour. Use t() for titles, descriptions, and values Weight specifies relative vertical location of element on the form canvas D6; use “Save” instead of “Submit” (#287986) Don&apos;t forget to return your form!
  • drupal_get_form Primary way of invoking forms Manages all phases of form lifecycle Returns rendered html Can be parameterized to pass default values D7: returns form array, not HTML drupal_execute Programmatic counterpart to drupal_get_form Pass in form_id and $form_state[&apos;values&apos;] Returns validation errors D7: becomes drupal_form_submit
  • Easiest way to alter a form Can alter your own or core/contrib forms Called on every form invocation Called after form creation but before rendering Also hook_form_FORM_ID_alter() for specific Remains in Drupal 7 Also exp
  • Goal: match a form&apos;s appearance to its context
  • Drupal Lightning FAPI Jumpstart

    1. 1. Lightning (It's gonna be fast paced) FAPI (Expect lots of code) Jumpstart (Feel the power!) Doug Stumberger drupal.org = twitter = facebook = ‘dougstum’ DND Communications www.raceonedesign.com dstumberger @ hotmail.com
    2. 2. It's a Drupal talk, so… * * No cats were harmed in the creation of these slides.
    3. 3. Don't recognize this? Uh-oh.
    4. 4. Something simple to begin with <ul><li>function newsletter_subscribe_form ( $form_state ) { </li></ul><ul><li>$form = array(); </li></ul><ul><li>$form['email'] = array( </li></ul><ul><li>'#type' => 'textfield', </li></ul><ul><li>'#title' => t('E-mail address') , // use t() for localization </li></ul><ul><li>'#size' => 64, </li></ul><ul><li>'#maxlength' => 64, </li></ul><ul><li>'#required' => TRUE, </li></ul><ul><li>'#weight' => -10, </li></ul><ul><li>); </li></ul><ul><li>$form['subscribe'] = array( </li></ul><ul><li>'#type' => 'radios', </li></ul><ul><li>'#title' => t('Subscribe'), </li></ul><ul><li>'#default_value' => 0 , </li></ul><ul><li>'#options' => array(t('Yes'), t('No')) , </li></ul><ul><li>'#weight' => 5, </li></ul><ul><li>); </li></ul><ul><li>$form['submit'] = array( </li></ul><ul><li>'#type' => 'submit', </li></ul><ul><li>'#value' => t(' Save '), // D6; use “Save” instead of “Submit” (#287986) </li></ul><ul><li>'#weight' => 20, </li></ul><ul><li>); </li></ul><ul><li>return $form; </li></ul><ul><li>} </li></ul>
    5. 5. Validate & submit <ul><li>Validate </li></ul><ul><ul><li>Default handler: FORMID_validate ($form, &$form_state) </li></ul></ul><ul><ul><li>Modify $form['#validate'] array in form definition or hook_form_alter </li></ul></ul><ul><ul><li>Use form_set_error to signal validation errors associated with the form </li></ul></ul><ul><ul><li>Also useful: form_get_error($element) and form_get_errors() </li></ul></ul><ul><ul><li>Required fields are handled automatically, no need to check in validate handler </li></ul></ul><ul><li>Submit </li></ul><ul><ul><li>Default: FORMID_submit ($form, &$form_state) </li></ul></ul><ul><ul><li>Modify $form['#submit'] array in form definition or hook_form_alter </li></ul></ul><ul><ul><li>Particularly useful for redirecting the user (default is to return to form) </li></ul></ul><ul><ul><li>drupal_goto ($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) </li></ul></ul><ul><ul><li>// Block redirection (returns to form) </li></ul></ul><ul><ul><li>$form_state['redirect'] = FALSE ; </li></ul></ul><ul><ul><li>// Redirect to site homepage </li></ul></ul><ul><ul><li>$form_state['redirect'] = '<front>' ; </li></ul></ul><ul><ul><li>// Redirect to relative path from base_path </li></ul></ul><ul><ul><li>$form_state['redirect'] = 'node/' . $node->nid ; </li></ul></ul><ul><ul><li>// Specify arguments to drupal_goto() </li></ul></ul><ul><ul><li>$form_state['redirect'] = array($node->path, drupal_get_destination()) ; </li></ul></ul>
    6. 6. Passing data to validate & submit <ul><li>Pass values from form definition to validate and submit handlers </li></ul><ul><ul><li>$form['node'] = array( </li></ul></ul><ul><ul><li>'#type' => 'value' , </li></ul></ul><ul><ul><li>'#value' => $node , </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><li>Once form is submitted, retrieve data from $form_state['values'] </li></ul><ul><ul><li>function subscribe_form_validate($form, & $form_state) { </li></ul></ul><ul><ul><li>$node = $form_state['values']['node'] ; </li></ul></ul><ul><ul><li>}; </li></ul></ul><ul><li>Pass values (or modify passed values) from validate to submit handler </li></ul><ul><ul><li>function subscribe_form_validate($form, & $form_state) { </li></ul></ul><ul><ul><li>$form_state['values']['node'] ->title = t('Hello World'); </li></ul></ul><ul><ul><li>}; </li></ul></ul><ul><ul><li>-- OR –- </li></ul></ul><ul><ul><li>function subscribe_form_validate($form, & $form_state) { </li></ul></ul><ul><ul><li>$node = $form_state['values']['node']; </li></ul></ul><ul><ul><li>$node->title = t('Hello World'); </li></ul></ul><ul><ul><li>form_set_value ($form['node'], $node, $form_state); </li></ul></ul><ul><ul><li>}; </li></ul></ul><ul><li>Once form is submitted, retrieve data from $form_state['values'] </li></ul><ul><li>$node = $form_state['values']['node'] ; </li></ul>
    7. 7. Fieldsets and trees (and access!) <ul><li>Collapsible groupings of form fields </li></ul><ul><ul><li>$form['options'] = array( </li></ul></ul><ul><ul><li>'#type' => ' fieldset ', </li></ul></ul><ul><ul><li>' #access ' => user_access('administer nodes') , </li></ul></ul><ul><ul><li>'#title' => t('Publishing options'), </li></ul></ul><ul><ul><li>' #collapsible ' => TRUE, // Default is False. </li></ul></ul><ul><ul><li>' #collapsed ' => TRUE, // Default is FALSE. </li></ul></ul><ul><ul><li>'#tree' => FALSE, </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>$form['options']['status'] = array( </li></ul></ul><ul><ul><li>'#type' => 'checkbox', </li></ul></ul><ul><ul><li>'#title' => t('Published'), </li></ul></ul><ul><ul><li>'#default_value' => $node->status, </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><li>Default: values are “collapsed” when #tree = FALSE </li></ul><ul><ul><li>function mymodule_form_submit($form, &$form_state) { </li></ul></ul><ul><ul><li>$status = $form_state['values']['status'] ; </li></ul></ul><ul><ul><li>}; </li></ul></ul><ul><li>But when '#tree' = TRUE, you must specify complete path to value </li></ul><ul><ul><li>$status = $form_state['values']['options']['status'] ; </li></ul></ul>
    8. 8. Tabular forms <ul><li>Widely used for admin forms </li></ul><ul><li>function request_form($form_state){ </li></ul><ul><li>$form = array(); </li></ul><ul><li>foreach ($requests as $request_id => $request) { </li></ul><ul><li>$form['request'][$request_id]['#tree'] = TRUE; </li></ul><ul><li>$form['request'][$request_id]['delete'] = array( </li></ul><ul><li>'#type' => 'checkbox', </li></ul><ul><li>'#default_value' => 0, </li></ul><ul><li>); </li></ul><ul><li>$form['request'][$request_id]['user'] = array( </li></ul><ul><li>'#value' => theme('username', user_load(array('uid' => $request->uid))), </li></ul><ul><li>); </li></ul><ul><li>$form['request'][$request_id]['time'] = array( </li></ul><ul><li>'#value' => date('j M H:I', $request->timestamp), </li></ul><ul><li>); </li></ul><ul><li>$form['request'][$request_id]['operations'] = array( </li></ul><ul><li>'#value' => l('Add article', 'newsletter/add_article', 'id=' . $request_id) </li></ul><ul><li>); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    9. 9. Tabular forms: theme <ul><li>Use form theming to convert into table markup </li></ul><ul><li>function theme_request_form($form) { </li></ul><ul><li>$headers = array( </li></ul><ul><li>'', </li></ul><ul><li>t('User'), </li></ul><ul><li>t('Time'), </li></ul><ul><li>t('Operations') </li></ul><ul><li>); </li></ul><ul><li>$rows = array(); </li></ul><ul><li>foreach ($form['add'] as $request_id => $request) { </li></ul><ul><li>$rows[] = array( </li></ul><ul><li>drupal_render ($form['request'][$request_id]['delete']), </li></ul><ul><li>drupal_render($form['request'][$request_id]['user']), </li></ul><ul><li>drupal_render($form['request'][$request_id]['time']), </li></ul><ul><li>drupal_render($form['request'][$request_id]['operations']), </li></ul><ul><li>); </li></ul><ul><li>} </li></ul><ul><li>return '<h3>' . t('Requests') . '</h3>' </li></ul><ul><li>. theme('table', $headers, $addrows) </li></ul><ul><li> . drupal_render($form); </li></ul><ul><li>} </li></ul><ul><li>Remember, FAPI will automatically look for theme_FORMID </li></ul>
    10. 10. Custom elements <ul><li>Define a custom element with fields to be merged </li></ul><ul><li>function fcklite_elements () { </li></ul><ul><li>return array('fcklite_textarea' => array( </li></ul><ul><li>' #input ' => TRUE, </li></ul><ul><li>'#prefix' => &quot;<div class='fcklite_textarea'>&quot;, </li></ul><ul><li>'#suffix' => '</div>', </li></ul><ul><li>' #rows ' => 20, </li></ul><ul><li>)); </li></ul><ul><li>} </li></ul><ul><li>Theme your element (remember to add to hook_theme) </li></ul><ul><li>function theme_fcklite_textarea ($element) { </li></ul><ul><li>return theme('form_element' , array( </li></ul><ul><li>'#title' => $element['#title'], </li></ul><ul><li>'#description' => $element['#description'], </li></ul><ul><li>'#id' => $element['#id'], </li></ul><ul><li>), </li></ul><ul><li>FCKeditor_IsCompatibleBrowser() </li></ul><ul><li>? fcklite_open_textarea($element['#id'], $val, $element['#rows']) </li></ul><ul><li>: t('Incompatible browser') </li></ul><ul><li>); </li></ul><ul><li>} </li></ul><ul><li>D7: hook_elements -> hook_element_info and hook_element_info_alter (#572932) </li></ul>
    11. 11. A custom fckeditor element
    12. 12. Invocation: drupal_get_form <ul><li>Primary means of invoking Drupal forms programmatically </li></ul><ul><li>Manages building, theming, presentation, execution </li></ul><ul><li>Returns HTML (at least in Drupal 6!) </li></ul><ul><ul><li>$html = drupal_get_form('newsletter_subscribe_form'); </li></ul></ul><ul><ul><li>drupal_set_content(‘column_1’, $html); </li></ul></ul><ul><li>Frequently used as a page callback for hook_menu items </li></ul><ul><ul><li>function newsletter_menu () { </li></ul></ul><ul><ul><li>$items['newsletter/subscribe'] = array( </li></ul></ul><ul><ul><li>'page callback' => 'drupal_get_form', </li></ul></ul><ul><ul><li>'page arguments' => array(' newsletter_subscribe_form '), </li></ul></ul><ul><ul><li>'access arguments' => array('manage subscriptions'), </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>return $items; </li></ul></ul><ul><ul><li>} </li></ul></ul>
    13. 13. drupal_get_form: default values <ul><li>Use your hook_menu wildcards and loaders! </li></ul><ul><ul><li>function newsletter_menu () { </li></ul></ul><ul><ul><li>// Note: %user wildcard loader = user_load </li></ul></ul><ul><ul><li>$items[' newsletter/subscribe/%user '] = array( </li></ul></ul><ul><ul><li>'page callback' => 'drupal_get_form ', </li></ul></ul><ul><ul><li>'page arguments' => array('subscribe_form', 2) , </li></ul></ul><ul><ul><li>'access arguments' => array('manage subscriptions'), </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>return $items; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>Remember to use $form_state as first parameter (almost always!) </li></ul><ul><ul><li>function newsletter_form($form_state, $objUser ) { </li></ul></ul><ul><ul><li>$form = array( </li></ul></ul><ul><ul><li>'email' => array( </li></ul></ul><ul><ul><li>'#type' => 'textfield', </li></ul></ul><ul><ul><li>'#title' => t('Email address'), </li></ul></ul><ul><ul><li>'#default_value' => $objUser->mail , </li></ul></ul><ul><ul><li>)); </li></ul></ul><ul><ul><li>}; </li></ul></ul>
    14. 14. Add/edit forms for node types <ul><li>Use hooks to change default behavior for two URLs </li></ul><ul><ul><li>Create URL: www.example.com/node/add/TYPE </li></ul></ul><ul><ul><li>Edit URL: www.example.com/node/%node/edit </li></ul></ul><ul><li>Replace standard node create/edit forms </li></ul><ul><ul><li>Define function TYPE_node_form($form_state, $node) </li></ul></ul><ul><ul><li>Use node_form_validate & node_form_submit </li></ul></ul><ul><ul><li>OR customize by specifying $form['#submit][] or $form['#validate'][] </li></ul></ul><ul><ul><li>To theme, either use default: theme_node_form </li></ul></ul><ul><ul><li>OR implement theme_TYPE_node_form (don't forget to add to hook_theme) </li></ul></ul><ul><li>Or add custom fields to standard node create/edit forms </li></ul><ul><ul><li>Only works with node types defined by a module (not through admin) </li></ul></ul><ul><ul><li>Implement hook_form ($node, $form_state) // NOTE REVERSED ARGUMENTS </li></ul></ul><ul><ul><li>Uses node_form_validate & node_form_submit </li></ul></ul><ul><ul><li>Themed using theme_TYPE_node_form or theme_node_form </li></ul></ul>
    15. 15. Form factories using hook_forms <ul><li>Multiple modules can use the same form function </li></ul><ul><li>Each invocation can use a different form_id </li></ul><ul><li>Modules can alter submission, validation etc. </li></ul><ul><li>function node_forms() { </li></ul><ul><li>$forms = array(); </li></ul><ul><li>if ($types = node_get_types ()) { </li></ul><ul><li>foreach (array_keys($types) as $type) { </li></ul><ul><li>$forms[$type .'_node_form']['callback'] = 'node_form'; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>return $forms; </li></ul><ul><li>} </li></ul><ul><li>Calls to TYPE_node_form will result in calls to function node_form(...) with form_id = TYPE_form </li></ul>
    16. 16. Modifying forms: hook_form_alter <ul><li>function newsletter_form_alter( &$form , $form_state, $form_id) { </li></ul><ul><li>// Switch statement is also commonly used. </li></ul><ul><li>if ($form_id == 'newsletter_subscribe_form') { </li></ul><ul><li>// Add elements to the form. </li></ul><ul><li>$form['name'] = array( </li></ul><ul><li>'#type' => 'textfield', </li></ul><ul><li>'#title' => t('Name') , </li></ul><ul><li>); </li></ul><ul><li>// Remove elements from the form. </li></ul><ul><li>unset($form['phone_number']); </li></ul><ul><li>// Add a new submit handler (or replace altogether). </li></ul><ul><li>$form['#submit'][] = 'mymodule_submit_handler'; </li></ul><ul><li>// Replace existing validation with your code (or add validation). </li></ul><ul><li>$form['#validate'] = array('mymodule_validate_handler'); </li></ul><ul><li>// Move form items around using weights. </li></ul><ul><li>$form['email']['#weight'] = -3; </li></ul><ul><li>// Fix tabindex problems, add prefix/suffix, etc. </li></ul><ul><li>$form['submit']['#attributes']['tabindex'] = '3'; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>See for example login_toboggan.module </li></ul><ul><li>Also explore: #after_build, #pre_render, #post_render </li></ul>
    17. 17. Theming forms & elements <ul><li>Goal: match the look of a form to its design or layout context </li></ul><ul><li>Leave markup the same but modify the CSS ( Use FIREBUG!!! ) </li></ul><ul><li>Use #prefix and #suffix fields on a form or on an individual element. Especially useful when set using hook_form_alter. </li></ul><ul><ul><li>$form['access'] = array(   '#type' => 'textfield',   '#title' => t('Log'),   ' #prefix ' => '<div class=&quot;inline_title&quot;>',    '#suffix ' => '</div>', ); </li></ul></ul><ul><li>Override the default individual element theme functions </li></ul><ul><ul><li>function MY_THEME_NAME_radio($element) { ... } </li></ul></ul><ul><ul><li>A default theme function exists for every visible element type </li></ul></ul><ul><ul><li>But, this overrides the theming for every element of that type on every form </li></ul></ul><ul><ul><li>Can also override theme_form and theme_form_element ! </li></ul></ul>
    18. 18. #theme…the hammer, er, scalpel <ul><li>Specify theme function on whole form or individual element </li></ul><ul><ul><li>$form = array( </li></ul></ul><ul><ul><li>   ' #theme ' => 'table_based_form', </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><li>Make sure the theme function is defined in hook_theme </li></ul><ul><li>Remember, you can add '#theme' during hook_form_alter </li></ul><ul><li>The usual algorithm for theming forms: </li></ul><ul><ul><li>Loop through all elements in a form </li></ul></ul><ul><ul><ul><li>Output the element's surrounding markup, description, etc. </li></ul></ul></ul><ul><ul><ul><li>Render the element with drupal_render($form[$element_id]) </li></ul></ul></ul><ul><ul><li>Render the remainder of the form with drupal_render($form) </li></ul></ul><ul><li>You can pass parameters into the theming using custom form elements and custom '#' fields on individual elements </li></ul>$form['fb_fields'] = array( '#type' => 'value', '#value' => array('title', 'body'), ); $form['sender_email'] = array( '#type' => 'item', '#fb_divider' => TRUE, );
    19. 20. Here, a standard imagefield form becomes both more functional and more consistent in presentation with the rest of the site. Combining form_alter and theming gives you the power to dramatically modify contrib module forms, icluding CCK-based forms. (after_build helps!)
    20. 21. Multi-step forms <ul><li>Multi-page surveys, wizards, notifications, etc. </li></ul><ul><li>First, conditionalize UI elements, especially for form navigation </li></ul><ul><li>f unction newsletter_subscribe_form($form_state) { </li></ul><ul><li>$form = array(); </li></ul><ul><li>// Second time through the form builder. </li></ul><ul><li>if (isset($form_state['storage']['confirm'])) { </li></ul><ul><li>$form['confirm_message'] = array( </li></ul><ul><li>'#type' => 'item' , </li></ul><ul><li>'#value' => t('Email address !email is subscribed.', </li></ul><ul><li>array('!email' => $form_state['storage']['email'])), </li></ul><ul><li>); </li></ul><ul><li>} </li></ul><ul><li>// First time through the form builder. </li></ul><ul><li>else { </li></ul><ul><li>$form['email'] = array( </li></ul><ul><li>'#type' => 'textfield', </li></ul><ul><li>'#title' => t('E-mail address'), </li></ul><ul><li>); </li></ul><ul><li>$form['submit'] = array( </li></ul><ul><li>'#type' => 'submit', </li></ul><ul><li>'#value' => t('Save'), </li></ul><ul><li>); </li></ul><ul><li>} </li></ul><ul><li>return $form; </li></ul><ul><li>} </li></ul>
    21. 22. Cycle data into next step: form_state <ul><li>Pass data from one step to the next </li></ul><ul><ul><li>Finally, a purpose for $form_state in form definition signature! </li></ul></ul><ul><ul><li>Use $form_state['storage'] in submit handler for signals, data </li></ul></ul><ul><li>function newsletter_subscribe_form_submit($form_state) { </li></ul><ul><li>// signal that the next form building shows confirmation message. </li></ul><ul><li>$form_state['storage']['confirm'] = 1; </li></ul><ul><li>// Pass the email address (assume validated) back to form build. </li></ul><ul><li>$form_state['storage']['email'] = $form_state['values']['email']; </li></ul><ul><li>// trigger a form rebuild. </li></ul><ul><li>$form_state['rebuild'] = TRUE; </li></ul><ul><li>} </li></ul><ul><li>Signal rebuild of form or redirect in submit handler </li></ul><ul><ul><li>$form_state['rebuild'] = TRUE; </li></ul></ul><ul><ul><li>Optional redirect on final step </li></ul></ul>
    22. 23. Drupal 7 Changes <ul><li>drupal_get_form returns structured array, not HTML </li></ul><ul><li>Specify text format in textarea and textfield elements </li></ul><ul><li>Attach CSS & JS to forms </li></ul><ul><li>Javascript element dependency (#557272) </li></ul><ul><ul><li>$form['element']['#dependencies'] => array(   'enabled' => array(     '#edit-menu-has-menu' => array('checked' => TRUE)   ) ), </li></ul></ul><ul><li>Use '#markup' not '#value' for elements markup & item (#252013) </li></ul><ul><li>drupal_execute => drupal_form_submit (#408024) </li></ul><ul><li>Easier to check for node form in hook_form_alter (#161301) </li></ul><ul><li>Changes to element definitions re: theming (#355236) </li></ul><ul><li>hook_elements -> hook_element_info (#572932) + hook_element_info_alter </li></ul>
    23. 24. D7: drupal_get_form (#353069) <ul><li>drupal_get_form returns form definition array, NOT HTML </li></ul><ul><ul><ul><li>D6: $html = drupal_get_form('mymodule_form'); </li></ul></ul></ul><ul><ul><ul><li>D7: $arrayForm = drupal_get_form('mymodule_form'); </li></ul></ul></ul><ul><li>Array structure should be passed back to menu handler </li></ul><ul><ul><li>All menu handlers should return arrays, not HTML </li></ul></ul><ul><ul><li>Arrays are passed through new page building stack </li></ul></ul><ul><ul><li>See hook_page_build for rendering </li></ul></ul><ul><li>Do not do this! </li></ul><ul><ul><li>$html = drupal_render(drupal_get_form('mymodule_form')); </li></ul></ul><ul><li>Can now modify form structure in hook_page_alter but use hook_form_alter just as you do in D6 </li></ul>
    24. 25. D7: Specify text format (#125315) <ul><li>Specify text format for either textfield or textarea elements </li></ul><ul><li>$form['comment'] = array( </li></ul><ul><li>'#type' => 'textarea', </li></ul><ul><li>'#title' => t('Comment'), </li></ul><ul><li>// Value from {filter_format}.format or filter_fallback_format() etc. </li></ul><ul><li>' #text_format ' => filter_default_format() , </li></ul><ul><li>); </li></ul><ul><li>Form structure is split into value and format sub-arrays </li></ul><ul><li>// Stores the actual textarea element in subarray </li></ul><ul><li>$form['comment'][' value '] </li></ul><ul><li>// Create format picker using filter_form(...) with default </li></ul><ul><li>$form['comment'][' format '] </li></ul><ul><li>Submit handler retains split between value and format </li></ul><ul><li>// Unaltered form element value </li></ul><ul><li>$comment_body = $form_state['values'][' comment ']; </li></ul><ul><li>// Text format (original value specified in #text_format field) </li></ul><ul><li>$comment_format = $form_state['values'][' comment_format '] </li></ul>
    25. 26. D7: Attach CSS & JS (#323112) <ul><li>Attached CSS and Javascript directly in form definition </li></ul><ul><li>function mymodule_form() { </li></ul><ul><li>$form = array(); </li></ul><ul><li>// Attach a css file. </li></ul><ul><li>$form['#attached']['css'] = array( </li></ul><ul><li>drupal_get_path('module', mymodule') . '/mymodule.css' </li></ul><ul><li>); </li></ul><ul><li>// Attach Javascript 'file', 'inline', 'external' or 'setting' </li></ul><ul><li>$form['#attached']['js'] = array( </li></ul><ul><li>// Inline Javascript. </li></ul><ul><li>'alert(&quot;Hello World.&quot;);' => array('type' => 'inline'), </li></ul><ul><li>); </li></ul><ul><li>return $form; </li></ul><ul><li>} </li></ul>
    26. 27. Resources <ul><li>API Reference </li></ul><ul><ul><li>http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/6 </li></ul></ul><ul><li>Quick start guide </li></ul><ul><ul><li>http://api.drupal.org/api/drupal/developer--topics--forms_api.html/6 </li></ul></ul><ul><li>Tree and parents </li></ul><ul><ul><li>Tree and parents: http://drupal.org/node/48643 </li></ul></ul><ul><li>Upgrading modules to D7 </li></ul><ul><ul><li>Upgrading to D7: http://drupal.org/update/modules/6/7 </li></ul></ul><ul><li>Maybe useful contributed modules </li></ul><ul><ul><li>form_builder: Nate Haug's GUI-based form layout tool </li></ul></ul><ul><ul><li>Webform: one-off forms such as surveys created as nodes </li></ul></ul><ul><ul><li>Multistep: add multistep forms to CCK </li></ul></ul><ul><ul><li>Formblock: forms in blocks </li></ul></ul><ul><ul><li>Formfilter: form editing/filter including formfilter_filter_form API </li></ul></ul><ul><ul><li>MerlinofChaos ctools: multistep, AJAX (rumor moving into D7 core?) </li></ul></ul><ul><ul><li>skip_validation (may provide solution for Cancel problem) </li></ul></ul><ul><ul><li>Fieldset_helper: Saves the collapsed state of a collapsible fieldset </li></ul></ul>
    27. 28. Appendix
    28. 29. AHAH <ul><li>“ Asynchronous HTML and HTTP” : Javascript-based dynamic behavior similar to AJAX </li></ul><ul><li>“… the response from the request is used directly without parsing on the clientside” </li></ul><ul><li>See poll & upload modules for core samples </li></ul><ul><ul><li>$form['choice_wrapper']['poll_more'] = array(     '#type' => 'submit',     '#value' => t('More choices'),     '#description' => t(“click here to add more choices.&quot;),     '#weight' => 1,     '#submit' => array('poll_more_choices_submit'), // If no javascript action.     ' #ahah ' => array(       'event' => 'click',       'path' => 'mymodule/js',       'wrapper' => 'myform-wrapper',       'method' => 'replace',       'effect' => 'fade',       'progress' => array(         'type' => 'bar',         'message' => t('Loading...')     ) </li></ul></ul><ul><li> http://drupalsn.com/learn-drupal/drupal-tutorials/getting-going-ahah-and-drupal-6 </li></ul>
    29. 30. drupal_execute <ul><li>// See user.module, line 2387. </li></ul><ul><li>function user_register () { </li></ul><ul><li>... </li></ul><ul><li>} </li></ul><ul><li>// http://api.drupal.org/api/function/drupal_execute/6 </li></ul><ul><li>// register a new user </li></ul><ul><li>$form_state = array(); </li></ul><ul><li>$form_state['values']['name'] = 'robo-user'; </li></ul><ul><li>$form_state['values']['mail'] = 'robouser@example.com'; </li></ul><ul><li>$form_state['values']['pass'] = 'password'; </li></ul><ul><li>$form_state['values']['op'] = t('Create new account'); </li></ul><ul><li>drupal_execute ('user_register', $form_state); </li></ul>
    30. 31. http://drupal.org/node/165104

    ×