WebIPDB

WebIPDB is a common basis for the Web forms used to access the IP address database. It encourages a uniformity of structure and appearance, and collects otherwise repeated code into a single place.

The processing of a web form request

An application module is called by WebDBI (q.v.) on receipt of a form request. WebIPDB imposes a general structure on the processing, which is

   1. Deal with any action requested as a result of a button
      being clicked in the form the browser was displaying.

   2. Print (or reprint) the form to replace whatever the
      browser is displaying. This form is of the shape

         i.   A header common to all forms in this family.

         ii.  A part specific to this form, the part you
              might regard as the form proper (which may
              depend in part on the action (1) above).

         iii. Any textual output from the action (1) above.

      The new form is constructed such that any button press
      will result in a re-invocation of the same application
      module.

Calling the handler

The main line of your WebDBI handler routine should be a single call to ipreg::WebIPDB->handle_request. The rest of your code should be contained in subroutines which are passed as parameters in the single call of ipreg::WebIPDB->handle_request, as keyword-value pairs. All pairs are optional, but some are more useful than others. For example

    ipreg::WebIPDB->handle_request(
        title => "My form title",
        initialise => \&my_init,
        actions => { button_name_1 => \&sub1,
                     button_name_2 => \&sub2 },
        form_text => \&form_text,
        clean_up => \&my_cleanup
        );  

The subroutines thus specified are called (back) when a request is submitted from the browser. In all cases the first parameter in such call-backs is a handler object that can be used to call various provided utility routines (in object method idiom). For example,

    sub sub1 {
        my $handler = shift;
        $handler->result_print( "You clicked button 1" );
    }

In fact the handler object handed to these routines is fixed within the processing of any single web request, so noting it in the "initialise" routine for use in the other routines is permitted and possibly convenient.

The initialise routine

This routine is called after WebDBI has initialised itself to deal with the request, but before it has done anything substantive. It is primarily useful for action required whatever button has been pressed.

The actions list

This specifies the routines to be called when specific buttons are clicked. Only one is called in any one interaction. It is called after "initialise" but before "form_text". Various utilities are available here. (Actually, most of them are available in the other call-backs as well, but action routines are where you mostly use them.) This is the place where you would normally set CGI parameter values to prime fields to be included by form_text. All the ordinary facilities of the CGI module can be used, but it is expected that you will use the WebIPDB button method to create buttons rather than bare submit.

The form_text routine

This should return a text string or array of text strings to constitute the guts of the form. This is where you embed your buttons, fields etc.

The clean_up routine

This is called last of all, to allow an opportunity for sweeping up.

Facilities available during call-backs

The WebIPDB facilities that are available during call-backs should be accessed by

    $handler->facility_name(parameters)

The result_print method

This takes any number of arguments and saves them up for inclusion in the results section of the emitted page. The text is included bare, can include html tags, and indeed must if you don't want it all run together as a single paragraph by the browser. Enclosing it in $handler->pre_esc() can be helpful if your text is acquired pre-formatted from elsewhere.

The pre_esc method

This is simply a shorthand convenience for transforming a string into an html-escaped string surrounded by <pre>...</pre>. Thus if handed some pre-formatted text you might do something like

  $handler->print( $handler->pre_esc( $text ) )

The debug_print method

This does what its name suggests. There is no promise about how or where it does it, but what you supply will be rendered somehow somewhere as plain text. Any number of arguments can be supplied; they are simply concatenated. You do not have to worry about html interpretation. The method does not predicate printing on the debug flag, but you may well care to.

The debug method

This simply returns the value (true or false) of the debug checkbox that WebIPDB included in the presented page.

The button method

This is the way to specify, from within form_text, that a button is to be inserted, to label it and to connect it with an action subroutine. The single argument is a text tag that appears on the button when rendered and which also links it to the action routine via the actions argument in "new".

The set_param method

See CGI::param with two arguments. set_param takes two arguments, a text name and an optional value. If the value is defined the CGI parameter is set to it, if not it is deleted. Compare and contrast CGI::param, which is unhelpful if the value argument is undefined.

The ipdbh method

This simply returns the IPDB handle.

Single part non-html output

It is possible for an action routine to emit a non-html document instead of the usual form plus results display, in other words to take over complete responsibility for all output. To do this, simply call $handler->suppress_output() before any output of any kind is emitted. Note that debugging output is problematic. The normal purpose is to deliver data to be filed rather than displayed, and in that context it will be necessary to emit $Q->header(...) as well.

Multipart output is not supported

The predecessor of WebIPDB had apparatus for allowing multi-part output. This is no longer available, following the realisation that Internet Explorer does not support it, and probably never will.

Example application module

  use ipreg::WebIPDB;

  sub request_init {

      my $handler = shift;
      $handler->debug_print( "In request_init\n" )
          if $handler->debug;
      my $hcount = $Q->param('hidden_count');
      if (defined($hcount)){
          my $count = $Q->param('count');
          $handler->result_print
              ( "You shouldn't have done that!", $Q->br )
                  unless $hcount == $count;
          $hcount++;
      }else{
          $hcount = 1;
      }
      $handler->set_param( 'hidden_count', $hcount );
      $handler->set_param( 'count', $hcount );
  }

  sub whoami {

      my $handler = shift;
      my $ipdbh = $handler->ipdbh;
      my $dbh = $ipdbh->dbh;
      $handler->result_print
          ( "I am ",
            $dbh->selectrow_array("select user from dual"));
  }

  sub echo {

      my $handler = shift;
      $handler->result_print( $Q->param('echo_field') );
  }

  sub form_text {

      my $handler = shift;
      return ( $Q->h3( "Sample form" ),
               $handler->button( 'echo' ),
               $Q->textfield( 'echo_field', '',30,1000 ), $Q->br,
               $handler->button( 'who' ), ' ',
               $Q->a( {href=>"http://www.ucs.cam.ac.uk/"},
                  "home" ), $Q->br,
               $Q->textfield( "count", undef, 2, 5 ),
               " iterations (read-only)",
               $Q->hidden( "hidden_count" )
               );
  }

  sub clean_up {

      my $handler = shift;
      $handler->debug_print("In clean_up\n")
          if $handler->debug;
  }


  ipreg::WebIPDB->handle_request( title => "Sample form_text",
                           initialise => \&request_init,
                           actions => { echo => \&echo,
                                        who => \&whoami },
                           form_text => \&form_text,
                           clean_up => \&clean_up
                           );