INTRODUCTION
FormMagick(FM) is the primary API available for creating server-manager panels in SME Server. It provides a comprehensive toolset for developing form-based web pages using an easy to use XML based templating system similar to HTML template systems like Template::Toolkit and HTML::Template. FM includes a powerful form field validation mechanism, multi-lingual support, and built in CGI security measures. Unlike the previous SME Server Manager API, which used a Batch Oriented approach to panel design, FM uses an Event Driven approach. This approach simplifies panel design and development and allows for easy recycling of code developed in other server-manager panels.
FORMMAGICK PANEL OVERVIEW
FormMagick Server-Manger panels consist of three major components:
- XML Document: The XML document is the backbone, or framework, of the FM server-manager panel. While it doesn’t contain any actual logic per se, the FM XML document provides the structure for the panel through a nested hierarchy of XML elements. Think of the XML document like an outline for a writing report.
- Lexicon Definitions: Lexicon definitions are collections of translation variables, in XML format, for each panel that provide the actual text for the panel depending on the defined language. This allows for support if any of a number of different languages by simply creating a new Lexicon for the language in question. There is no need to alter the panel code in any way.
- Perl Module: This component of the FM server manager panel provides much of the “under the hood” logic for the panel. Typical FM perl modules consist of a collection of functions that either look up existing information from SME data bases or set values in these databases. This is also the place to signal events, restart services, etc.
XML DOCUMENT
Location: /etc/e-smith/web/functions/
Overview
Each SME Server-Manager panel requires what we’ll now refer to as an “XML Document” to be located in etc/e-smith/web/functions and a symbolic link in /etc/e-smith/web/panels/manager/cgi-bin pointing to the XML document. While this document isn’t 100% XML, most of what’s contained in this document are XML elements that define the layout of the panel. The XML document contains several important things in addition to the actual XML, including information that tells SME where to put the panel in the server-manager menu bar and code that basically ties all three components of the FM panel together (i.e., XML Document, Lexicon Definitions, and Perl Module). The XML Document can be divided into three required sections: Header, Initialization, and XML. Following we will look at each in detail.
Header
A typical Header section for an XML Document is as follows:
1: #!/usr/bin/perl -wT 2: 3: #---------------------------------------------------------------------- 4: # heading : Security 5: # description : My first panel 6: # navigation : 5000 5200 7: #----------------------------------------------------------------------
OK, lets have a line-by-line look at what's included here and what it means.
Line 1: This is the perl shebang with Taint and Warnings flags set. Include this verbatium with all panels.
Line 2: Space.
Line 3: Begin menu placement comment block. Include verbatium.
Line 4: Menu item placement. Replace the work "Security" with the Server-Manager menu category that you'd like your panel to show up it.
Line 5: Menu item text. Replace the phrase "My first panel" with the menu text that you'd like displayed in the menu block
Line 6: Menu item placement: Replace the 5000 and 5200 numbers with numbers that place your new menu item in the order that you'd like it displayed (note to self: Need to flush this out a bit more).
Line 7: End menu placement comment block. Include verbatium.
Just after Line 7, you can place additional perl comment lines to include other information related to your panel code such as copyright information and licensing.
Initialization
The Initialization section must consist of the following:
8: use strict; 9: use esmith::FormMagick::Panel::my_first_panel; 10: my $f = esmith::FormMagick::Panel::my_first_panel->new(); 11: $f->display();
Let's have a look at what's going on here.
Line 8: Attach the strict pragma. Include this verbatium with all panels.
Line 9: Attach your panel perl module. Change "::my_first_pane" with the perl module name for your new FM panel.
Line 10: Creates a instance of your new panel. Replace "::my_first_panel" with your panel perl module name.
Line 11: Display the panel. Include verbatium.
XML
A typical XML section is as follows:
12: __DATA__ 13: <form 14: title="FORM_TITLE" 15: header="/etc/e-smith/web/common/head.tmpl" 16: footer="/etc/e-smith/web/common/foot.tmpl"> 17: 18: <!-- page 0 --> 19: <page 20: name="Front_Page" 21: pre-event="print_status_message()"> 22: <description>FIRST_PAGE_DESCRIPTION</description> 23: <field 24: id="widget1" 25: type="select" 26: options="'YES','NO'"> 27: <label>LABEL_FOR_WIDGET_ONE</label> 28: </field> 29: </page> 30: 31: <!-- page 1 --> 32: <page 33: name="Another_Page" 34: pre-event="print_status_message()"> 35: <description>NEXT_PAGE_DESCRIPTION</description> 35: <field 36: id="widget2" 37: type="text" 38: size="15" 39: validation="my_custom_validation_function()"> 40: <label>LABEL_FOR_WIDGET2</label> 41: </field> 42: </page> 43: </form>
LEXICON DEFINITIONS
Location: /etc/e-smith/location/
PERL MODULE
Location: /usr/lib/perl5/site_perl/esmith/FormMagick/Panel/
EXAMPLE 1: Hello World
EXAMPLE 2:
FORMMAGICK XML REFERENCE
NAME
CGI::FormMagick - easily create CGI form-based applications
SYNOPSIS
use CGI::FormMagick;
my $f = new CGI::FormMagick();
- all options available to new()
my $f = new CGI::FormMagick(
type => file, source => $myxmlfile,
);
- other types available
my $f = new CGI::FormMagick(type => string, source => $data );
$f->display();
DESCRIPTION
FormMagick is a toolkit for easily building fairly complex form-based web applications. It allows the developer to specify the structure of a multi-page "wizard" style form using XML, then display that form using only a few lines of Perl.
- How it works
You (the developer) provide at least:
- An XML form description
- HTML templates for the page headers and footers
And may optionally provide:
- Translations of strings used in your application, for localisation
- Validation routines for user input data
- Routines to run before or after a page of the form is displayed
FormMagick brings them all together to create a full application.
METHODS
new()
The "new()" method requires no arguments, but may take the following optional arguments (as a hash):
type
Defaults to "file". "string" is also available, in which case you must specify a source which is either a literal string or a scalar variable.
source
Defaults to a filename matching that of your script, only with an extension of .xml (we got this idea from XML::Simple).
charset
Tell FormMagick that the XML input uses the specified character set encoding. Defaults to 'none' which is good enough for English text and US ASCII. Any other characters may cause parse errors. Valid charsets are "ISO-8859-1", "UTF-8", "UTF-16", or "US-ASCII". This option is case sensitive.
previousbutton()
With no arguments, tells you whether the previousbutton will be displayed or not. If you give it a true argument (eg 1) it will set the previous button to be displayed. A false value (eg 0) will set it to not be displayed.
nextbutton()
As for previousbutton, but affects the "Next" button.
finishbutton()
Ditto.
resetbutton()
Ditto.
startoverlink()
Ditto.
debug()
Turns debugging on/off.
sessiondir()
With no arguments, tells you the directory in which session tokens are kept.
With a true value, set the session directory, in which session tokens are kept. Defaults to "session-tokens" under the directory in which your CGI script is kept, but you probably want to set it to something outside the web tree.
With a false (but defined) value, resets the session dir to its default value.
fallback_language($language)
Given a 2-letter ISO language code, makes that language the fallback language for localisation. Not necessary unless you want it to be something other than the base language in which your application is written. Set it to a false (but defined) value to turn off the fallback language feature.
With no arguments, tells you what the current fallback language is.
display()
The display method displays your form. It takes no arguments. It does however, respect certain CGI parameters that can be set in the submission of the page. For example, if the skip_header parameter is set, it will just execute the post-event and return, giving the post-event complete control over the response.
RANDOM USEFUL METHODS
$fm->cgi()
Returns the CGI object that FormMagick is using.
$fm->wherenext($pagename);
Set the magic "wherenext" CGI parameter, which tells FormMagick which page to display next. Particularly useful when used in a page's post-event routine, to (for instance) go to a different next page depending on what the user entered on the last page.
This method is also exported so you can use it in the form itself, for
- instance
- <page post-event="wherenext('SomePage')">
With no args, returns the value of the "wherenext" parameter.
$fm->go_to_finish()
Like wherenext(), except that it says to go to the finish and perform the form post-event and do all the things that would ordinarily be done when a user clicks the "Finish" button. Can be used as a method or as an
- exported function, so you can do things like
- <page post-event="go_to_finish()">
FORMMAGICK XML TUTORIAL
Form descriptions
The main thing you need to know to use FormMagick is the structure and syntax of FormMagick forms. FormMagick is based on a "wizard" sort of interface, in which one form has many pages, and each page has many fields. This is expressed as a nested hierarchy of XML elements.
For examples of FormMagick XML, see the "examples/" directory included in the FormMagick distribution.
The XML must comply with the FormMagick DTD (included in the distribution as FormMagick.dtd). A command-line tool to test compliance is planned for a future release.
Here is an explanation of the nesting of elements and the attributes supported by each element.
FORMS
Form sub-elements
A form may contain the following elements:
- page
Form attributes
The following attributes are supported for forms:
- pre-event (a subroutine to run before the form is displayed)
- post-event (a subroutine to run after the form is completed)
Example
<form pre-event="setup()" post-event="submit()>
<page> ... </page> <page> ... </page> <page> ... </page>
</form>
PAGES
Page sub-elements
A page may contain the following sub-elements:
- description
- field
Page attributes
The following attributes are supported for pages:
- name (required)
- pre-event=<func>
- post-event=<func>
- menu=<func>
Example
<page
name="RoomType" menu="show_menu()" post-event="check_availability">
<description>
Please provide us with details of your preferred room.
</description> <field> ... </field> <field> ... </field> <field> ... </field>
</page>
FIELDS
Fields are the most important part of the form definition. Several types of HTML fields are supported, and each one has various attributes associated with it.
Field types
You can specify the type of HTML field to be generated using the type
- attribute
- <field type="...">
The following field types are supported:
text
A plain text field. You may optionally use the size attribute to modify the size of the field displayed. To restrict the length of data entered by the user, use the maxlength() validation routine.
select
A dropdown list. You must provide the options attribute to specify the contents of the list (see below for the format of this attribute). If you set the multiple attribute to 1, multiple selections will be enabled. The optional size attribute sets the number of items displayed at once.
radio
Radio buttons allow users to choose one item from a group. This field type requires the options attribute (as for select, above).
checkbox
This field type provides a simple check box for yes/no questions. The checked attribute is optional, but if set to 1 will make the checkbox checked by default.
password
The password field type is like a text field, but obscures the data typed in by the user.
file
This field type allows the upload of a file by the user.
textarea
A multi-line text field allowing the input of blocks of text. Defaults to 5 rows and 60 columns, but you can specify "rows" and "cols" arguments to change that.
literal
A field that is just printed literally. Useful if you want to just print out a non-editable bit of text in the same sort of layout as the other fields in the form.
You may specify a subroutine to generate the field type. This is particularly useful in "create or modify" type forms where one or more fields will be input fields when creating or literals when modifying. The subroutine can return any of the above type as a string.
Field sub-elements
The following elements may be nested within a field:
- label (a short description; required)
- description (a more verbose description; optional)
Other field attributes
Fields must ALWAYS have a type (described in the previous section) and an id attribute, which is a unique name for the field. Each type of field may have additional required attributes, and may support other optional attributes.
Here is a list of optional attributes for fields:
value
A default value to fill in; see below for more information on the format of this field.
validation
a list of validation functions; see the CGI::FormMagick::Validator manpage for more information on this subject.
validation-error-message
an error message to present to the user if validation fails. CGI::FormMagick::Validator provides one by default, but you may prefer to override it.
options
A list of options required for a select list or radio buttons; see below for more information on the format of this attribute.
checked
For checkbox fields, used to make the box checked by default. Defaults to 0.
multiple
For select fields, used to allow the user to select more than one value.
size
For select fields, height; for text and textarea fields, length.
Notes on parsing of value attribute
If your value attribute ends in parens, it'll be taken as a subroutine to run. Otherwise, it'll just be taken as a literal.
- This will be literal
- value="username"
- This will run a subroutine
- value="get_username()"
The subroutine will be passed the CGI object as an argument, so you can use the CGI params to help you generate the value you need.
Your subroutine should return a string containing the value you want.
Notes on parsing of options attribute
The options attribute has automagical Do What I Mean (DWIM) abilities. You can give it a value which looks like a Perl list, a Perl hash, or a
- subroutine name. For instance
options="'red', 'green', 'blue'"
options="'ff0000' => 'red', '00ff00' => 'green', '0000ff' => 'blue'"
options="get_colors()"
How it works is that FormMagick looks for the => operator, and if it finds it it evals the options string and assigns the result to a hash. If it finds a comma (but no little => arrows) it figures it's a list, and evals it and assigns the results to an array. Otherwise, it tries to interpret what's there as the name of a subroutine in the scope of the script that called FormMagick, expecting to get back a value which is either an arrayref or a hashref, which it will deal with appropriately in either case.
A few gotchas to look out for:
- Make sure you quote strings in lists and hashes. "red,blue,green" will fail (silently) because of the barewords.
- Single-element lists ("red") will fail because the DWIM parsing doesn't find a comma there and treats it as the name of a subroutine. But then, a single-element radio button group or select dropdown is pretty meaningless anyway, so why would you do that?
- Arrays will result in options being sorted in the same order they were listed. Hashes will be sorted by value using the Perl's cmp() function (ASCIIbetical sort, in other words).
- An anti-gotcha: subroutine names do not require the parens on them. "get_colors" and "get_colors()" will work the same.
INTERNAL, DEVELOPER-ONLY ROUTINES
The following routines are used internally by FormMagick and are documented here as a developers' reference. If you are using FormMagick to develop web applications, you can skip this section entirely.
magic_wherenext
We allow FM users to set the "wherenext" param explicitly in their code, to do branching of program logic. This routine checks to see if they have a magic "wherenext" param and returns it. Gives undef if it's not set.
prepare_for_next_page
This does all the things needed before going on to the next page. Specifically, it validates the data from this page, and then if validation was successful it puts the current page onto the page stack and then sets page_number to whatever page we should be visiting next.
$fm->cleanup_checkboxes()
Checkbox params only get passed around if they're checked. An unchecked box doesn't send "checkbox=0" ... no, it just completely fails to send anything at all. This is a PITA, as it's impossible to distinguish an explicity unchecked box from one that never got seen at all.
This subroutine is intended to clean up the mess, by checking the checkboxes that were expected on the current page against what it actually saw on the CGI parameters, and explicitly setting any missing ones to 0.
$fm->commit_session()
Commits a session's details to disk, in the same way as CGI::Persistent. Needed by cleanup_checkboxes().
get_option_labels_and_values ($fieldinfo)
returns labels and values for fields that require them, by running a
- subroutine or whatever else is needed. Returns a hashref containing
- { labels => \@options_labels, $vals => \@option_values }
parse_options_attribute($options_field)
parses the options attibute from a field element and returns a reference to either a hash or an array containing the relevant data to fill in a select box or a radio group.
do_external_routine($self, $routine, @optional_args)
Runs an external routine, for whatever purpose (filling in default values of fields, validation, etc). If anything is in @optional_args, the routine is called using those. If @optional_args is ommitted, then $self->{cgi} is passed. Returns the return value of the routine, or undef on failure. Also emits a warning (to your webserver's error log, most likely) if it can't run the routine.
The routine is always called in the package which called FormMagick (usually main::, but possibly something else).
The CGI object is passed to your routine, so you can do stuff like $cgi->param("foo") to it to find out CGI parameters and so on.
SEE ALSO
BUGS
The validation attribute must be very carefully formatted, with spaces between the names of routines but not between the arguments to a routine. See description above.
AUTHOR
Kirrily "Skud" Robert <skud@infotrope.net>
Contributors:
Shane R. Landrum <slandrum@turing.csc.smith.edu>
James Ramirez <jamesr@cogs.susx.ac.uk>
More information about FormMagick may be found at http://sourceforge.net/projects/formmagick/
NAME
esmith::FormMagick - esmith wrapper for CGI::FormMagick
SYNOPSIS
use esmith::FormMagick;
my $f = new esmith::FormMagick(); $f->display();
my $f = new esmith::FormMagick( filename=>'/some/path/to/script' ); $f->display();
DESCRIPTION
esmith::FormMagick is a wrapper for CGI::FormMagick which automatically does all the things that we always want to do for the SMEServer manager. These include:
- Turning off unwanted buttons (previous, reset)
- Automatically clearing %ENV for taint-friendliness
- Disabling uploads through CGI.pm and setting the MAX_POST size to 100KB.
- Reading in FormMagick XML from the DATA section of the script
This last point is the most important one. In order to avoid having XML files littering the filesystem, we have chosen to include them along with the script which parses them. Your script will therefore look like
- this
my $fm = esmith::FormMagick->new(); $fm->display();
- miscellaneous subroutines, etc
DATA <form ...>
<page ...>
<field ...> ... </field> <field ...> ... </field> <field ...> ... </field>
</page> <page ...>
<field ...> ... </field> <field ...> ... </field> <field ...> ... </field>
</page>
</form>
esmith::FormMagick also provides certain convenience functions to assist in writing FormMagick web panels.
METHODS
new()
Creates a new esmith::FormMagick object. Takes an optional hash of
- arguments, including
more_lexicons a list of additional lexicon files to use charset the character set encoding of the lexicon files
(default is ISO-8859-1 (Latin1)).
Notes on lexicon files:
By default, lexicons are read in from /etc/e-smith/locale//FormMagick (general FormMagick-internal phrases) and /etc/e-smith/locale//$scriptpath (where $scriptpath is something like etc/e-smith/web/functions/useraccounts. NB: any symlinks will be traced to their source). You can append items to this list using the more_lexicons argument. Later lexfiles override earlier ones.
For debugging purposes, $fm->{lexfiles} will tell you which files were read in, and $fm->{original_xml} will show you the XML that was generated by smushing those files together.
The script will also be parsed to look for the following special coments, which are used to generate the navigation bar:
- heading : Security # description : Remote access # navigation : 1000
1200
Note on character set encodings:
Valid character sets are "ISO-8859-1", "US-ASCII", "UTF-8" and "UTF-16".
get_languages
Override for CGI::FormMagick::get_languages to only return languages which are installed on this server
_filename
Figures out the filename of the script being run, either from the arguments or by looking at the perl special variable $0.
_scriptname_from_filename
Given a filename such as that found in $0, follows symlinks and figures out the actual original filename. This is mostly used to turn /etc/e-smith/web/panels/manager/cgi-bin/whatever into /etc/e-smith/web/functions/whatever.
_lexicon_filename_list
Figures out the full filenames of all required i18n/l10n lexicons, and returns them as a list.
_read_lexicons
Given a list of lexicon filenames, reads each of them in and returns them as a concatenated string.
$fm->_navigation_setup(%args)
Sets up various properties related to the navigation menu, such as heading/description/etc. You need to pass it the same args as were passed to new(). It doesn't return anything.
$fm->get_validation_attribute
This method overrides the one in CGI::FormMagick::Validator to forcibly add "nopipes" to the list of validations performed.
$fm->props_to_query_string()
Given a hash of properties, turns them into a CGI query string. Useful for if you need to pre-populate a form based on data from the accounts or config database. See the table on the first page of the "useraccounts" web function for an example.
EXPORTED FUNCTIONS
The following exported functions may be used in your FormMagick scripts and XML, for instance as page pre-events, validation routines, etc.
turn_off_buttons()
Turns off all buttons. Useful if you want to replace the Next/Prev style of navigation with something else.
print_button('STRING')
Given a string, prints a submit button with that string localised. For instance, print_button('SAVE') will localise SAVE and put it onto the button. This is used to replace the next/prev/etc buttons with custom buttons.
set_status_message($message)
Sets the status message to be displayed at the top of the next page.
print_status_message()
Prints an status message on the first page, to give an indication of success/failure of the previous step. Resets the status message to blank and turns off all buttons as a side-effect.
description
Return the description entry read from the script, or "Unknown"
heading
Return the heading entry read from the script, or "Unknown"
description_weight
Return the description weight entry read from the script, or zero
heading_weight
Return the heading weight entry read from the script, or zero
validate_password ($strength, $password)
Checks the supplied password for security. Strength can be "strong", "normal" or "none". A "strong" password passes the cracklib tests. A "normal" password passes the tests in CGI::FormMagick::Validator::Network::password, and "none" will accept any password. An invalid argument for 'strength' is considered to be 'normal'.
validate_description ($description).
Checks the supplied description. Period is allowed in description
nopipes
Validation routine to ensure there are no pipe characters in a field. This is necessary because we don't want them to end up in the esmith configuration databases.
Note that this validation routine is automatically added to every field, so you do not have to call it explicitly.
gen_locale_date_string
Generates a date string in the preferred format for the locale.
success
This method takes a lexicon tag as argument, optionally with a page name as second argument (defaulting to 'First'), and sets the status message to the lexicon tag, and sets the next page. To make use of this, the page that the method is directing FormMagick to should have, as pre-event, the print_status_message method.
This method simply factor's all of the results of successful operations, and helps to ensure that all results end up in looping back to the start page.
error
This method is much like the above 'success' method, except it is intended for display of error messages.
It is currently identical to success(), but can be altered to yield different results, like addition of red text, or logging of the error, etc.
SEE ALSO
the CGI::FormMagick manpage
the esmith::FormMagick::Tester manpage
the esmith::FormMagick::LexTester manpage
AUTHOR
Mitel Networks Corporation
See http://www.e-smith.org/ for more information