FormEntry Definitions

Quick Links:

Each project defines an application - a set of forms generated and handled by FormEntry. Each project has a definition table associated with it. The definition table uses the same name as the maintable (where the data to be managed lives), but has an additional suffix as defined by $CFG[def_suffix] in the local_config.php file. The database connection details ($CFG[cfg_*]) for the definition table are separate from those of the live data ($CFG[form_*]). You may (and should) put the definition table name in a completely different place and with different database authorizations from those of the live data.

Definition

A definition table is created by and managed solely by FormEntry. This table is used to generate the HTML <form> the user sees. The rows, called definitions are ordered (by column id) and that order determines the order things are seen in the HTML file. The the initial definition table is generated automatically by FormEntry, as you saw in the Introduction (as seen on the right). This document will explain in detail everything you will find in a definition.

When a definition table is defined, all of the definitions (columns) will take the same defaults. This immediately gives you an almost usable form after just a little work. After creating the table, you'll want to edit each definition and make the proper changes. Start by editing a definition.


Edit a Definition

Definition Table Details

As you can see in the screen snapshot to the left, every defintion has a number of attributes you may control. The definition name ('id' in this example) cannot be modified once it has been created. If we had selected 'Add a Definition', then we could set Column (and hence Definition Name). Each of the fields in this screen relate to one of the following:

  1. Something the user sees on the screen (label, column type, text max size, select values, mouse over hint, default value, html comment). Make changes to the definition and then select 'Show Generated Form' and in most cases you'll immediately figure out how these are used.

  2. Saving the data (column type, column name). Column type is more important than you might expect.

  3. Something related to checking the data (conditions. trigger PHP code, additional flags). These are more complex and require some explaination.

You are also reminded that you can backup definitions as convenient ASCII files using Import and Export.


Column Type

Some databases are lenient when setting values for a column and can handle values whether they are quoted or not. Some are more lax, but invalid values silently fail taking new, surprising values. FormEntry requires you to explicitly set the type of data for each column:

text
means this is a simple text field and results in an HTML TEXT INPUT field.
textarea
means this is a text field and results in an HTML TEXTAREA INPUT field. Note that data in this database column could contain unprintables (especially the newline character).
numeric
means this is an integer or floating point field
select
means this is a text field whose choices are specified by the 'select values' field. Values for the drop down are specified as a comma delimited string (A,B,C) or as a comma delimited set of key=values (A=1,B=2,C=3). The first time the drop-down list will show 'Not Selected' as the item that is selected. If you mark this field as required, the user will be forced to select something from your list. If your values require a comma, you will need to replace this with a replacement character defined by the configuration variable $CFG[selectcomma]. This defauts to '%'. Thus if you provide '1,2%3,4', the drop down list will show '1', '2,3' and '4'.
selectdef
is just like 'select' except the drop-down list will default to the first item in the list.
checkbox
is a single checkbox. If checked the value for this column is provided by string found in the 'default value' field. This field will be set using a quoted string (e.g. FIELD='yes').
hidden
means this is a text field and results in an HTML HIDDEN INPUT field. This is commonly used with primary keys whose values are needed to construct the SQL to do an UPDATE, but whose value you do not want seen or changed by the <form>.
label
results in a bold-italic string and is useful to mark "sections" of the <form>.
page divider
results in a horizontal bar across most of the form. It does not actually result in a new page, since HTML does not really have the concept of a page.
sub divider
results in an italized string and is useful as a header in the <form>.
spacer
results in an empty space in the <form>.
button_link
results in a button which if clicked will result in a popup window which opens a URL. The URL is specified in the default value field.
page_link
results in a string with a <a href=""> tag which directs the browser to a new URL. The URL is specified in the default value field.

Conditions

Conditions result in Javascript routines being generated and called during the processing of the forms. The Javascript routines are invoked by the browser and can be circumvented if the user disables Javascript or the Javascript engine in the browser is not very good. You have no direct control over this. Still, it's a very good idea to check the form as much as possible at the user's end. You can find more regarding the interaction of Javascript and FormEntry here.

Nonetheless, I am the first to admit using Javascript is troublesome. Perhaps this is because I've done something poorly in Formentry. You are invited to help us all out and give me better Javascript. I've found it most helpful to enable the Javascript console and the internal tracing. The Venkman debugger is a tremendous help in sorting out Javascript problems. Javascript is evaluated from top to bottom and many times I find that an earlier error has caused the Javascript to fail - preventing a later Javascript check from actually working properly. I've come to really dislike Javascript. :-(

N .. M
says the field is a number and must fall between N and M (inclusive). N and M may be integers or floating point numbers.

'> N' or '>= N' or '< N' or '<= N'
says the field must be less then, greater than etc. than N, an integer or floating point number.

checkif(msg,v1,op1,val1[... ,v4,op4,val4]) { condition }
provides support for a common check as shown in this pseudo-code:
  if (value != '') {
    if (%sex% == 'F') { 25 .. 99 }
    else { fail('Field for women only'); }
  }
  else {
    if (%sex% != 'F') { fail('Field for required for women'); }
  }
Use this condition to handle fields which are required only if another field is set a certain way (e.g. for women only). If the field for which this condition is set is provided, then a test is made on the variable 'var'. Note that the value of 'var' must be non-blank. If it is blank, no error is generated. If this fails an error message is generated. If it does not fail, the condition specified in the {} clause will be run against the field for which this condition is set. You may specify up to triplets, so that if any are true, the condition is checked. You might code this like the following:
  checkif('Field for women only', sex, '==', 'F') { 25 .. 99 }
    or
  checkif('Menstrual cycle not set', mcycle,==,1, mcycle,==,2,) { 10 .. 50 }
If the value of this field is one or more blanks, the test will be made. If your conditions are more complex than what checkif() can do, use if(). Any commas in the values or the error message should be set of the value of $CFG[selectcomma] as specified in the local configuration file.

date(partial|yyyy-mm-dd|mm-dd-yy|mm-dd-yyyy|yyyy-mm|yyyy)
says the field is a date in various formats. 'partial' means the format must be in yyyy, yyyy-mmm or yyyy-mm-dd format,

fail(message)
generates a error message specified by the administrator which appears in the popup, just like an error about an invalid date would appear. Use this condition in if statements to fail some condition.

failifeq(msg,var1,val1[,var2,val2,...varN,valN])
is a simplified version of if(). Sometimes you simply want to condition a field based on the value of another like this:
  if (%pregnant% == 'yes' && %sex% == 'm') { fail('pregnant is only valid for women'); }
For the condition for 'pregnant', you could specify this condition:
  failifeq(Only women can be pregnant,sex,M)
    or even check two fields:
  failifeq(Women named 'Mary' cannot be pregnant,sex,F,name,Mary)
If your conditions are more complex than what failifeq() can do, use if(). Any commas in the values or the error message should be set of the value of $CFG[selectcomma] as specified in the local configuration file.

failifnoteq(msg,var1,val1[,var2,val2,...varN,valN])
is a simplified version of if(). Sometimes you simply want to condition a field based on the value of another like this:
  if (%pregnant% != '' && %sex% != 'F') { fail('pregnant is only valid for women'); }
For the condition for 'pregnant', you could specify this condition:
  failifnoteq(Only women can be pregnant,sex,F)
    or even check two fields:
  failifnoteq(Only women named 'Mary' can be pregnant,sex,F,name,Mary)
If your conditions are more complex than what failifnoteq() can do, use if(). Any commas in the values or the error message should be set of the value of $CFG[selectcomma] as specified in the local configuration file.

FEalert(string)
is not actually a condition, but is provided so you can check the values of various javascript variables. This will open up a window and write to it - allowing you to generate warnings or other messages to the user or to help in debugging your Javascript. It always fails.

if ( %col% op val ) { condition }
elseif ( %col% op val ) { condition }
else { condition }
provides a simple if-else-clause. '%col%' is the name of any definition column (e.g. id, category etc. in our example). These will be replace with the correct JavaScript variable name (e.g. %satfact% becomes form.satfact.value). 'op' is a Javascript operator like '!=' or '=='. 'val' is the string to test against. 'condition' may be any of the conditions list above as well as simple JavaScript statements (e.g. form.satfact.value=3;).

If this is clause is true, then the condition is checked for this column These statements cannot really handle complex situtations, however, you can write your own JavaScript functions and call them in a condition. Note: Nested if statements are not permitted. You may not put an if statement in a condition.

onlyif(msg,var,op,val)
is a simplified version of if(). Sometimes you simply want to condition a field based on the value of another like this:
  if (value != '' && %sex% == 'F') { fail('This field for women only'); }
    or
  if (value != '' && %sex% != "M") { fail("This field for women only"); }
Many times you only want certain field used when some other field has a particular value. The value of the field itself is not really too interesting.
  onlyif('This field for women only', sex, '==', 'F')
    or
  onlyif("This field for women only", sex, '!=', "M")
There is an implicit test of the value of the field for which this condition is set. If this field is undefined or empty, the test is made. If the value of this field is one or more blanks, the test will be made. If your conditions are more complex than what onlyif() can do, use if(). Any commas in the values or the error message should be set of the value of $CFG[selectcomma] as specified in the local configuration file.

regexp /expr/
provides a Javascript regular expression check on the field. Here is one of many sources explaining these on the web.

time(hhmm|hhmmss)
says the field is a time in 24 hour clock format.

There are several conditions which are just shorthand for certain if/then statements that occur often. Many times we only want to check a field if one or more fields are set a certain way. This table will help you keep these straight:

Function
Name
Error Mesage to Issue Operation Condition to Run Details
checkif emsg v1,op1,val1 Any of: N..M, comparisons (>N), date(), FEalert(), if/then, regexp, time() Run the condition only if the operation is true. For instance, "color,==,'red'" means only if variable color is 'red'. All operations are checked and must all be true in order to run the condition. If the condition fails, an error is raised with fail(emsg). You may specify up to four v/op/val triplets. Many times you'll want to set the proper Treat as OK values for cases when you do not want the condition run.
failifeq emsg var1,val1... No conditions are checked The field on which this is set is required if the variables specified (varN) are not equal to the values provided. If all variables are not equal, then the field must be provided (i.e. the field does not have a 'Treat as OK' value). No check is actually made on the value of the field. If the required field is not provided, an error is raised with emsg. You may specify up to four var/val pairs.
failifnoteq emsg var1,val1... No conditions are checked The field on which this is set is required if the variables specified (varN) are equal to the values provided. If all variables are equal, then the field must be provided (i.e. the field does not have a 'Treat as OK' value). No check is actually made on the value of the field. If the required field is not provided, an error is raised with emsg. You may specify up to four var/val pairs.
onlyif emsg var,op,val No conditions are checked The field on which this is set is required if the operation is true. For instance, "color,==,'red'" means only if variable color is 'red' will the field be required (i.e. the field does not have a 'Treat as OK' value). If the required field is not provided, an error is raised with emsg. Many times you'll want to set the proper Treat as OK values for cases when you do not want the operation checked like blank values.

Condition Examples

    onlyif("You must be married to have an anniversary",status,==,'married');

Sometimes you do not care what is entered, but you do wish to insure a field is not set under certain conditions. This tests first if the field being checked is empty. If so, no error will ever be generated. If it is not empty, then we check status to see if it is equal to the string 'married' (in this example), we generate the error provided. Here's a another kind of check:

    failifeq(You must set Status,status,'');

This simple example says status is blank, an error message is set. Here's a slightly more complex check:

    failifnoteq('Men must have a status of 4',status,4,sex,"M");

In this example if status is not 4 and sex is not 'M', an error message is set. Not everything can be done with onlyif(), failifnoteq() or failifeq() conditions. Here are some examples using if():

    //   Connect two fields
    failifeq('You must set Status',age,'',state,MI)

This simple example requires that both age be non-blank and state not be 'MI'. If age is blank or state is 'MI' then an error is raised. Here's a slightly more complex check:

    //   Connect two fields. Verify one field is in a range
    if (%status% == -5 || %status% == '') {
        fail("You must set Status");
    }
    elseif (%assay% < 1.0 || %assay% > 5.0) {
      fail("Assay must fall between 1.0 and 5.0");       
    }

This example ties two columns together also, but adds the additional requirement that one field fall in a range of values. I thought you could use 'else { 1.0 .. 5 }' to check the range, but it did not work and I had to add the extra check means you must do it all in Javascript.

    // For 'satfact' in our example you could do:
    if (%state% == 'MI') { 1 .. 3 }
    elseif (%state% == 'CA') { 3 .. 5 }
    else { 1 .. 5 }

This would check that 'satfact' was 1-3 when the column 'state' was 'MI', 3-5 when 'state' was 'CA', or 1-5 for any other 'state'. So if 'state' was 'MI' and satfact was 4, then this condition would generate an error.

Actually the whole if '()' clause can be more complex. It may include '||' comparisons as well like:

    // For 'satfact' in our example you could do:
    if (%state% == 'MI' || %state ==% 'CA' ) { 1 .. 3 }
    else { 1 .. 5 }

This would check that 'satfact' was 1-3 when state was 'MI' or 'CA', or 1-5 for any other state.

Treat As OK

This field provides a set of values the field may take which should be treated as OK. Often times a field which is not of interest at the moment could have several valid, but uninteresting values like '' (the null string), 'N' (no), or 0 (zero). Specify all such values as a blank-delimited string. Use the word 'blank' to mean the null string. You may not specify a value with an imbedded blank.

Default Value

This field provides the default value which will appear in the form, unless the field is already set. A few short cuts are provided to make this more convenient:

%date%
Specifying this string will generate the current date as a string in the format YYYYMMDD.
%date-%
Specifying this string will generate the current date as a string in the format YYYY-MM-DD.
%date/%
Specifying this string will generate the current date as a string in the format YYYY/MM/DD.
%time%
Specifying this string will generate the current time as a string in the format HHMMSS.
%time:%
Specifying this string will generate the current time as a string in the format HH:MM:SS.
%user%
Specifying this string will provide the value of the current user - if the page is using .htaccess (or similar) access control.

Additional Flags

The additional flags field controls the behavior associated with this definition. Valid values for these flags are:

Auto-increment
indicates this field is generated automatically by the database.
Contains HTML
specifies the field contains HTML and should have all characters translated into their respective HTML entities. For instance if the field contains '<', this will be translated into '&lt;' so your browser will display this correctly.
Ignore Column
makes sure that this column is never shown
Javascript Validation
allows one to enable or disable the Javascript check for a column.
Meta Chars
specifies the field contains unprintable characters like newlines, carriage returns and tabs which should be translated into their escaped form (e.g. newline becomes '\n') before being put in the database. They will be translated into their normal format '\n' (e.g. a newline character) when shown in the form. Realize that on a web form, all 'newlines' are DOS/Windows newlines - a carriage return followed by a newline (i.e. \r\n).
No Changes
shows the column in the form, but provides not HTML controls to allow this to be changed.
Primary Key
You want to be sure this is checked for the column which is the primary key. Failure to have a primary key will prevent the <form> from working properly.
Required
setting this will enable Javascript checks to ensure this field has some sort of value You may not check both BlankOK and Required.
Searchable
setting this flag will make this column appear on the search menu. You may search more than one field.

Once in a while a new release of FormEntry will introduce new flags which will not exist in your definition tables. This will cause an error when you attempt to edit a definition like this:

There is a column missing from the definition table. Maybe this is from a previous release? Be sure your database tables are backed up and then do an Export Definitions for the project and then Import Definitions.

As the message implies, your definition table needs to be updated. By far the easiest method is to 'Export' and then 'Import' the defintions for this table. See here for more details on this process.

Trigger PHP Code

After the Javascript checks have been run, the <form> data is delivered to the web site for the script where yet one final set of checks can be run - so called triggers. These are analagous to database triggers. Triggers are PHP code provided by the installation and run inline as the data is processed. In order to use triggers you will need to know about the conventions for the variables:

    //  Example 1:  Call a subroutine I wrote
    if ($val > 20) {     
        TriggerMsg("Value '$val' is pretty high for '$col'");
    }   

    //  Example 2:  Call a user subroutine saved in the project file
    $err = Verify_Studyid($col, $val);

    //  Example 3:  Check relationship between two fields
    if ($ROWDATA[deaddate] && (! $ROWDATA[dob])) {
        $err = "Date of death specified without a date of birth";
    }
    if ($ROWDATA[deaddate] && $ROWDATA[dob] &&
    $ROWDATA[deaddate] <= $ROWDATA[dob]) { 
        $err = "Date of death ($ROWDATA[deaddate]) must come after date of birth ($ROWDATA[dob])";
    }     

Quick Links:



Direct questions to: Terry Gliedt tpg@hps.com (Include 'Formentry' in the subject line so my SPAM filter lets your message through.)

This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. See http://www.gnu.org/copyleft/gpl.html