FAPI
heavy lifting with the drupal 6 forms api
DRUPAL FIT


http://groups.drupal.org/fit
ABOUT ME

•   @stevenator d.o/g.d.o

•   me@stevenrifkin.com

•   in addition to Drupal, RoR

•   codeStubble.com

•   Freelancer, hobbyist, World Traveler
MANY WAYS TO SKIN A CAT
CONTRIB MODULES

•   Webform

•   Rules Module does some of this very well - d.o/project/rules

•   CTools...thanks @mdorrell

•   hook_form_alter(&$form, &$form_state, $form_id)

•   Other modules...comments?
MAKE A DECISION
    WHEN MAKING YOUR OWN FORMS

•   planning is your best friend

•   if you go with contrib...test - test - test.

•   Have a read of the .module file

•   can you get away with just hook_form_alter()?
BUILD A MODULE
http://drupal.org/project/module_builder
     @joachim - Joachim Noreiko
MODULE BUILDER ALSO
•   pulls the hook definitions directly from api.drupal.org

•   for lazy developers - reminds you of the params and whether they are
    referenced

•   noobs/newbs/neubs

•   toggle comments
drush mbdl
   drush mb fapi_demo nodeapi menu form form_alter
Paste the returned code into the MY_MODULE.module file

               fapi_demo.module
                    pass in params
                     --build
                     --write --quiet
                     --parent
                     --add
                     --go
                 drush en fapi_demo
FAPI - PERSONAL THOUGHTS
UNDERSTAND THE PAST
The release of Drupal 4.7 introduced the Form API, a framework for building, displaying,



validating, and processing HTML forms. With it, forms are defined as structured arrays, and



those structured arrays contain all the information necessary to properly handle the form



throughout its life cycle. This approach also makes it possible for modules to customize other



forms (adding additional fields to a signup page, for example), and allows designers to



customize the on-screen display of forms using overridable theming functions. It also makes



validating form input, and avoiding form tampering, much easier
FAPI 1.0 VS 2.0
•   Form API 1.0 handled display and submission with drupal_get_form($form_id, $form)
          •   single function built to process and build, handling a single $form array

          •   This works for static forms but makes dynamic forms harder


•   Form API 2.0 was introduced with Drupal 5
          •   drupal_get_form($form_id)

          •   Dedicated functions for processing and building

          •   Separates unprocessed user values from the outgoing array of user inputs
API.DRUPAL.ORG
•   http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/6

•   API Quickstart Guide: http://drupal.org/node/751826
#TREE

•   form array is written as a tree structure with nested elements

•   $form_state[‘values’] returns a flat array that ignores the defined tree

•   unless you set #tree => TRUE

•   #parents is like #tree
#MARKUP
•   an element to wrap elements, insert basic html

•   any element without a #type attribute defaults to a
    markup element

•   #prefix and #suffix may be able to achienve what
    you are after

•   I use this for a lot of js callbacks on the page to
    replace, append, prepend etc...
QUICK DETOUR FOR hook_theme()

•   register your theme functions as you usually would

•   also declare a template key to the function and a tpl.php (or whatever your templating
    flavor) can be made which is useful if you are working with developers

•   this is also something that I have found increasingly more useful with the rise of AJAX
    heavy calls.

•   there is also a #theme key for every element type allowing for custom theming
    through a function or array of functions you want to pass in.
#VALUE
•   internal form element that never gets printed onto the page.

•   not editable by the user

•   Can hold sensitive data that a #hidden form field would be wrong for.

•   Will be joined into the form array upon submission and placed into
    $form_state[‘values’] for future use.

•   form_set_value($form_values[‘key’], $data, $form_state)
OTHER KEYS WORTH MENTIONING

 •   #after_build

 •   #pre-render - you are responsible for returning altered element array

 •   #post-render - you are responsible for returning the results return $html
ADD MENU PATHS
CLEAR
THE
CACHE
CLEAR THE MENU CACHE
       drush cc menu
INITIALIZING THE FORM

•   $_POST and $form_build_id exist?

•   setting a token -- drupal_private_key -- http://drupal.org/node/28420

•   logged in users only anonymous user forms are not unique and are cached

•   prevent injection and xss attacks
hook_elements()

•   this is called from element_info() - collects information on all element properties and
    stores them in cache

•   custom form elements, extend existing elements

•   fivestar module or wysiwyg/tinymce
drupal_get_form($form_id)

•   most called/commonly used of the FAPI functions

•   it returns the output of the rendered form



return drupal_get_form(‘user_register’);
hook_forms($form_id, $args)

•   analogous to hook_theme but for forms

•   validation and submit callbacks are still mapped to the unique form id
drupal_validate_form($form_id)
•   validates token
•   FAPI validation
•   validation callbacks -- form_set_error()
drupal_submit_form($form_id)
•   this is the final step for the developer, i.e. do something
    with all of your new data

•   When a form submits to itself, drupal_get_form will return
    the form to it’s intial page callback unless 1 of two
    conditions exist:

•   $form_state[‘redirect’]

•   $form_state[‘rebuild’] = TRUE
drupal_process_form($form_id, &$form, &$form_state)

•   “the heart of the form API” --api.drupal.org

•   called by drupal_get_form(), drupal_rebuild_form(), and drupal_execute()


               •   form is built

               •   validated

               •   submitted if passes validation or nothing else get in the way
hook_form(&$node, $form_state) vs my_function_form(&$form_state)
         •   hook_form is also used by modules that invoke node forms
             and takes a referenced node object

         •   changes will be seen on the save/edit paths

         •   this is used to add your own form elements to node content

         •   replication of what cck does?

         •   hook_node_info
FORM SCENARIOS

•   Long Form

•   Multistep

•   Wizard/Self Building Form
LONG FORM
•   this is pretty straight forward and comes straight out of the box
    using content types and cck

•   build your form in the browser interface
MULTISTEP
•   save the philosophical debate for the end

•   keys to multistep are in the form_state[‘rebuild’] and
    form_state[‘storage’] settings.

•   Beginning in D6, a form is cached after it is built for the first
    time. So setting $form_state[‘rebuild’] => TRUE will create a
    fresh form and allow you to change the $form array’s
    structure and values.

•   Storing the form’s values into $form_state[‘storage’] will
    cache them for use on the next page
hook_form_alter(&$form, &$form_state, $form_id)

•   remember that you are passing in a reference to the $form array

•   hook_form_FORM_ID_alter will save you a switch or if statement
CAVEATS AND GOTCHAS

•   menu cache

•   $form is an array not an object

•   forms are cached

•   ‘enctype’ => ‘multipart’

•   Drupal.behaviors -to bind functions to page load. Plays nice with other Javascript
    objects acting on the DOM
OTHER FUNCTIONS AND TOPICS

•   good practice to use module key within $form_state, i.e. form_state[‘fapi_demo’][], if
    you are going to use it to pass values

•   $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']);
FUTURE

• Advanced AJAX - #ajax - BADCAMP

• http://api.drupal.org/api/drupal/includes--ajax.inc/group/ajax_commands/7

• Ctool by earl miles (@merlinofchaos)

• Open discussion
•   Pro Drupal Development by John K. VanDyk, Apress © 2008

    D7 version is out - Todd Tomlinson

•   http://drupal.org/node/101707

•   API Quickstart Guide: http://drupal.org/node/751826

•   FAPI (The Grail) http://api.drupal.org/api/drupal/developer--
    topics--forms_api_reference.html/6



                       SOURCES
•   http://www.appnovation.com/create-multiple-step-form-drupal-6




                     SOURCES

Fapi

  • 1.
    FAPI heavy lifting withthe drupal 6 forms api
  • 2.
  • 3.
    ABOUT ME • @stevenator d.o/g.d.o • me@stevenrifkin.com • in addition to Drupal, RoR • codeStubble.com • Freelancer, hobbyist, World Traveler
  • 4.
    MANY WAYS TOSKIN A CAT
  • 5.
    CONTRIB MODULES • Webform • Rules Module does some of this very well - d.o/project/rules • CTools...thanks @mdorrell • hook_form_alter(&$form, &$form_state, $form_id) • Other modules...comments?
  • 6.
    MAKE A DECISION WHEN MAKING YOUR OWN FORMS • planning is your best friend • if you go with contrib...test - test - test. • Have a read of the .module file • can you get away with just hook_form_alter()?
  • 7.
  • 8.
    MODULE BUILDER ALSO • pulls the hook definitions directly from api.drupal.org • for lazy developers - reminds you of the params and whether they are referenced • noobs/newbs/neubs • toggle comments
  • 9.
    drush mbdl drush mb fapi_demo nodeapi menu form form_alter Paste the returned code into the MY_MODULE.module file fapi_demo.module pass in params --build --write --quiet --parent --add --go drush en fapi_demo
  • 10.
  • 11.
    UNDERSTAND THE PAST Therelease of Drupal 4.7 introduced the Form API, a framework for building, displaying, validating, and processing HTML forms. With it, forms are defined as structured arrays, and those structured arrays contain all the information necessary to properly handle the form throughout its life cycle. This approach also makes it possible for modules to customize other forms (adding additional fields to a signup page, for example), and allows designers to customize the on-screen display of forms using overridable theming functions. It also makes validating form input, and avoiding form tampering, much easier
  • 12.
    FAPI 1.0 VS2.0 • Form API 1.0 handled display and submission with drupal_get_form($form_id, $form) • single function built to process and build, handling a single $form array • This works for static forms but makes dynamic forms harder • Form API 2.0 was introduced with Drupal 5 • drupal_get_form($form_id) • Dedicated functions for processing and building • Separates unprocessed user values from the outgoing array of user inputs
  • 13.
    API.DRUPAL.ORG • http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/6 • API Quickstart Guide: http://drupal.org/node/751826
  • 14.
    #TREE • form array is written as a tree structure with nested elements • $form_state[‘values’] returns a flat array that ignores the defined tree • unless you set #tree => TRUE • #parents is like #tree
  • 15.
    #MARKUP • an element to wrap elements, insert basic html • any element without a #type attribute defaults to a markup element • #prefix and #suffix may be able to achienve what you are after • I use this for a lot of js callbacks on the page to replace, append, prepend etc...
  • 16.
    QUICK DETOUR FORhook_theme() • register your theme functions as you usually would • also declare a template key to the function and a tpl.php (or whatever your templating flavor) can be made which is useful if you are working with developers • this is also something that I have found increasingly more useful with the rise of AJAX heavy calls. • there is also a #theme key for every element type allowing for custom theming through a function or array of functions you want to pass in.
  • 17.
    #VALUE • internal form element that never gets printed onto the page. • not editable by the user • Can hold sensitive data that a #hidden form field would be wrong for. • Will be joined into the form array upon submission and placed into $form_state[‘values’] for future use. • form_set_value($form_values[‘key’], $data, $form_state)
  • 18.
    OTHER KEYS WORTHMENTIONING • #after_build • #pre-render - you are responsible for returning altered element array • #post-render - you are responsible for returning the results return $html
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
    CLEAR THE MENUCACHE drush cc menu
  • 24.
    INITIALIZING THE FORM • $_POST and $form_build_id exist? • setting a token -- drupal_private_key -- http://drupal.org/node/28420 • logged in users only anonymous user forms are not unique and are cached • prevent injection and xss attacks
  • 25.
    hook_elements() • this is called from element_info() - collects information on all element properties and stores them in cache • custom form elements, extend existing elements • fivestar module or wysiwyg/tinymce
  • 26.
    drupal_get_form($form_id) • most called/commonly used of the FAPI functions • it returns the output of the rendered form return drupal_get_form(‘user_register’);
  • 27.
    hook_forms($form_id, $args) • analogous to hook_theme but for forms • validation and submit callbacks are still mapped to the unique form id
  • 28.
    drupal_validate_form($form_id) • validates token • FAPI validation • validation callbacks -- form_set_error()
  • 29.
    drupal_submit_form($form_id) • this is the final step for the developer, i.e. do something with all of your new data • When a form submits to itself, drupal_get_form will return the form to it’s intial page callback unless 1 of two conditions exist: • $form_state[‘redirect’] • $form_state[‘rebuild’] = TRUE
  • 30.
    drupal_process_form($form_id, &$form, &$form_state) • “the heart of the form API” --api.drupal.org • called by drupal_get_form(), drupal_rebuild_form(), and drupal_execute() • form is built • validated • submitted if passes validation or nothing else get in the way
  • 31.
    hook_form(&$node, $form_state) vsmy_function_form(&$form_state) • hook_form is also used by modules that invoke node forms and takes a referenced node object • changes will be seen on the save/edit paths • this is used to add your own form elements to node content • replication of what cck does? • hook_node_info
  • 32.
    FORM SCENARIOS • Long Form • Multistep • Wizard/Self Building Form
  • 33.
    LONG FORM • this is pretty straight forward and comes straight out of the box using content types and cck • build your form in the browser interface
  • 34.
    MULTISTEP • save the philosophical debate for the end • keys to multistep are in the form_state[‘rebuild’] and form_state[‘storage’] settings. • Beginning in D6, a form is cached after it is built for the first time. So setting $form_state[‘rebuild’] => TRUE will create a fresh form and allow you to change the $form array’s structure and values. • Storing the form’s values into $form_state[‘storage’] will cache them for use on the next page
  • 35.
    hook_form_alter(&$form, &$form_state, $form_id) • remember that you are passing in a reference to the $form array • hook_form_FORM_ID_alter will save you a switch or if statement
  • 36.
    CAVEATS AND GOTCHAS • menu cache • $form is an array not an object • forms are cached • ‘enctype’ => ‘multipart’ • Drupal.behaviors -to bind functions to page load. Plays nice with other Javascript objects acting on the DOM
  • 37.
    OTHER FUNCTIONS ANDTOPICS • good practice to use module key within $form_state, i.e. form_state[‘fapi_demo’][], if you are going to use it to pass values • $form['destination'] = array('#type' => 'hidden', '#value' => $_GET['q']);
  • 38.
    FUTURE • Advanced AJAX- #ajax - BADCAMP • http://api.drupal.org/api/drupal/includes--ajax.inc/group/ajax_commands/7 • Ctool by earl miles (@merlinofchaos) • Open discussion
  • 39.
    Pro Drupal Development by John K. VanDyk, Apress © 2008 D7 version is out - Todd Tomlinson • http://drupal.org/node/101707 • API Quickstart Guide: http://drupal.org/node/751826 • FAPI (The Grail) http://api.drupal.org/api/drupal/developer-- topics--forms_api_reference.html/6 SOURCES
  • 40.
    http://www.appnovation.com/create-multiple-step-form-drupal-6 SOURCES

Editor's Notes

  • #2 Welcome\nLet’s wait for everyone to settle\n
  • #3 \n
  • #4 \n
  • #5 \n
  • #6 \n
  • #7 I’ve made many a module that only implements hook_form_alter\n
  • #8 \n
  • #9 stores the hooks in the default directory default.hooks.inc\n
  • #10 --add Append hooks to module file. Implies '--write --build=code'. Warning: will not check hooks already exist.\n\ndrush dochooks my_module -- inserts hooks into existing modules\n\nremember to clear out unused BS before you try to run the module...\n\nHigher LEVEL\nTelling module builder about your hooks\nLots of contrib modules provide hooks. You can tell module builder about them, so users can easily generate code for your module's hooks in their own modules.\nTo do this, implement hook_module_builder_info() in a file named YOUR_MODULE.module_builder.inc file in your module folder. See the contents of module_builder.module_builder.inc for a detailed example.\n
  • #11 so before i delve into the api itself, i thought i’d mention why i wanted to give this presentation.\n-learning curve\n-wished someone had started me here\n-because of the loop that the form api takes us through, we learn a lot about drupal, it’s hooks and, most importantly, it’s caches.\n-does anyone share this feeling?\n
  • #12 there are a few steps\narrays not objects\n
  • #13 \n
  • #14 spend some time here\ncheckbox vs checkboxes\n
  • #15 \n
  • #16 \n
  • #17 outside the scope of this talk\ntpl.php is reminiscent of MVC frameworks\n
  • #18 \n
  • #19 pass callback function as well as an array of functions for abstracting common tasks that might repeat themselves in other parts of your module and/or form processing\n\n#pre-render called before drupal_render...receives the #element as the param and must return the altered element\n#post-render 2 params “rendered element and its children”\n\nbe careful of overwriting your existing array...you can do a check to see if the properties you are after are set\n\nrules module hooks into these functions\n
  • #20 GO TO THE SIMPLE #MARKUP, #VALUE EXAMPLE\n
  • #21 \n
  • #22 \n
  • #23 \n
  • #24 \n
  • #25 private key is stored in the variables - best not to touch it\n\nif POST exists then we check the cache to see if there is a copy for the current session\nif YES then retrieve cached form and move on to the check if the form was submitted\nif YES we move to the validate functions\nif PASS validate run submit and process values\nif REDIRECT we are off\nif no REDIRECT then redisplay empty form with a message (hopefully)\nif NO check cace, rebuild, set cache, render form\nif NO cached copy, build form, then move to see form was submitted\nNO Post or form_build_id exists then build\n\npg 222 of Pro Drupal 6\n
  • #26 then element_info is called\nfivestar is pretty straightforward\ntinymce modifies the default properties of the already existing textarea element - changes the #process => ‘callback function called tinymce_process_textarea’\n
  • #27 \n
  • #28 This hook allows modules to build multiple forms from a single form "factory" function but each form will have a different form id for submission, validation, theming or alteration by other modules.\n
  • #29 these are the default callbacks that Drupal tries to match to your unique form id. You can set the #validate and #submit keys on the form, and form elements to instruct your callback to do something special. Those are also called during the drupal_process_form function\n
  • #30 these are the default callbacks that Drupal tries to match to your unique form id. You can set the #validate and #submit keys on the form, and form elements to instruct your callback to do something special. Those are also called during the drupal_process_form function\n
  • #31 show http://api.drupal.org/api/drupal/includes--form.inc/function/drupal_process_form/6\n
  • #32 I though I’d mention hook_node_info here because it doesn’t really jive elsewhere in the presentation\n name\n module\n description\n help\naccepts array with the usual params:\nhas_title => FALSE\nhas_body\n
  • #33 \n
  • #34 show hook_form and the returning of the $form\n
  • #35 \n
  • #36 &$form\n
  • #37 \n
  • #38 \n
  • #39 show Form API reference D7\nhttp://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7\n \n FAPI integration - allows module developers to create new form components using '#type' => 'multiselect'\n\n
  • #40 \n
  • #41 \n