NAME

HTML::FormEngine - create,validate and control html/xhtml forms

DEPENDENCIES

Perl Version

5.004

Standard Modules

none

Nonstandard Modules

Clone 0.13
Hash::Merge 0.07
Locale::gettext 1.01
Date::Pcalc 1.2

SYNOPSIS

Example Code

       #!/usr/bin/perl

       use strict;
       use CGI;
       use HTML::FormEngine;
       #use POSIX; # for setlocale
       #setlocale(LC_MESSAGES, 'german'); # for german error messages

       my $q = new CGI;
       print $q->header;

       my $Form = HTML::FormEngine->new(scalar $q->Vars);
       my @form = (
	    {
	      templ => 'select',
	      NAME => 'Salutation',
	      OPTION => ['mr.','mrs.'],
	    },
	    {
	     SIZE => 10,
	     MAXLEN => 20,
	     SUBTITLE => [['', ' / ']],
	     NAME => [['forname', 'surname']],
	     TITLE => 'For- / Surname ',
             ERROR_IN => 'not_null'
	    },
	    {
	      MAXLEN => 30,
	      NAME => 'Email',
	      ERROR => ['not_null', 'rfc822'] # rfc822 defines the email address standard
	    },
	    {
	     templ => 'radio',
	     TITLE => 'Subscribe to newsletter?',
	     NAME => 'newsletter',
	     OPT_VAL => [[1, 2, 3]],
	     OPTION => [['Yes', 'No', 'Perhaps']],
	     VALUE => 1
	    },
	    {
	     templ => 'check',
             OPTION => 'I agree to the terms of condition!',
             NAME => "agree",
             TITLE => '',
	     ERROR => sub{ return("you've to agree!") if(! shift); }
	    }
       );

       $Form->conf(\@form);
       $Form->make();

       print $q->start_html('FormEngine example: Registration');
       if($Form->ok){
         $Form->clear();	
	 print "<center>You've successfully subscribed!</center><br>";
       }
       print $Form->get,
             $q->end_html;

Example Output

This output is produced by FormEngine when using the example code and no data was submitted:

    <form action="/cgi-bin/FormEngine/registration.cgi" method="post">
    <table border=0 align="center" summary="">
    <tr>
       <td valign="top">Salutation</td>
       <td>
	  <select size="1" name="Salutation">
	    <option value="mr.">mr.</option>

	    <option value="mrs.">mrs.</option>
	  </select>
       </td>
       <td style="color:#FF0000" valign="bottom"></td>
    </tr>
    <tr>
       <td valign="top">For- / Surname </td>
       <td>
	  <table border=0 cellspacing=0 cellpadding=0 summary="">

	    <tr>
	      <td valign="top">
		<table border=0 cellspacing=0 cellpadding=0 summary="">
		  <tr>
		    <td></td>
		    <td>
		      <input type="text" value="" name="forname" maxlength="20" size="10" /><br/>
		    </td>
		  </tr>

		  <tr><td></td><td style="color:#FF0000"></td></tr>
		</table>
	      </td>
	      <td valign="top">
		<table border=0 cellspacing=0 cellpadding=0 summary="">
		  <tr>
		    <td>&nbsp;/&nbsp;</td>
		    <td>

		      <input type="" value="" name="surname" maxlength="20" size="10" /><br/>
		    </td>
		  </tr>
		  <tr><td></td><td style="color:#FF0000"></td></tr>
		</table>
	      </td>
	    </tr>
	  </table>
       </td>
       <td style="color:#FF0000" valign="bottom"></td>
    </tr>
    <tr>
       <td valign="top">Email</td>
       <td>
	  <table border=0 cellspacing=0 cellpadding=0 summary="">
	    <tr>
	      <td valign="top">
		<table border=0 cellspacing=0 cellpadding=0 summary="">

		  <tr>
		    <td></td>
		    <td>
		      <input type="text" value="" name="Email" maxlength="30" size="20" /><br/>
		    </td>
		  </tr>
		  <tr><td></td><td style="color:#FF0000"></td></tr>
		</table>
	      </td>

	    </tr>
	  </table>
       </td>
       <td style="color:#FF0000" valign="bottom"></td>
    </tr>
    <tr>
       <td valign="top">Subscribe to newsletter?</td>
       <td>
	  <table border=0 summary="">

	    <tr>
	      <td><input type="radio" value="1" name="newsletter" checked />Yes</td>
	      <td><input type="radio" value="2" name="newsletter" />No</td>
	      <td><input type="radio" value="3" name="newsletter" />Perhaps</td>
	    </tr>
	  </table>
       </td>
       <td style="color:#FF0000" valign="bottom"></td>
    </tr>
    <tr>
       <td valign="top"></td>
       <td>
	 <table summary="">
	   <tr>
	     <td>
	       <input type="checkbox" value="I agree to the terms of condition!" name="agree" /> I agree to the terms of condition!
	       <font style="color:#FF0000"></font>

	     </td>
	   </tr>
	 </table>
       </td>
       <td valign="bottom" style="color:#FF0000"></td>
    </tr>
    <tr>
       <td align="right" colspan=3>
	  <input type="submit" value="Ok" name="FormEngine" />
       </td>
    </tr>
    </table>
    </form>

DESCRIPTION

FormEngine.pm is a Perl 5 object class which provides an api for managing html/xhtml forms. FormEngine has its own, very flexible template system for defining form skins. A default skin is provided, it should be sufficent in most cases, but making your own isn't difficult (please send them to me!).

FormEngine also provides a set of functions for checking the form input, here too it is very easy to define your own check methods or to adapt the given.

gettext is used for international error message support. So use setlocale(LC_MESSAGES, 'german') if you want to have german error messages (there isn't support for any other language yet, but it shouldn't be difficult to translate the .po file, don't hesitate!).

FormEngine is designed to make extension writing an easy task!

OVERVIEW

Start with calling the new method, it will return an FormEngine object. As argument you can pass a reference to an hash, which should contain the input values (calling set_input is also possible). Now you should define an array or hash which contains the form configuration. Pass a reference to that hash or array to conf. Now call make, this will generate the html code. Next you should use ok to check if the form was submitted and all input values are correct. If this is the case, you should display a success message and call get_input(fieldname) for getting the value of a certain field and e.g. write it in a database. Else you should call get (which will return the html form code) or print which will directly print the form.

If you want the form to be always displayed, you can use clear to empty it (resp. display the defaults) when the transmission was successfull.

USING FORMENGINE

The easiest way to define your form is to create an array of hash references:

    my @form = (
	    {
	      templ => 'select',
	      NAME => 'Salutation',
	      OPTION => ['mr.','mrs.'],
	    },
	    {
	     SIZE => 10,
	     MAXLEN => 20,
	     SUBTITLE => [['', '&nbsp;/&nbsp;']],
	     NAME => [['forname', 'surname']],
	     TITLE => 'For- / Surname ',
             ERROR_IN => 'not_null'
	    },
	    {
	      MAXLEN => 30,
	      NAME => 'Email',
	      ERROR => ['not_null', 'rfc822'] # rfc822 defines the email address standard
	    },
	    {
	     templ => 'radio',
	     TITLE => 'Subscribe to newsletter?',
	     NAME => 'newsletter',
	     OPT_VAL => [[1, 2, 3]],
	     OPTION => [['Yes', 'No', 'Perhaps']],
	     VALUE => 1
	    },
	    {
	     templ => 'check',
             OPTION => 'I agree to the terms of condition!',
             NAME => "agree",
             TITLE => '',
	     ERROR => sub{ return("you've to agree!") if(! shift); }
	    }
       );

This is taken out of the example above. The templ key defines the field type (resp. template), the capital written keys are explained below. If templ is not defined, it is expected to be text.

You then pass a reference to that array to the conf method like this:

$Form->conf(\@form);

Another possibility is to define a hash of hash references and pass a reference on that to conf. This is seldom needed, but has the advantage that you can define low level variables:

my %form = (
     METHOD => 'get',
     FORMNAME => 'myform',
     SUBMIT => 'Yea! I want that!',
     'sub' => [ 
                 # Here you place your form definition (see above)
              ] 
);

$Form->conf(\%form);

The meaning of the keys is explained below. You can call set_main_vars for setting low level (main) variables as well, so the hash notation isn't necessary.

The Default Skin

...knows the following field types:

  • text - text input field(s), one row

  • textarea - text input field(s), several rows

  • radio - selection list in terms of buttons (one can be selected)

  • select - selection list in terms of a pull down menu (one can be selected)

  • check - selection list in terms of buttons (several can be selected)

  • hidden - invisible field(s), can be used for passing data

  • emb_text - text field, designed to be embedded (nested) in another template (see below)

Variables

Note that if you don't use the default skin, things might be diffrent. But mostly only the layout changes. A skin which doesn't fit to the following conventiones should have its own documentation.

These Variables are always available:

  • NAME - the form fields name (this must be passed to get_input for getting the complying value)

  • TITLE - the displayed title of the field, by default the value of NAME

  • VALUE - the default (or initial) value of the field

  • ERROR - accepts name of an FormEngine check routine (see Config.pm and Checks.pm), an anonymous function or an reference to a named method. If an array reference is passed, a list of the above mentioned values is expected. FormEngine will then call these routines one after another until an errormessage is returned or the end of the list is reached.

These variables are available for the text and emb_text field type only:

  • SIZE - the physical length of the field (in characters) [default: 20]

  • MAXLEN - max. count of characters that can be put into the field [default: no limit]

  • TYPE - if set to password for each character a * is printed (instead of the character) [default: text]

These variables are available for all selection field types (radio, select, check) only:

  • OPTION - accepts an reference to an array with options

  • OPT_VAL - accepts an reference to an array with values for the options (by default the value of OPTION is used)

These variables are available for the textarea field type only:

  • COLS - the width of the text input area [default: 27]

  • ROWS - the height of the text input area [default: 10]

These variables are so called main variables they can be set by using the hash notation (see above) or by calling set_main_vars (see below):

  • ACTION - the url of the page to which the form data should be submitted [default: $ENV{REQUEST_URI}, that means: the script calls itself]. Normally it doesn't make sense to change this value, but when you use mod_perl, you should set it to '$r->uri'.

  • METHOD - can be 'post' (transmit the data in HTTP header) or 'get' (transmit the data by appeding it to the url) [default: post].

  • SUBMIT - the text that should be displayed on the submit button [default: Ok]

  • FORMNAME - the string by which this form should be identified [default: FormEngine]. You must change this if you have more than one FormEngine-made form on a page. Else FormEngine won't be able to distinguish which form was submitted.

Note: only NAME must be set, all other variables are optional.

Methods For Creating Forms

new ([ HASHREF ])

This method is the constructor. It returns an FormEngine object. You can pass the user input in a hash reference to it, but you can use set_input as well.

set_input ( HASHREF )

To this method you must pass a reference to a hash with input values. You can pass this hash reference to the constructor (new) as well, then you don't need this function. If you use mod_perl you can get this reference by calling 'scalar $m->request_args'. If you use CGI.pm you get it by calling 'scalar $q->Vars'.

conf ( FORMCONF )

You have to pass the configuration of your form as array or hash reference (see above).

set_main_var ( HASHREF )

You can use this method for setting the values of the main template variables (e.g. SUBMIT). Another possibility to do that is using the hash notation when configuring the form (see above).

clear

If the form was submitted, this method simply calls set_use_input and set_error_chk. It sets both to false. If make was already called, it calls it again, so that no input is used and no error check is done.

set_error_chk ( VALUE )

Sets wether the error handler should be called or not. Default is true (1).

set_use_input ( VALUE )

Sets wether the given input should be displayed in the form fields or not. Default is true (1).

make

Creates the html/xhtml output, but doesn't return it (see get and print below). Every method call which influences this output must be called before calling make!

print

Sends the html/xhtml output directly to STDOUT. make must be called first!

get

Returns the html/xhtml form code in a string. make must be called first!

ok

Returns true (1) when the form was submitted and no errors were found! Else it returns false (0). This method simply calls is_submitted and get_error_count.

get_error_count

Returns the count of errors which where found by the error handler.

is_submitted

Returns true (1) if the form was submitted, false (0) if not.

get_input ( FIELDNAME )

Returns the input value of the corresponding field.

Methods For Configuring FormEngine

set_skin ( HASHREF )

If you want to use an alternate skin, call this method. You have to pass a reference to the skin hash.

add_skin ( HASHREF )

If you only want to add or overwrite some templates of the current skin, call this method. You have to pass a reference to the hash which stores these templates.

set_default ( HASHREF )

By using this method, you completly reset the default values of the template variables. You have to pass a reference to the hash which stores the new settings. Look at Config.pm to see the current settings. In most cases you better call add_default.

add_default ( HASHREF )

Pass a hash reference to this method for adding or overwriting default values. Look at Config.pm for more information.

set_handler ( HASHREF )

This method resets the handler settings. Look at Config.pm for the default settings. If you just want to add or overwrite a handler setting, use add_handler (see below).

add_handler ( HASHREF )

This method adds or overwrites template handlers. Look at Config.pm and Handler.pm for more information.

add_checks ( HASHREF )

This method temporary adds or overwrites check routines. Look at Config.pm and Checks.pm for more information.

Debug Methods

set_debug ( DEBUGLEVEL )

Sets the debug level. The higher the value the more output is printed.

get_method

Returns the value of mains METHOD variable (should be get or post).

get_formname

Returns the value of mains FORMNAME variable. If you have several FormEngine forms on one page, these forms mustn't have the same FORMNAME value! You can set it with set_main_vars.

get_conf

Returns a reference to a hash with the current form configuration. Changing this hash DOESN'T influence the configuration, because it is just a copy.

Prints the current form configuration to STDOUT.

Special Features

nesting templates

There are two ways how you can nest templates. The first one is to put a handler call in the template definition. This is a less flexible solution, but it might be very usefull. See the pod documentation of Skin.pm for more information.

The second and flexible way is, to assign a handler call to a template variable (see the pod documentation of Skin.pm for more information about handler calls). A good example for this way is hobbies.cgi. There you have a option called other and an input field to put in the name of this alternative hobby. When you look at the form definition below, you see that the value of the OPTION variable of this option is simply <&emb_text&>, this is a handler call. So the handler is called and its return value (in this case the processed emb_text template) is assigned to the variable.

The form definition of hobbies.cgi:

    my @form = (
	    {
	      templ => 'check',
	      NAME  => [['hobbies[1]','hobbies[2]'],['hobbies[3]','hobbies[4]'],['hobbies[5]','hobbies[6]'],'hobbies[7]','hobbies[8]'],
	      TITLE => 'hobbies',
	      OPTION => [['Parachute Jumping', 'Playing Video Games'], ['Doing Nothing', 'Soak'], ['Head Banging', 'Cat Hunting'], "Don't Know", '<&emb_text&>'],
	      OPT_VAL => [[1,2], [3,4], [5,6], 7, 8],
	      VALUE => [1,2,7],
	      'sub' => {'emb_text' => {'NAME' => 'Other', 'VALUE' => ''}},
	      ERROR => sub{if(shift eq 4) { return "That's not a faithfull hobby!" }}
	    }
    );			

If you have a closer look at the form definition above, you'll recognize that there is a key called 'sub'. With help of this key you can define the variables of the nested templates. If the nested templates don't use the same variable names as their parents, you don't need that, because then you can assign these variables on the same level with the parents template variables.

EXTENDING FORMENGINE

Modify A Skin

To modify the current skin, use the method add_skin (see above). You should have a look at Skin.pm and read its pod documentation.

Write A New Skin

Have a look at Skin.pm for this task. You can easily change the layout by copying the skin hash, fitting the html code to your needs and then using set_skin (see above) to overwrite the default. Please send me your skins.

Write A Handler

Look at the pod documentation of Handler.pm. You can use add_handler to add your handler temporary, edit Config.pm to make it persistent.

Write A Check Routine

The design of a check routine is explained in the pod documentation of Checks.pm. You can easily refer to it by reference or even define it in line as an anonymous function (see the ERROR template variable). If your new written routine is of general usage, you should make it part of FormEngine by placing it in Checks.pm and refering to it in Config.pm. Please send me such methods!

MORE INFORMATION

Have a look at ...

  • the pod documentation of Skin.pm for information about FormEngines template system.

  • the pod documentation of Handler.pm for information about FormEngines handler architecture.

  • the pod documentation of Checks.pm for information about FormEngines check methods.

  • Config.pm for the default configuration.

BUGS

Send bug reports to: moritz@freesources.org

Thanks!

AUTHOR

(c) 2003, Moritz Sinn. This module is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (see http://www.gnu.org/licenses/gpl.txt) as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This module is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

I am always interested in knowing how my work helps others, so if you put this module to use in any of your own code then please send me the URL. Also, if you make modifications to the module because it doesn't work the way you need, please send me a copy so that I can roll desirable changes into the main release.

Address comments, suggestions, and bug reports to moritz@freesources.org.