FormBroker
| The Form Broker |

## Name

FormBroker — Form broker object creator

## Synopsis

::FormBroker create ?-quoting quoting_procedure? ?variable1 descriptor? ?variable2 descriptor? ?...?

## Description

The command returns a reference to a form broker object by creating a representation of the form data using the list of variable descriptors passed to method create. Each descriptor is a list of parameter or parameter-value pairs that must begin with the {variable_name variable_type} pair as only requirement. A formbroker object provide native support for integer, unsigned integer, string, boolean and email data types. The programmer can defined new data types and provide in the descriptor a reference to a validation procedure for that type.

The optional ?-quoting quoting_procedure? switch defines an external procedure to quote or reformat the response values. The quoting procedure is any procedure accepting a single string argument and returning its quoted value. A most basic example is the FormBroker default quoting procedure

    proc force_quote {str} {
        return "'$str'"
    }

Other parameters of a descriptors are

- type: the data type of the variable
- bounds: limits of a variable value. The meanining of bounds depends on the variable type. For an integer is the maximum absolute value for that variable (for an unsigned the lower limit is invariably 0), for a string is the maximum length of the string. The parameter bounds has no effect on an email data type
- constrain: boolean value telling the variable has to be forced to fulfill the constrain imposed by bounds. This field is bidirectional in that it can be used by the validator to force the variable value rewriting
- validator: name of the specialized validator for this variable
- default: default value of the variable if not set in a response array. When a variable is given a default value the form validation will not fail on the fact that this variable may be missing from the form response array
- quote: the variable value has to be quoted when written back in the response array
- validator: name of the validator procedure. The procedure can be any Tcl procedure accepting as argument the name of a dictionary holding the variable internal representation.

An example of a form accepting four variable, one for each native type of a form broker object

     % set fbroker [::FormBroker create {var1 integer} {var2 unsigned} {var3 string} {var4 integer bounds {-10 100}}]
    ::FormBroker::form0

## Form broker object methods

The central method of a form broker object is validate

  `formBroker_object` validate ?-forcequote? response ?`response copy`?
  The method validate takes as argument the name of an array of variables in the way this is produced by command load_response returning a form response. The optional argument `-forcequote` causes the variable values to be rewritten and quoted. If the optional argument `response copy` is present the validated response is copied in this array instead of the input response array.
  If the form data have been validated the method validate returns true
  Example of form data validation (assuming ::rivet::load_response is loading the array response with data taken from a form non displayed here)

      % package require formbroker
      % set fbroker [::FormBroker create {var1 integer} {var2 unsigned} {var3 string} {var4 integer bounds {-10 100}}]
      ::FormBroker::form0

      % ::rivet::load_response
      % parray response
      response(var1) = -10
      response(var2) = 20
      response(var3) = a string
      response(var4) = 50

      # let's keep a copy of the response

      % array set response_copy [array get response]

      # form data validation

      % $fbroker validate response
      true
      % $fbroker validate -forcequote response
      % parray response
      response(var1) = '-10'
      response(var2) = '20'
      response(var3) = 'a string'
      response(var4) = '50'

      # restore response original value

      % array set response [array get response_copy]
      % $fbroker validate -forcequote response response_copy
      true
      % parray response
      response(var1) = -10
      response(var2) = 20
      response(var3) = a string
      response(var4) = 50
      % parray response_copy
      response_copy(var1) = '-10'
      response_copy(var2) = '20'
      response_copy(var3) = 'a string'
      response_copy(var4) = '50'

      # a form object has to be destroyed if it's not needed anymore

      % $fbroker destroy

  `formBroker_object` failing
  In case the validation fails method failing returns a list of variable_name - error_condition pairs for each variable whose value failed to validate and was impossible to fix. This list is suitable to populate an array or used directly as a dictionary

      % package require formbroker
      1.0
      % set fbroker [::FormBroker create {var1 integer} \
               {var2 unsigned} \
               {var3 string} \
               {var4 integer}]
      ::FormBroker::form0
      % ::rivet::load_response

      # let's suppose we have an incomplete response
      % parray response
      response(var1) = '100'
      response(var2) = '20'
      response(var3) = 'a string'
      % $fbroker validate response
      false
      $fbroker failing
      var4 MISSING_VAR

      # this can be prevented by assigning a variable a default value

      % set fbroker [::FormBroker create {var1 integer} \
                                         {var2 unsigned} \
                                         {var3 string} \
                                         {var4 integer default 0}]
      ::FormBroker::form1
      % $fbroker validate response
      true
      % parray response
      response(var1) = 100
      response(var2) = 20
      response(var3) = a string
      response(var4) = 0

      % set fbroker [::FormBroker create {var1 integer} \
                                         {var2 unsigned} \
                                         {var3 string length 10 constrain} \
                                         {var4 integer bounds {-10 100}}]
      ::FormBroker::form2
      % ::rivet::load_response

      # this time the response has invalid data

      % parray response
      response(var1) = 'aaaaa'
      response(var2) = '-20'
      response(var3) = 'a longer string that breaks the 10 chars max limit imposed'
      response(var4) = '150'
      % $fbroker validate response
      false
      % $fbroker failing
      var1 NOT_INTEGER var2 FB_OUT_OF_BOUNDS var4 FB_OUT_OF_BOUNDS

  Notice that even though $response(var3) exceeds the 10 characters max length imposed to variable var3 this variable is not in the list returned by failing because the 'constrain' attribute forced the truncation of the string. In fact this applies also to the integer and unsigned values

      % package require formbroker
      % set fbroker [::FormBroker create {var1 integer bounds 10 constrain} \
                                         {var2 unsigned constrain} \
                                         {var3 string length 10 constrain} \
                                         {var4 integer bounds {-10 100} constrain}]
      ::FormBroker::form0
      % ::rivet::load_response
      % parray response
      response(var1) = abcdef
      response(var2) = -20
      response(var3) = a longer string that breaks the 10 chars max limit imposed
      response(var4) = 150
      % $fbroker validate response response_copy
      false
      % $fbroker failing
      var1 NOT_INTEGER
      % parray response_copy
      response_copy(var2) = 0
      response_copy(var3) = a longer s
      response_copy(var4) = 100

  The variable var1 could not be constrained because the input value "abcdef" is fundamentally incompatible
  `formBroker_object` response ?response_array_name?
  The response method fills the array whose name is passed as optional argument with the last response processing. If this argument is omitted the method creates an array named response.
  This method can be called also if no form response validation has taken place: it simply populates the array with the default values assigned to the form variables. As such is a way to create form default arrays to initialize forms created with the form package.

      set fbroker [::FormBroker create {var1 integer default 0} \
                                       {var2 unsigned default 1} \
                                       {var3 string} \
                                       {var4 integer default 0}]
      % $fbroker response a
      % parray a
      a(var1) = 0
      a(var2) = 1
      a(var4) = 0

  `formBroker_object` reset
  The method resets the object to its initial defaults

## Validator Error codes

Variable type validators returned specific code

- string:
  - FB_EMPTY_STRING if the variable descriptor has the 'nonempty' flag set and the trimmed string is empty
  - FB_STRING_TOO_LONG if the string length exceeds the max string length set with the maxlength option. This error is not returned if maxlength was not set
- integer:
  - FB_OUT_OF_BOUNDS if bounds were assigned to the variable but it's value lies outside of them. This error is not returned if bounds were not set or the variable was defined with the flag constrain which forces its value to be the closest boundary value
- unsigned:
  - FB_OUT_OF_BOUNDS the variable value is either negative or outside the bounds assigned to the variable descriptor. The error is not returned if the variable was defined with the flag constrain which forces its value to be the closest boundary value
- email:
  - FB_INVALID_EMAIL the variable is an invalid email address representation

## Writing a custom variable validator

The form broker is by no means restricted to work only with its native data types: you may define your own form variable types and have them validated with their own variable validator.

A validator is a function accepting a dictionary as single argument and must return either FB_OK, if the variable value is valid, or any other used defined error code. The dictionary argument stores the variable descriptor used internally by the form broker.

Suppose you're writing a form text entry that demands as input a network interface MAC address. A MAC address is represented by 6 hexadecimal octets separated by either a “-” (Windows convention) or “:” (Unix, Mac convention). The procedure validate_mac checks the validity of the mac address and if validation is successful it transforms its representation into the Unix form. By setting the key “constrain” in the dictionary mac_address_d the procedure is telling the form broker to copy the transformed value back in the input response array

    proc validate_mac {_mac_address_d} {
        upvar $_mac_address_d mac_address_d

        dict with mac_address_d {

            set var [string trim $var]
            if {[regexp {^[[:xdigit:]]{2}([:-][[:xdigit:]]{2}){5}$} $var]} {

                set var [string tolower $var]

                # we normalize the mac address to the Unix form.
                # The dash '-' characters in the windows representation
                # are replaced by columns ':'

                set var [regsub -all -- {-} $var :]

                # the 'constrain' field is bidirectional:
                # it tells the validator to curb/change the value
                # within bonds/forms/representation. By setting it the
                # validator tells the FormBroker to copy the value
                # back in the response array

                set constrain 1
                return FB_OK

             } else {

                return FB_WRONG_MAC

             }

        }

    }
    % set fbroker [::FormBroker create {mac mac_address validator validate_mac}]
    % ::rivet::load_response r
    % parray r
    r(mac) = 00-A1-B2-C3-D4-C5
    % $fbroker validate r
    true
    % parray r
    r(mac) = 00:a1:b2:c3:d4:c5

The Form Broker |  | Resources - How to Get Help