RazorForm User Guide

Introduction

RazorForm is a robust PHP library aimed at taking the grunt work out of dealing with HTML forms. Using a familiar HTML-like syntax, you tell RazorForm what fields you want in your form and what properties you want those fields to have, and RazorForm does the tedious stuff for you.

Among the tedious stuff about HTML forms is the need to make each input field and each row have the same look and feel. For this task, RazorForm generates HTML that includes a consistent and sensible arrangement of CSS elements. So most of the form's appearance is taken care of by simply creating style definitions for the CSS elements already in place after the form has been generated by RazorForm.

Another very common and tedious task is form validation. Usually, this means creating the form, having separate scripting that checks the user's input, and including code for each input field that shows the field's label differently (hightlighted in red, for example) if that field had an error. In RazorForm, you can specify that a field is required, must be a certain number of characters, must be the same value as that of another field (useful for password fields), or even must match a PHP regular expression that you define. For any error, you can specify the text of an error message that is displayed to the user. If a field has an error after submission, RazorForm simply changes the CSS elements associated with the field to be those that reflect an error. If the form designer has specified different styles for the error elements, the input field's display is affected as desired. You can also create a PHP function that does your own custom error checking, and RazorForm will call it internally, adding any error messages your code generates to that field's list of errors.

In addition to these features, RazorForm provides a slew of useful little conveniences to make the task as not-annoying as possible. For example, you can have the form definition in a separate file that both programmer and page designer have access to. Or you can set which character(s) will be globally used to separate the field labels if there are more than one field in a row (perhaps a comma followed by a space). Or you can arbitrarily create variables at the top of the form definition that will be used by various elements later on, for example, a variable that holds a size to be used by input fields that aren't the default size. There's even an object-oriented interface to RazorForm, so you could do this all programmatically.

RazorForm at a Glance

RazorForm's syntax is very similar to HTML, so you should not have a difficult time creating simple forms from the start. Here's a sample RazorForm definition for a small form:

        <RazorForm action="myform.php" method="post">
            <row>
                <input type="text" name="usr" label="Username" req>
            <row>
                <input type="password" name="pwd" label="Password">
            <row>
                <input type="submit" value="Login">
        </RazorForm>
        

This defines a form that will have two input fields - usr and pwd - and a submit box, each on its own row. The fields will have their more human-friendly labels to the left of the input boxes, and the submit box will be labeled "Login". Because of the "req" in the usr field, if error checking is being used and the form is submitted without a value for usr, the form will come back with an error for the usr field.

Even in this simple case, there are already some advantages over doing this with RazorForm instead of just normal old HTML.

First, the HTML that will be generated will include certain CSS elements for each element in the form. So the resulting code for the Username row will look like this:

        <tr class="form-row">
            <td class="field-lab-cell" valign="top">
                    <div class="field-lab">Username</div>
            </td>
            <td class="field-cell">
                <div class="field-block">
                    <div class="field"><input type=text name="username"></div>
                </div>
            </td>
        </tr>
        

You'll notice that there are various CSS classes being used here: form-row, field-lab-cell, etc. To alter the look of your form, just assign definitions to these classes as you normally do with stylesheets (either in a <style> tag or a separate stylesheet file). These classes and their roles will all be described in greater detail below.

The second obvious benefit is that there is built-in form validation. Since we defined the usr field as required (using "req"), if a user submitted this form with that field empty, the CSS classes for the usr field would be altered: "field-lab" would be "field-lab-err", and "field" would be "field-err". So if "field-lab-err" had a style definition that set the text color to be red, the label "Username" would show up in red instead of black.

Basic Usage

To use RazorForm, you must first include the file RazorForm.php in your PHP page or script. Then you call the RazorForm class's constructor, usually passing the RazorForm definition, all a big string, to it as an argument. So the simple form above would actually look like this in the PHP file:

        <?
        $formdef = <<<EOS
        <RazorForm action="myform.php" method="post">
            <row>
                <input type="text" name="username" label="User" req>
            <row>
                <input type="password" name="password" label="Password">
            <row>
                <input type="submit" value="Login">
        </RazorForm>
        EOS;

        include("RazorForm.php");
        $rf = new RazorForm($formdef);
        $rf->check_errors();
        ?>

        <html>
        <body>

        <? $rf->get_form(); ?>

        </body>
        </html>
        

Note the PHP heredoc syntax, with the <<<EOS and the EOS;. If you are unfamiliar with that syntax, see the doc on PHP strings (in the PHP Manual under Language Reference > Types > Strings). You don't have to use the heredoc syntax - the RazorForm definition is just a string and you can create it however you want. I like heredocs because they won't conflict with whatever arrangement of single or double quotes I feel like putting into the form definition.

The method $rf->get_form() spits out the entire form. It accepts an optional argument of true or false (default true), telling it whether or not to include the <form> and </form> tags.

Note the line $rf->check_errors();. This is an optional line that tells RazorForm to validate the input the user has submitted against any error-checking conditions specified in the form definition. In this case, the only condition is the req attribute on the username field, which means that field is required. The check_errors() function knows not to try error checking on any first page views; it will only do it on POSTs or GETs. Leave this line out to disable form validation. More on error checking later.

NOTE: I'll be using the imaginary object $rf as a generic object of type RazorForm from here on out. There is, of course, no obligation that your RazorForm object be named $rf. You could call it $bob if you wanted to.

A Word About Layouts

As I was writing this utility, I did my best to leave everything related to the visual presentation of the form up to the stylesheets. Unfortunately, there are some things that are just not practical to try to accomplish with CSS in the generic way that this utility is trying to make possible. I've found that it's relatively easy to change the elements' colors, borders, font sizes, and the like with stylesheets. But things like the relative positioning of one element to its neighbor, whereas possible, are a cumbersome duty to leave up to the stylesheet author to try to handle.

Enter the RazorForm notion of layouts. A layout defines where the form elements are in relation to one another. It also makes certain decisions about the functionality related to how things are positioned.

For example, in the default layout, the whole form is put together in a traditional HTML table, with each RazorForm row being a <tr>. In each row, the field label is in the left <td> and the field itself is in the right <td>. If there is more than one field in a given row, all the field labels for that row are listed in the left <td>, separated by the value of the label_sep setting, unless the RazorForm row itself has a label specified, which will override the list of the field labels.

The thing to keep in mind is that the form doesn't have to come as a big HTML table - it could be an arrangement of <div>s and <span>s. That's the job of the layout to decide. Likewise, the field labels wouldn't have to be all listed together if the layout wasn't set to do that - it could have just the first one in the left cell and the rest next to their input boxes in the right cell. Or whatever it was set to do.

There will be more on layouts later on, including what layouts are available and how you can define your own layouts. Right now I just wanted to prep you for the times coming up when I'll say something could be one way or another based on the layout you're using.

The other thing to remember about layouts is that if you usually just have HTML forms with field labels to the left of the input boxes, you may never have to use an alternate layout or know anything about them whatsoever.

Incidentally, to change the layout from the default, you just specify it as an attribute in the <RazorForm> tag, like this:

        <RazorForm action="foo.php" method="post" layout="labels_above">
        

The RazorForm Definition

The RazorForm definition is where you tell RazorForm what you want to show up in your form. It is made up of tags delimited by the right and left angle brackets, just like HTML. The form definition must start with a <RazorForm> tag and end with a </RazorForm> tag and contain only other valid RazorForm tags in between. Unlike HTML, everything in a RazorForm definition must be inside of a tag. The tag must start out with the tag name, like row or input, and can then be followed with attributes and possibly values for those attributes. For example:

        <input type="text" name="foo" req>
        

input is the tag name, type and name are attributes, text and foo are values for those attributes, and req is a valueless attribute.

As of the current iteration of RazorForm, all RazorForm tag names are case sensitive. This applies only to the tag names themselves (i.e. the first word in the tag), not the attributes or their values, which can be capitalized however you want. The <RazorForm> and </RazorForm> tags are as shown, with the R and the F capitalized. All other RazorForm tags are lower case. So, for example, this works:

        <input type="text" NAME="foo">
        

and this doesn't:

        <INPUT type="text" NAME="foo">
        

In RazorForm, the only closing tag (i.e. one that begins with a slash and is the terminating couterpart for a previous tag) that exists is the </RazorForm> tag. All other tags operate with the idea that they are associated with the most recent higher-level tag. For example, once you make a <row> tag, any <input> tags coming thereafter will belong to that row, until you create another <row> tag. The <option> tags following an <input> tag of type select or multiselect will likewise belong to that input field, until another <input> tag is encountered.

Like HTML, whitespace is ignored in RazorForm. In my examples, you'll see that I like to indent things a certain way, but that's just for the organization of the code - it doesn't affect the output of the form.

The <input> Tag

The <input> tag in the RazorForm definition corresponds to an input field that will show up in the HTML output. As mentioned above, any <input> tag will be associated with the most recent <row> tag that was defined.

There are attributes of <input> tags that have special meaning to RazorForm, and these will be discussed in the next several sections. Any attributes that do not have special meaning will be passed along as is to the HTML input field. So you can put anything into a RazorForm <input> tag that you would normally put into an HTML <input> tag.

The one exception is the value attribute. In HTML, this is used to specify the default value of an input field, before the user changes anything. The problem with using this attribute in a RazorForm input tag is that you don't always want RazorForm to put a "value=whatever" string into the HTML input tag - you only want that on the first page load, and after that, it's whatever they've submitted. So RazorForm actually blocks usage of the value attribute on any input field with which this conflict would arise. Wherever you would use the value attribute in a normal HTML form to set a default value that might be changed by the user, in RazorForm you use the appropriately-named default attribute. You may, however, (and sometimes should) use the value attribute on input fields of type hidden, submit, or image, as these will never be changed by the user.

In HTML, there are separate tags for different types of inputs, i.e. input, select, textarea. This is not the case in RazorForm. All inputs get an <input> tag, and what sort of input they are is determined by the value of their type attribute. The possible values for the type attribute are text, password, select, multiselect, textarea, checkbox, radio, static, submit, image, and hidden. With the exception of a few things you're not used to, these behave pretty much just as you'd expect. A few examples:

            <input type="text" name="foo" default="foo foo foo" size=15>
            <input type="textarea" name="stuff" rows=4 cols=40>
            <input type="checkbox" name="blah" default="checked">
            <input type="hidden" name="floo" value="floofy">
            <input type="submit" value="Go!">
            <input type="image" src="submit.jpg" width=100 height=20>
            

Inputs of type hidden are the only inputs in a RazorForm that are allowed to be defined before the first <row> definition and therefore not be associated with a particular row. If you define any hidden inputs after the <RazorForm> tag and before any <row> tags, these inputs will show up in the HTML after the <form> tag but before the start of the form table (which could be a <table> or a <div>).

You might have noticed the multiselect type, which isn't a normal HTML thing. A RazorForm input of type multiselect will come out in the HTML as a <select> tag with the multiple attribute set, and will therefore allow the user to choose more than one value from a list. Whatever you name this input (i.e. with "name=foo") should have the opening and closing square brackets required for PHP to read the submitted value as an array. For example:

            <input type="multiselect" name="foo[]">
            

If you don't supply the [], RazorForm will do it for you. Which might cause problems if you are otherwise relying on the name of that field to be without the brackets. So it's best to be conscientious in always putting them in explicitly.

RazorForm also supports the normal PHP behavior of using [] to indicate to PHP that an input can have multiple values even when that input isn't of type multiselect. Thus, you can have multiple input fields with the same name and different values, even different types, so long as the name ends with []. For example:

            <row>
                <input type="text" name="keywords[]" label="Keyword #1">
            <row>
                <input type="text" name="keywords[]" label="Keyword #2">
            <row>
                <input type="select" name="keywords[]" label="Keyword #3">
                    <option value="linux" display="Linux">
                    <option value="freebsd" display="FreeBSD">
                    <option value="php" display="PHP">
                    <option value="python" display="Python">
                    <option value="perl" display="Perl">
            

You might also have noticed the static input type, which isn't found in the HTML your parents taught you about. Inputs of type static aren't really input fields at all; they're just static html text in the place where the input field would be. This is useful for those times when you have a value for some field in your form that you want to display but not allow users to alter. I put it in as an "input" even when it's really not because sometimes you have a field that will sometimes be an input and sometimes static. This way, you can put it into your form definition as a normal input, and just change its type when you want to alter whether it's static or not. You could do this with the object oriented interface (ex. $input->set("type", "static");) or with a PHP variable in the place of the type value in the <input> tag. One thing to note about static inputs: the label and value attributes are meaningful because you want those things displayed, but the other attributes are not - you don't need size, req, (etc.) or even name in order to simply display the text on an HTML page. Feel free to put such things into the <input> tag (for example, when you might be switching types back and forth), but they'll be ignored.

I'm toying with the idea of a couple of enhancements to the static input type. Some people might prefer to have their static input fields show up as actual input boxes but using CSS or perhaps JavaScript to prevent the altering thereof. I haven't looked into whether you could even do this with CSS, but if so I might make it the default or I might make it an attribute of the input tag to indicate whether to show it as a box or not. If you absolutely have to have it that way now, you could do it with a layout object of your own creation, by checking if an input is of type static and putting the output of $input->get_input() as the value in a tag that you create by hand. You'd have to get that input's attributes and put them in the tag as well if you wanted them to show up. I hope it's apparent that this approach is definitely a hack, because the layout object should not have to deal with any of that stuff. About doing the static-but-still-in-a-box idea with JavaScript, I won't do it if it has to be done with JavaScript, as you can do that already by just using a normal input box and writing your JavaScript to prevent the alteration. The other idea I had is to maybe make a static-hidden type or some other way of having a static input show up in the normal way but also include a hidden input behind the scenes. As it stands, you have to put both in there by hand if you want something passed to the processing script as well as shown as static text.

Inputs That Take Options

The input types select, multiselect, and radio all accept a list of options. Whereas in HTML the syntax is different for selects and radio buttons, in RazorForm the syntax is the same. After the input tag, you specify any number of <option> tags, each with a value attribute and a display attribute. Both value and display are required for each option. Every option is associated with the most recent input field defined before it.

To specify the default value for an input with a list of options, use the default attribute, with a value matching the value (not display) of one the options in the list. Since mutliselects can take multiple values, it can also accept multiple defaults. This is done with the array syntax: the keyword array, a left parenthesis, a comma delimited list of quoted values, and a right parenthesis. The following form exemplifies the use of inputs with options lists:

                <RazorForm action="myform.php" method="post">
                    <row>
                        <input type="select" name="icecream" default="trs">
                            <option name="rr" display="Rocky Road">
                            <option name="trs" display="Tin Roof Sundae">
                            <option name="neo" display="Neopolitan">
                    <row>
                        <input type="multiselect" name="candy" default="array('ddc', 'os')">
                            <option name="ddc" display="Dove Dark Chocolate">
                            <option name="cb" display="Cinnamon Bears">
                            <option name="os" display="Orange Slices">
                            <option name="sni" display="Snickers">
                    <row>
                        <input type="radio" name="drink" default="lem">
                            <option name="cm" display="Chocolate Milk">
                            <option name="soda" display="Soda">
                            <option name="lem" display="Lemonade">
                </RazorForm>
                

This is probably a good place to mention a useful piece of information about radio buttons in RazorForm. Sometimes you want radio buttons to be lined up horizontally next to one another, and sometimes you want them lined up vertically on top of one another. To give you the ability to choose which of these you want, there is a CSS class called radio-div. Each radio button and its label will be enclosed in a div of this class. This is explained in more detail in the section on CSS Classes.

Built-in Option Lists

RazorForm provides you with various built-in lists of options for commonly needed selections. You can use these built-in option lists for any <input> that takes a list of options, instead of specifying the list explicitly. You do this with the options attribute and the builtin keyword, as in this example:

                    <input type="select" name="state" options="builtin:states">
                    

Here are the current possible values for the builtin keyword:

  • monthdays. A list of days in the month, from 1 to 31. The values of options 1 through 9 are each padded with a leading 0, like so: 01, 02, 03, etc. The displays are not padded.
  • weekdays. A list of days in the week, starting with Sunday. The values are the first 3 characters of each word, lowercased, like so: sun, mon, tue, etc. The displays are the full words with the first letter capitalized.
  • months. A list of the 12 months of the year. Values are (zero-padded) numbers from 01 through 12. Displays are the full names of the months with the first letter capitalized.
  • states. A list of states in the USA. Values are 2-character abbreviations, capitalized, like so: AL, AK, AZ, etc. Displays are the full names of the states, with first letters capitalized. This list includes the District of Columbia. (I am neither for nor against DC statehood; I just think it makes sense to have it in the list.)
  • states_only. The same list as states, but without DC.
  • states_ext. The same list as states, but with the other US territories included.
  • countries. A list of all the coutries in the world. Values are 2-character abbreviations. Displays are the full country name, with first letters capitalized.

If you can think of anything else that should be in this list, feel free to put it together and email it to me. Please send it to me in the form in which the builtin_* functions are at the bottom of RazorForm.php, from the function keyword down to the closing "}". Also send me a blurb for the above list.

Likewise, I'm open to corrections in the countries list. I'm not a geography buff, and I have no idea if that list is accurate or appropriately represents the current state of the globe.

Labels

The label attribute of rows and input fields is what is visibly displayed to the user to tell them what the row or field is. The syntax is the same as any attribute inside a tag:

                <input type="text" name="phone" label="Home Phone">
                
                or

                <row label="Email Address">
                

As mentioned above in the section A Word About Layouts, there is usually some internal logic to arrive at exactly what the label will be, and some of this logic is left up to the layout to decide. For example, in the default layout, if a <row> tag has no label attribute explicitly set, the label that will show up will be the concatenated labels of the fields in that row. Because RazorForm does this concatenation for you, it's usually best to specify input field labels and leave the label attribute out of the <row> tag, unless you have a specific need where you don't want the individual field labels to be the label of the row. An example of when you might want to do that would be in the case of a date, where you would want the row to be labelled, say, "Birthday", and the fields themselves to be labelled "month", "day", and "year". You would accomplish this by specifying a row label and labels for each of the fields, and the logic built into the default layout knows that in that case it would show the explicit row label for the whole row, and the individual field labels right next to their fields.

This internal logic may also include the insertion or appending of certain characters based on the values of the following three attributes:

  • label_sep. When a row has more than one input field and no explicit row label, the row's label will usually be a concatenation of all labels specified for the individual input fields. Whatever you specify for the label_sep attribute will be what shows up between the individual input fields' labels. A common value would be a comma followed by a space. So if a row had three fields with labels City, State, and Zip, and the label_sep was set to "--", the label that showed up for that row would be "City--State--Zip". Note that this feature is determined by what layout you're using. The default layout behaves this way but others might not use the label_sep at all if it didn't make sense for them.
  • row_punc. The value of this setting is appended to all row labels, whether explicity stated or created as a concatenation of the labels for the fields in that row. A common value would be a single colon.
  • input_punc. The value of this setting is appended to the label of an input field, but only when that label is right next to the input field itself and not being used as a part of a concatenated row label. Suppose you had a row with an explicit row label of "Birthday" but you also wanted each input field to be labeled with "month", "day", or "year". In the default layout, if you specify an explicit row label as well as individual labels for the input fields themselves, the labels will show up next to their inputs with the value of input_punc appended.

Setting Form-wide Defaults with the <default> Tag

You can use the <default> tag to create default values for attributes used by the rows and input fields throughout the form. Note: don't confuse this with the default attribute itself which can be set on individual input fields to specify what the initial value of that field will be pre-set to for the user. This feature is for setting useful attributes for the whole form so you don't have to set them individually by hand on each row or input. This tag may only appear after the <RazorForm> tag and before the first <row> tag. Here are the possible attributes you can set with the <default> tag (some are also covered above in the section on Labels):

  • label_sep. When a row has more than one input field and no explicit row label, the row's label will usually be a concatenation of all labels specified for the individual input fields. Whatever you specify for the label_sep attribute will be what shows up between the individual input fields' labels. A common value would be a comma followed by a space. So if a row had three fields with labels City, State, and Zip, and the label_sep was set to "--", the label that showed up for that row would be "City--State--Zip". Note that this feature is determined by what layout you're using. The default layout behaves this way but others might not use the label_sep at all if it didn't make sense for them.
  • row_punc. The value of this setting is appended to all row labels, whether explicity stated or created as a concatenation of the labels for the fields in that row. A common value would be a single colon.
  • input_punc. The value of this setting is appended to the label of an input field, but only when that label is right next to the input field itself and not being used as a part of a concatenated row label. Suppose you had a row with an explicit row label of "Birthday" but you also wanted each input field to be labeled with "month", "day", or "year". In the default layout, if you specify an explicit row label as well as individual labels for the input fields themselves, the labels will show up next to their inputs with the value of input_punc appended.
  • lab_cell_valign. I couldn't get the vertical alignment of the row labels to work right with CSS. So lab_cell_valign accepts all possible values of a normal HTML <td> and will determine the vertical alignment of the cell that contains the row label.
  • layout. Sets the layout to be used throughout the form. Note that the layout is actually applied on a row-by-row basis, so you can use this feature to set a default layout but then change a particular row's layout by adding a "layout=alt_layout" to the <row> tag for that row.

Besides the above, you can specify anything else you want to be handed to all input fields as a default attribute. This only applies to input fields, not rows, or options for selects. If you create a <default> tag that doesn't have special meaning to RazorForm (as the above values do), it will just take that attribute and its value and hand them off to all input fields almost indiscriminately. I say almost indiscriminately because RazorForm is smart enough to know that certain attributes would be meaningless to certain input fields and won't pass those along. So this feature makes the following attributes possible:

  • size. Set a default size for all text input fields. This will not be passed to textareas, selects, multiselects, or any other type of input field to which a size attribute is meaningless (which I think is all of them).
  • maxlength. All text input fields will get this value for maxlength unless otherwise specified. Will not be passed on for other types.
  • rows and cols. All textarea input fields will get these values set unless specified differently in the <input> tag for a given textarea. Will not be set for other types of input fields.
  • checked. All checkboxes are checked by default if you create a <default> tag with this attribute and the value of "yes", "on", "true", or "checked".
  • errmsg. This one isn't rejected by any input fields, so all fields would get this as the error message in case something was wrong with a user's submitted value for a given field, and no other error message was provided in the <input> tag. A sensible value might be something like "Required field."

Remember that you could use this feature to create defaults for anything else you wanted, not just things from either of the above lists. Just keep in mind that anything you do create will just be passed along to all input fields, which may or may not be what you really want.

Here's an example of the first part of a RazorForm definition that sets up a default size for all text input fields and a default error message for all fields:

            <RazorForm action="myform.php" method="post">
                <default size=20>
                <default errmsg="Required field">
                <row>
                    <input type="text" name="firstname">
                <row>
                    <input type="text" name="lastname" errmsg="Last name goes here.">
            

In this example, both the firstname and lastname fields would have a size of 20. firstname would get the default error message "Required field", but lastname would use its own error message that overrode the default.

Form Validation

RazorForm has a powerful built-in system for validating the input a user has entered in a form. In the <input> tag for any field, you can include attributes that tell RazorForm to check the user's input against certain conditions, some of which are stock with RazorForm, and some of which you specify yourself.

RazorForm always generates form HTML with a standard set of CSS elements for which you can set styles in the normal way. If a given input field has an error after the user's submission, RazorForm signifies this by simply replacing the normal CSS selectors with those associated with errors. If you've defined styles for the "error" selectors that are different from the normal styles, form elements with errors will show up differently than those without.

Specifically, there are two selectors that will be different if a field has an error. Normally, the field's label will be enclosed in a div of class field-lab, and the input field itself will be enclosed in a div of class field. For fields with errors, the label will be enclosed in a div of class field-lab-err, and the field itself will be enclosed in a div of class field-err. (More on the various CSS selectors later.)

Let's take a look at a form with some error checking. Here's the entire file for such a form:

        <?
        $formdef = <<<EOS
        <RazorForm action="myform.php" method="post">
            <row>
                <input type="text" name="username" label="User" req>
            <row>
                <input type="password" name="password" label="Password">
            <row>
                <input type="submit" value="Login">
        </RazorForm>
        EOS;

        include("RazorForm.php");
        $rf = new RazorForm($formdef);
        $rf->check_errors();
        ?>

        <html>
        <body>

        <style type="text/css">
        .field-lab { color: green; }
        .field input { background-color: lightgreen; }
        .field-lab-err { color: red; }
        .field-err input { background-color: pink; }
        </style>

        <? $rf->get_form(); ?>

        </body>
        </html>
        

This example uses the most basic of the form validation attributes, req, which in this case tells RazorForm that at least something must be provided by the user for the username field. After the RazorForm object has been constructed, we call the $rf->check_errors() function, which tells RazorForm to do the form validation. $rf->check_errors() returns the number of errors encountered in the form, so you can use that number for your own purposes, including perhaps to determine whether or not to display the form again.

Notice that we defined CSS styles for the classes field-lab and field-lab-err, and for input fields inside of containers of classes field and field-err. These are defined as normal, with no interaction with RazorForm. That's because RazorForm doesn't care about styles here; all it cares about is telling the browser which styles to use. If there is no error on the username field, its generated HTML will look like this:

        <tr class="form-row">
            <td class="field-lab-cell" valign="top">
                    <div class="field-lab">User</div>
            </td>
            <td class="field-cell">
                <div class="field-block">
                    <div class="field"><input type=text name="username"></div>
                </div>
            </td>
        </tr>
        

If there were an error with username, it would look like this:

        <tr class="form-row">
            <td class="field-lab-cell" valign="top">
                    <div class="field-lab-err">User</div>
            </td>
            <td class="field-cell">
                <div class="field-block">
                    <div class="field-err"><input type=text name="username"></div>
                </div>
            </td>
        </tr>
        

Notice that it's all exactly the same with the exception of the field-lab-err and the field-err classes. Because of the styles we defined in the HTML itself, the non-error example would show up with green label text and a light green background on the input box, and the error example would show up with red label text and a pink background on the input box.

The only other thing RazorForm does with an input field that has an error is display any error message you might have specified with the errmsg attribute following a form validation attribute. This will be discussed in detail in the errmsg section below.

RazorForm is smart enough to not attempt validation on the first time the page is displayed to the user. It does this by generating a hidden input with the name rf_subsequent and value true. This is generated by $rf->start_form() for all forms. Keep this in mind if you ever have a need to submit a form to be processed by RazorForm but that was not generated by RazorForm. In that case you'd need to put the rf_subsequent field in yourself.

The re Attribute

The re attribute allows you to specify a PHP regular expression for the pattern that the user's input must match. The regular expression is the value of the re attribute. As is usually the case with regular expressions, this feature provides you with about as much fine control over the input as you could want, but also requires an understanding of the complicated regex syntax. Here are a couple of examples of this feature in action:

            <input type="text" name="foo" re="/x/">
            <input type="text" name="phone" re="/^\(\d{3}\)\d{3}-\d{4}$/">
            

The foo field would have to have an x in it, and the phone field would have to have to be in the fomat left paren, 3 digits, right paren, 3 digits, hyphen, 4 digits (by the way, I wouldn't recommend doing a phone field with that exact regex because you'd want to include support for arbitrary spaces and international area codes longer than three digits, etc; this was just for example).

The regex will be matched against using the PHP Perl Compatible Regular Expression (PCRE) functions - the ones starting with preg. As such, it must be enclosed in the required delimiters, usually forward slashes, and must adhere to all other PCRE requirements. For more on PHP regular expressions, see the PHP manual section on Perl-compatible regular expressions.

The sameas Attribute

The sameas attribute requires that an input field's value must match the value of another input field. The name of the other field is specified as the value of the sameas attribute. The most common case where this would be useful would be for passwords that must be entered twice because they're invisible. For example:

            <input type="password" name="pwd1" label="Password">
            <input type="password" name="pwd2" label="Re-Enter Password" sameas="pwd1" errmsg="passwords don't match">
            

I had to make a decision about the best way to implement this feature, and you should keep in mind a couple of idiosyncracies about the sameas attribute. When you specify that a field must match another one, both fields will show an error condition (i.e. will have the "err" CSS selectors instead of the normal ones), but only the one with the sameas attribute will have the error message. I did it this way because the only usual case I can think of for using the sameas attribute would be password fields, and password fields will normally be one right above the other, or otherwise adjacent. It seems ugly to have the error message on both fields when they're right next to each other, but it does seem sensible to have both of them showing up with the error styles. So in the example above, if you had specified red styles for fields with errors, both pwd1 and pwd2 would show up red, and the error message "passwords don't match" would show up underneath the pwd2 field (if you're using the default layout). For this reason I think it makes sense to put the sameas attribute on the second field instead of the first.

The function Attribute

You can use the function attribtue in conjuction with your own PHP code for validating a user's input for a field. The value you specify for the function attribute must be the name of a PHP function in a scope callable by the RazorForm object, which usually just means in the same file you're doing your form in.

The function you create must accept a single argument of the input field's value as supplied by the user. You're free to use the value as passed by RazorForm or get it from the POST yourself; it's all the same.

The function must return one of the following values:

  • true, meaning an error occurred (and the error message to display will be the corresponding errmsg attribute from the field's <input> tag).
  • A single string, meaning an error occurred and this string will be used as the error message.
  • An array of strings, meaning at least one error occurred, and all strings in the array will be displayed as error messages. (The layout being used will apply its own logic for displaying multiple error messages.)
  • false, meaning no error occurred.

Here's an example page with an error-checking function:

            <?
            function check_foo($val) {
                if ($val != "blah")
                    return "foo should have been 'blah'";
                else
                    return false;
            }

            $formdef = <<<EOS
            <RazorForm action="myform.php" method="post">
                <row>
                    <input type="text" name="foo" function=check_foo>
                <row>
                    <input type="submit" value="Go">
            </RazorForm>
            EOS;

            include("RazorForm.php");
            $rf = new RazorForm($formdef);
            $rf->check_errors();
            ?>

            <html>
            <body>

            <? $rf->get_form(); ?>

            </body>
            </html>
            

If you specify an errmsg attribute (discussed in detail below) after the function attribute in the field's input tag, this errmsg will be displayed in addition to whatever message(s) the function returns. So if the tag in example above were like this:

            <input type="text" name="foo" function=check_foo errmsg="bad foo">
            

The error message would include both the "foo should have been 'blah'" from the check_foo function and the "bad foo" from the input tag. And as mentioned above, if the check_foo function were to return only true for an error, then the only error message displayed would be the "bad foo" from the tag.

Customizing the Look and Feel of Your Form

There are two main ways of making your form look the way you want it to: CSS styles and RazorForm layouts. CSS is used for colors, borders, font sizes, margins, and the like, and is probably what you'll deal with most frequently. Layouts are in charge of the positioning of the elements in relation to one another as well as some logic for what to show where, and you're not likely to deal with them much on a day-to-day basis, besides perhaps setting once the layout to be used by the whole form.

CSS Classes

Every HTML form that RazorForm generates comes with a standard set of elements with CSS classes specified. In the current incarnation of RazorForm, all of the elements are <div>s. (There are cases where you'd likely want a <span> instead of a <div>, and you can easily make a div behave just like a span with display:inline in its style definition.) Consider the following form:

            <RazorForm action="myform.php" method="post">
                <row>
                    <input type="text" name="foo" label="Foo">
            </RazorForm>
            

This form would be sent to the browser as such (not including the <form> tags and the other invisible setup stuff):

            <table class="form-table">
            <tr class="form-row">
                <td class="field-lab-cell" valign="top">
                        <div class="field-lab">Foo</div>
                </td>
                <td class="field-cell">
                    <div class="field-block">
                        <div class="field"><input type=text name="foo"></div>
                    </div>
                </td>
            </tr>
            </table>
            

If you wanted to customize the way the form looked, all you would have to do would be to define styles for the classes in the output. You could put something like this into the HTML:

            <style>
            .form-table {
                background-color: tan;
            }
            .form-row td {
                border-bottom: 2px solid black;
            }
            .field-lab {
                color: maroon;
                font-weight: bold;
                font-size: x-small;
            }
            .field input, .field select, .field textarea, .field checkbox {
                border: 1px dashed maroon;
            }
            </style>
            

It probably wouldn't look very good, but you could do it. You might have noticed that I put the border on the tds which are in rows of class form-row. That's because I can't seem to get styles for table rows working the way I want them to.

Something you should be aware of here is that the layout you're using will often set up its own styles for some of these elements, and they will override yours. But this should not be a problem because the layout should keep its style definitions strictly to properties that affect where something is positioned and should therefore not conflict with anything you would want to put into your style definitions.

You should also be aware that certain decisions about what classes will be used are left up to the layout to decide. So it's possible for a layout to not have need for some class, in which case it wouldn't make any difference if you defined a style for that class. Check the documentation on the layout you're using to see which classes it uses.

Here's the breakdown of all the CSS classes and their roles in the form:

  • form-table. The form table itself, which might be an HTML table or might be an arrangement of divs and spans, depending on the RazorForm layout being used. For the default layout, it's an HTML table.
  • form-row. The form row, which might be a <tr> or might be a <div>, depending on layout. For the default layout, it's a <tr>.
  • field-lab-cell. The table cell containing the input field's label. If there is more than one label, they will usually all show up in this cell. May be a <td> or may be a <div> depending on layout. For the default layout, it's a <td>.
  • field-lab. A div surrounding each individual field label. If there are more than one fields (that have labels) in a row, each will be enclosed in a div of this class. Note that certain situations cause the labels to be right next to their input boxes (in the "field-cell"), and these labels also will be enclosed in divs of this class.
  • field-lab-err. Same as field-lab but used in its place if the given input has an error.
  • field-cell. The table cell containing the input field itself. If there is more than one field, they will usually all show up in this cell. May be a <td> or may be a <div> depending on layout. For the default layout, it's a <td>.
  • field-block. Each collection of an input field and possibly its label, its error messages, and its note is enclosed in a div of this class.
  • field. The input field itself is enclosed in a div of this class.
  • field-err. Same as "field", but used in its place if the given input has an error. Use this to change what the input field itself (not the error message) looks like upon error.
  • errmsg. If an error occurs, and it has an error message associated with it, the message will show up and be enclosed in a div of this class.
  • field-note. If a field has a note, the note will show up and will be enclosed in a div of this class.
  • radio-div. In a set of radio buttons, each radio button and its label will be enclosed in a div of this class, allowing for a horizontal layout or a vertical layout. (Hint: use display:inline in your style for a horizontal layout.)

RazorForm Layouts

The layout decides what goes where in a RazorForm row. For an overview of the role of layouts, please review the section A Word About Layouts. The specific duties of the layout are these:

  • Specify if the form will come out all in a normal HTML table or in some other setup, most likely some collection of divs and/or spans.
  • Determine what the row label will be. The layout will have to decide what rules and logic to apply to arrive at the final label for the row, including the label separator for multiple inputs in the row (label_sep), and the punctuation that will come after the label (row_punc).
  • Specify the position of the row label relative to the other elements in the row.
  • Determine what the label for each input field in the row will be, including any punctuation coming after the label (input_punc).
  • Specify the position of the input labels relative to their input boxes.
  • Specify the position of the input boxes and their labels relative to the other elements in the row.
  • Specify the position of the error messages if they occur. This could be adjacent to the individual input boxes or all concatentated together in some location.
  • Specify the position of the note if there is any.

If you are just using RazorForm with the stock layouts, the above list of things is something you mostly don't need to worry about. Just keep in mind that these things may or may not vary depending on which layout your form is using. If you are wanting to make a layout of your own, your layout will have to address these issues. More to come on making your own layouts.

To use an alternate layout from default, you simply put a layout=whatever attribute into the <RazorForm> tag. Technically, layouts are applied on a row-by-row basis, so you can also specify a layout=whatever attribute in the <row> tag. If you do, that row alone will have a different layout from the rest of the form. Do this with caution, because one layout will use <tr>s and <td>s where another will use <div>s and <span>s, and they won't work together at all. Make sure you know what the new layout will do before straying from your form-wide layout. (As a matter of fact, I'm only describing this stuff for hypothetical reasons - at the moment the only two layouts I've made are not compatible with one another.) Leaving out the layout attribute in the <row> tag means the row will inherit that attribute from the form-wide setting, just as it does any other attribute. The beginning and ending of the form - i.e. the opening and closing <table> or <div> - will be taken from the form-wide setting.

What follows is a description of all layouts currently available in RazorForm. I would love to receive any more that you would think generally useful. If you make your own and would like me to include it in future releases of RazorForm, please include a description like the ones here, addressing all of the same issues.

Creating your own Layouts

I'm going to have to flesh this section out more later on. Sorry for the brevity.

If you want to create your own layout, go into RazorForm.php and take a look at what I've done with a couple of classes called layout_default and layout_labels_above. Whenever you tell RazorForm to use a non-default layout, it tries to instantiate a class called "layout_xxx", where xxx is the "visible" name of the layout. The constructor must accept a $caller argument, which is the object that called your constructor, either a RazorForm object or a RazorFormRow object. You will call methods on your $caller object to get necessary information to construct your row. This will include the names of the CSS classes (which might be modified from their default names), the array of input fields in the row, the row label, the input field labels, and the HTML/plaintext values for the input fields themselves, their error messages, and their notes.

You take all of that stuff and arrange it into a single string of HTML that will be handed off to the browser for the current row. This value must be returned by the get_output() method, which must accept no arguments.

The other methods your layout class is required to have are get_start(), which returns a string containing the beginning of your form (<table> or <div>, etc.), get_end(), which returns the end of the form (closing tags for what was in get_start()), and get_style, which returns a string containing any style definitions you need to set to achieve the desired effect in your layout. These three methods should return false if your layout has no need for them.

The setup_row() method is not required, but I find it handy. Likewise with the get_label() method of the default layout class. I've also created a utility function called pretty() that just takes a string and formats it with the specified number of indentations and tacks a newline on the end. This makes your output HTML nice and, well, pretty.

You can use the layout_blank class as a template for creating your own, if you'd like.

Inserting Your Own Code into the RazorForm Output

As mentioned above, $rf->get_form() spits out the entire form. Internally, this method just calls a few other RazorForm object methods which you can call yourself instead of calling $rf->get_form(). You would want to do something like this in the case that you wanted to insert some of your own code at some point in the RazorForm output.

$rf->get_form() calls the following in order:

  • $rf->start_form()
  • $rf->get_rows()
  • $rf->end_form()

$rf->start_form() prints out the beginning code of the form. It accepts a single optional argument of true or false (default true) telling it whether or not to include the <form> tag. So you could do something like this (assuming you had already created a RazorForm object called $rf):

        <form action="foo.php" method="post">
        ... insert your own stuff here ...
        <? $rf->start_form(false); ?>
        

The output of $rf->start_form() will have anything necessary to get the form started. This will include the opening <table> or <div> tag (depending on the layout) and any stylesheet definitions the layout needs to set to organize the row as it sees fit. It will also include any hidden input fields that were in the form definition before any rows were defined.

$rf->get_rows() prints out the rows of the form. It keeps track internally of what rows have been printed already, and it will start printing from the next row after that. get_rows() accepts two optional arguments which must be integers. If you give it neither of these, it will print out all rows of the form from the current row to the last. So if nothing has been printed yet, the current row will be at 1, and the whole form will be printed. If you pass get_rows() only one integer, it will print out that many rows, starting at the current row. Finally, if you give it both arguments, it will see these as startrow and endrow, and print out all rows starting with startrow and ending with endrow, inclusively. This last scenario ignores the whole question of what the current row was to start out with, but it does reset the current row to be the one immediatedly following endrow. If endrow is greater than the number of rows in the form, get_form() will print from startrow up to the last row.

$rf->get_row() prints out one row at a time. If you give it the optional integer argument, it prints out the row with that row number. If you call it without the argument, it prints out the next row after the last one printed, according to the internal pointer mentioned in the previous paragraph.

You can reset the internal current row pointer back to 1 by calling the $rf->resest_curr_row() method, which takes no arguments.

NOTE: The row numbering for the $rf->get_rows() and $rf->get_row() methods is NOT zero-based indexing. It starts at 1 and goes up.

Using $rf->get_rows() and $rf->get_row(), you could do something like this (note that in this case we don't type out a <form> tag because we don't pass a false to $rf->start_form()):

        <? $rf->start_form(); ?>
        <? $rf->get_row(); ?>
        ... put your own stuff here ...
        <? $rf->get_row(2); ?>
        ... more of your own stuff ...
        <? $rf->get_rows(3,7); ?>
        ... more of your own stuff ...
        <? $rf->get_rows(); ?>
        <? $rf->end_form(); ?>
        

Usually you wouldn't use both methods of access like shown here. In a single form, you'd likely only access rows by current row pointer or by explicit row numbers. In other words, you'd use only get_row() with no arguments and get_rows() with zero or one arguments, or get_row() with one argument and get_rows() with two arguments.

When doing something like the above example, keep in mind that the places where you insert your own stuff will be inside of the overall form table at this point. This could be either a traditional HTML table or an arrangement of divs and spans, depending on which layout you're using. The default layout uses an HTML table, so in that case you'd want to put whatever of your own stuff you were adding into its own <tr> and <td>.

$rf->end_form() is the counterpart to $rf->start_form(), printing out the </table> or the final </div> (depending on the layout). Like $rf->start_form(), it takes an optional argument $formtag, which is a true or false telling it to print out the final </form> tag or not, default true.

Putting the RazorForm Definition into a Separate File

Frequently a project requires that both a programmer and a graphic designer be altering the files that determine what will be seen by the end user, and it makes sense to split the programmatic code up from the display code. For example, you might have a script that tests the input from the user and updates a database if it's good or shows the template again if it's bad. You don't want the designer to have to muck around in the script, and you don't want the programmer to have to muck around in the template, but both the script and the template need to have access to the form definition (the script because it needs to run the error checking code, and the template because it needs to display the form).

The string argument passed to the RazorForm object's constructor can be the name of a file instead of the form definition itself. If it is, RazorForm will try to read this file and use its contents as the form definition. In this case you do not set the whole thing up as a PHP variable; you just start out with the <RazorForm> tag and go from there.

You can include arbitrary PHP code in the form definition file that will affect the final outcome of the form definition, in the same way that PHP code affects the outcome of the HTML in which it is embedded. This code will be in the same namespace as a template included by the RazorForm class would be, so it has access to global variables and functions in your file, subject to the same rules of scope.

Let's consider an example. Here we have the entire contents of three files: script.php, template.php, and form.rzf. script.php is a PHP script that determines what to do with the user input. If the current page view is the first one, or if there's an error, it shows the template. If it has received valid input from the user, it updates the user's information in the database. template.php is the template that just displays the form. Since RazorForm handles the error checking, the template doesn't need to do anything special in case of errors other than defining CSS styles for the error classes field-lab-err and field-err. Notice that template.php doesn't need to instantiate a RazorForm object - it gets that from script.php because script.php includes it. form.rzf is the form definition, and it includes some PHP logic to set up the list of options for the dropdown list. Notice that form.rzf gets the options from script.php, but it must use the global keyword to do so.

        script.php -----------------------------------------------

            <?
            include("RazorForm.php");

            $opts = array("Tin Roof Sundae", "Neopolitan", "Rocky Road");

            $rf = new RazorForm("form.rzf");

            if ($_REQUEST['cmd'] == "process_form") {
                $err = $rf->check_errors();
                if ($err) {
                    include("template.php");
                } else {
                    update_database();
                }
            } else {
                include("template.php");
            }

            function update_database() {
                ... put database code here ...
            }
            ?>

        template.php ---------------------------------------------

            <html>
            <body>

            <style type="text/css">
            .field-lab-err {
            color: red;
            }
            .field-err select {
            border: 1px solid red;
            }
            </style>

            <? $rf->get_form(); ?>

            </body>
            </html>

        form.rzf -------------------------------------------------

            <? global $opts; ?>
            <RazorForm action="script.php" method=post>
                <input type=hidden name="cmd" value="process_form">
                <row>
                    <input type=select name=foo label="Foo" req>
                        <option value="" display="select one">
                        <? for ($i = 0; $i < count($opts); $i++) { ?>
                        <option value=<?=$i?> display="<?=$opts[$i]?>">
                        <? } ?>
                <row>
                    <input type=submit value="go">
            </RazorForm>
        

If the user does not select one of the options, the value of the first option will be submitted. That value is a blank string, and since the field has the req attribute, it will cause an error. Because the script has found an error, it will just show the template again.

Also notice that in this case the programmer (sure, it's me, but just go with it for a second) has used his own little mechanism for telling his script whether it's a first page view or a subsequent submission. He's created a hidden input called cmd which won't be there on the first page view but will thereafter. Since that's the only question, he could easily have used the rf_subsequent hidden input that RazorForm uses for this same purpose. As a matter of fact, I'd recommend doing it that way in a case like this. But frequently a form will have a more complicated set of commands than this, maybe something like the following: show_add, do_add, show_add_success, show_edit, do_edit, show_edit_success. In such a scenario, using rf_subsequent wouldn't be enough information for the script, and it would be best to just do your own thing and let RazorForm use rf_subsequent for its own purposes unbeknownst to your script.

Pre-Populating a Form

Sometimes you want to populate a form on the first page view, perhaps with values coming out of a database. To do so, you use the populate() method of the RazorForm object. $rf->populate() accepts a string-indexed array of form data, and any keys in that array that also exist as inputs in the form definition will have their values transmitted to the corresponding inputs. For example:

        $formdef = <<<EOS
        <RazorForm action="script.php" method=post>
            <row>
                <input type=text name=fname label="First Name">
            <row>
                <input type=text name=lname label="Last Name">
            <row>
                <input type=submit value="go">
        </RazorForm>
        EOS;

        $rf = new RazorForm($formdef);

        $data = array("fname" => "Billy", "lname" => "Joel");
        $rf->populate($data);
        

In this example, the form would show up pre-populated with "Billy" in the fname box and "Joel" in the lname box.

If you're going to pre-populate your form and use error checking on submissions, you need to take care not to pre-populate it again if the current page view is actually a re-display after errors were found. There's more than one way to do this, but a pretty sensible way is using the subsequent property of the RazorForm object. This property gets set to true after a RazorForm has been submitted (using the rf_subsequent hidden input field):

        $rf = new RazorForm($formdef);
        if (!$rf->subsequent) {
            $data = array("fname" => "Billy", "lname" => "Joel");
            $rf->populate($data);
        }
        $rf->check_errors();
        

We don't have to put the call to check_errors() in an else block here because check_errors() internally checks $rf->subsequent and only runs if it's set to true. In other words, with $rf->populate you have to worry about whether the current call is a postback, and with $rf->check_errors() you don't.

Object-Oriented RazorForm

I'm so sick of writing documentation right now that I could barf. So for now I'm hoping you'll be able to get what you need to know about the object-oriented programmatic interface to RazorForm from an example.

I'll say a few things about it, though. There are four main classes you need to know about: RazorForm, RazorFormRow, RazorFormInput, and RazorFormOption. A RazorForm object has a collection of RazorFormRow objects, a RazorFormRow object has a collection of RazorFormInput objects, and a RazorFormInput object has a collection of RazorFormOption objects, if it's of type select, multiselect, or radio. You add a RazorFormRow object to a RazorForm object's list of RazorFormRow objects using the RazorForm object's add_row() method. The others have their analogous methods, i.e. RazorFormRow->add_input() and RazorFormInput->add_option(). I'm hoping it's readily apparent why all of this is so.

The constructors for each of these classes can accept a string-indexed array of attributes, like type, name, or label. This is analogous to setting these attributes in the respective tags in a RazorForm definition. You can also set them with the set() method that each of these classes has. For the RazorForm object, attributes that normally go into a <default> tag can go into the array passed to the constructor.

So you just use this object-oriented interface in place of your normal form definition, and the rest is all the same as described in the previous sections of this guide, i.e. for outputting the form, using the CSS styles, checking errors, etc.

        <?
        include("RazorForm.php");

        $rf = new RazorForm(array(
            "action" => "myscript.php",
            "method" => "post",
            "layout" => "labels_above",
            "label_sep" => ", "
            "row_punc" => ":"
            ));

        $row = new RazorFormRow();
        $input = new RazorFormInput(array(
            "type" => "text",
            "name" => "foobar",
            "label" => "Foobar"
            ));
        $row->add_input($input);
        $rf->add_row($row);

        $row = new RazorFormRow();
        $input = new RazorFormInput(array(
            "type" => "select",
            "name" => "icecream",
            "label" => "Ice Cream"
            ));
        $opt = new RazorFormOption("value"=>"trs", "display"=>"Tin Roof Sundae");
        $input->add_option($opt);
        $opt = new RazorFormOption("value"=>"rr", "display"=>"Rocky Road");
        $input->add_option($opt);
        $opt = new RazorFormOption("value"=>"neo", "display"=>"Neopolitan");
        $input->add_option($opt);
        $row->add_input($input);
        $rf->add_row($row);

        $row = new RazorFormRow();
        $input = new RazorFormInput();
        $input->set("type", "text");
        $input->set("name", "movie");
        $input->set("label" => "Favorite Movie");
        $row->add_input($input);
        $rf->add_row($row);


        $rf->check_errors();
        ?>

        <html>
        <body>

        <? $rf->get_form(); ?>

        </body>
        </html>