Forms

From KnowledgeTree Document Management Made Simple

Jump to: navigation, search

Displaying a form, processing its output, validating that output and handling any errors which occur along the way - these are the steps involved in the vast majority of KT UI code. To make this process less error-prone, more efficient and a whole lot less tedious, KT includes a fairly solid widget & validation layer.

Key to using that layer is the KTForm class (/lib/widgets/forms.inc.php). Using this class will allow you to use and re-use the broad range of items available in the system.

There are 4 phases to the lifecycle of any form:

  1. Create the form.
  2. Display the form
  3. Validate the form
  4. Act on that validation

Step 4 may send you back to Step 2 with errors, or proceed to a different action. Doing all this in a generic, easy to use way requires a lot of effort for each form if done manually - doing it using the Forms code requires virtually none.

Contents

Setting up the basic form

All of the form, widget and validator functionality uses configuration arrays rather than lots of method calls or long method signatures to do its work. This makes it more flexible, and easier to read code that uses it. The basic sequence of calls is:

$oForm = new KTForm;
$oForm->setOptions($aConfiguration);
$oForm->setWidgets($aWidgets);
$oForm->setValidators($aWidgets);

Using the form comes down to 3 basic methods. To display the form, one uses one of

$oForm->render()
$oForm->renderPage($sTitle, $sDescription)

The latter is useful for all those "display just this form" situations. Validating the form (after its been submitted) uses both of the following:

$res = $oForm->validate()
return $oForm->handleError($sCustomMessage, $aMoreErrors)

validate() returns an array containing two subarrays: errors and results. See "Validating the form" below for more information.

The best way to do all this is to use a separate method on the dispatcher so that you only ever define the form in one place. Typically, we call these methods "form_<actionname>" to make it clearer what the form does.

Basic Configuration

Configuring the actual form is relatively straightforward - it uses a fairly straightforward configuration array.

item required type description !
identifier yes string Its very important that each different form has a "namespaced" name. This allows the system to work out whether old data (e.g. from a previous request) is still valid
context no dispatcher If you're creating the form from a dispatcher, you will usually need to pass around a variety of extra information (e.g. what folder / document you're on if you're an action, etc). Passing in your dispatcher as "context" will allow all that to occur automatically. You want to do this in the vast majority of situations.
extra_args no array If for some very good reason you don't want to use the persistence built into dispatchers, you can pass in an array of key => value pairs to pass on to the form recipient.
label yes string The form should have a clear label, describing the data being collected. See UI Guidelines for more information on how to name forms, actions, etc.
description no string When possible, one should provide a simple introductory description explaining what the form will do. Naturally, this is not always appropriate.
submit_label yes string What label should the "submit" action have.
action yes string The name of the action to which this form should send its data.
fail_action yes string When there's a validation problem, where should the form be submitted?
cancel_action no string If the form can be cancelled, where does the cancellation send the user (action)
cancel_url no string An alternative to the "cancel_action", sometimes you need to send the user to a completely different part of the application. This will let you do that. (e.g. KTBrowseUtil::getUrlForDocument(...))

Adding Widgets

Adding widgets is very straightforward, and can be done in one of 2 ways. The annoying, painful way is actually instantiate a subclass of KTWidget, configure it, and add that to the form using addWidget. The "easy" way is to simply tell the form what widgets to instantiate, and how to configure them. Since the former isn't recommended, I'll only explain how to use the "normal" mechanism.

To create widgets using the form's widget-factory, you use a set of arrays like this:

$oForm->setWidgets(array(
   array('ktcore.widgets.string', array(
      'label' => _kt('My Label'),
      ...
   )),
));

Essentially, its a list of arrays of the form:

  array($sWidgetNamespace, $aWidgetConfiguration) 

For more information on how to configure each widget, see Widgets.

The key methods are

setWidgets($aWidgets)
addWidgets($aWidgets)
addWidget($mWidgetOrConfiguration)

Adding Validators

Validators are added in exactly the same way as widgets, except that you validators instead of widgets. Similarly to Widgets, the key methods are

setValidators($aValidators)
addValidators($aValidators)
addValidators($mValidatorOrConfiguration)

Validating the form

Validation typically has two parts

  1. extracting the data from widget-specific formats into something generally more useful.
  2. identifying an errors in the user's input

Within the form machinery, this is all done by the same set of validators, depending on how they work. Some validation is automatically handled by the widgets (e.g. a field marked as "required" will check that something was selected or input). Some needs to be done by you. For more info on what validators are available, see Validators. The most important things to remember

  1. extracting the data into the "results" array is done by validators with an output parameter to their configuration.
  2. the widgets will have massaged their data into some useful format. Check the widget's documentation for details of what that format is.

Very often the validation you need to perform doesn't fit neatly into the pre-defined validators and writing a once-off validator doesn't make much sense. In that case you can do the validation manually and pass any errors out using handleError()'s "$aExtraErrors" parameter. To do this you create an array of "widget_name" => $mMixedErrors, where the value is either a string or a list of strings to be shown as the error on a given field. "widget_name" is the "basename" of one of your widgets (e.g. the name of the value that the widget puts out).

Handling problems

If and when there's a problem, its important to do two things:

  1. provide the user with the best idea of both what went wrong, and how to fix it
  2. not lose the information the user input.

The forms machinery handles both of these for you through the use of

$sOutput = handleError($sMessage, $aExtraErrors)

Usually this is used very simply as follows

$oForm = $this->form_addmyobject()
$res = $oForm->validate()
if (!empty($res['errors'])) { return $oForm->handleError(); }
$data = $res['results'];

If you don't pass a message into "handleError" it will automatically use "Please correct the errors indicated below" as the message, and $aExtraErrors is described in the section called "Validating the form".

If the form had a "context" parameter, that will be used to error-out of the current method using errorRedirectTo()".

Personal tools