Copyright Notice

This text is copyright by InfoStrada Communications, Inc., and is used with their permission. Further distribution or use is not permitted.

This text has appeared in an edited form in Linux Magazine magazine. However, the version you are reading here is as the author originally submitted the article for publication, not after their editors applied their creativity.

Please read all the information in the table of contents before using this article.

Linux Magazine Column 72 (Jul 2005)

[Suggested title: ``Introduction to CGI::Prototype (part 3)'']

In the last two column articles, I introduced my CGI::Prototype generic controller framework. Let's continue the examination with a description a real workhorse subclass, CGI::Prototype::Hidden.

The CGI::Prototype framework can be used to write applications, but lacks the concrete means by which the state of the application can be deduced. I wrote the code expecting that various strategies for state dispatch (hidden fields, cookies, server-side databases, mangled URLs) would be coded as subclasses of CGI::Prototype. The first of these coded is hidden fields, as CGI::Prototype::Hidden.

For CGI::Prototype::Hidden (which I'll abbreviate CGIPH from here forward), the state must be a simple arbitrary keyword: something that matches /^\w+$/. The state is used to select a particular class for the controller, along with the default template for that class. Once a state has been selected, the corresponding class is loaded into the program (unless already defined), and used to determine the next step in the program. This ``lazy loading'' behavior permits a minimum of loading for CGI programs: at most, two different state-named classes are loaded per web hit.

CGIPH also defines a ``wrapper'' template to provide common definitions, headers, and footers for the processed templates, and a means by which the templates can be found ``next to'' the class source files. More on those later.

CGIPH is designed to make multi-page web applications easy to create and update. I found in practice that this is true: I recently created a fully functional administrative application for the booking engine of geekcruises.com, in far less time than I suspect it would have taken using hand-rolled CGI.pm code.

CGIPH makes extensive use of defaults, which generally work nicely, but can be easily overridden for custom configurations. For example, the dispatcher needs to know the name of the CGI parameter in which the state will be stored. The default value is _state, but if this name conflicts with something else in your application, you can override the value by simply defining a method named config_state_param in your application class with the new value. For example:

  package My::App;
  use base CGI::Prototype::Hidden;
  sub config_state_param { "--state--" }

Now the state parameter will be in the --state-- parameter, not the _state parameter. Speaking of My::App, the config_class_prefix (default My::App) gets prepended to the state to select the page class, so a state of enter_serial_number" will map to the class of C<My::App::enter_serial_number>.

If no state parameter exists, the config_default_page state is used instead. This configuration parameter defaults to welcome. Unless you override this parameter, your first hit will go to My::App::welcome as a class, which defaults to showing My/App/welcome.tt as a template.

This template is wrapped by a wrapper template, defaulting to My/App/WRAPPER.tt, but overridden by defining config_wrapper. The purpose of the wrapper is to provide definitions for common blocks and variables, and common headers and footers. The most trivial wrapper is simply:

  [% PROCESS $tempate %]

which then runs the corresponding individual page template, however you will probably want something more along the lines of:

   [%-
   TRY;
     content = PROCESS $template;
     self.CGI.header;
     self.CGI.start_html;
     content;
     self.CGI.end_html;
   ### exceptions
   ## for errors:
   CATCH;
     CLEAR;
     self.CGI.header('text/plain');
   -%]
   An error has occurred.  Remain calm.
   Authorities have been notified.  Do not leave the general area.
   [%-
     FILTER stderr -%]
   ** [% template.filename %] error: [% error.info %] **
   [%
     END; # FILTER
   END; # TRY
   -%]

This wrapper processes the individual page template, then ``wraps'' it with CGI HTML headers and footers, so that the page is properly displayed in the browser. This wrapper also traps any thrown errors, either from Template Toolkit or something called by a template, displaying an innocent message to the user and logging the details into the web error log.

One interesting trick here is to set variables in the template, and then check them in the wrapper. For example, if the template contains:

  [% has_custom_header = 1 %]

then we can use that to alter the behavior of the wrapper:

  [%
    content = PROCESS $template;
    IF has_custom_header;
      content; # it's all up to you
    ELSE;
      self.CGI.header;
      self.CGI.start_html;
      content;
      self.CGI.end_html;
    END;
  %]

This works because the template's variables are included in the wrapper's invocation context, allowing a two-way sharing.

So, the minimum CGIPH app consists of the CGI script in the CGI bin area, definitions for the classes My::App and My::App::welcome, and templates for welcome.tt and WRAPPER.tt. Each additional state requires a pair of files: the Perl module to implement the Perl code, and the template file to implement the view.

By default, the templates are placed in the same directory as the Perl modules. This is because the default engine parameters put the Perl @INC array into Template's search path. If you want a different policy, feel free to override engine_config from the value given in the CGIPH manpage with your own INCLUDE_PATH definition.

In order for the ``hidden'' part of CGIPH to work, every form or link must maintain the state of the application. The easiest way I've found to manage the state passing is to create a TT block that's meant to be used as a wrapper, and put this into the WRAPPER.tt file:

    [% BLOCK form %]
    [% self.CGI.start_form %]
    [% self.CGI.hidden(self.config_state_param) %]
    [% content %]
    [% self.CGI.submit; self.CGI.end_form %]
    [% END %]

Now I can define my forms in each page like:

  [% WRAPPER form %]
  ... my fields and text ...
  [% END %]

Without this hidden state parameter, the dispatcher gets lost in trying to find the page to which this is a response.

You may also want to override some of the other methods, which all have reasonable defaults. For example, render_enter_per_page is called just before a page is rendered. This is a good place to set up default params (for CGI.pm's sticky fields), or fetch the data for a ``data push'' model (more on this later). By default, nothing happens in this step.

Another hook provided by CGIPH is the pair of respond_per_app and respond_per_page. The dispatcher first calls respond_per_app to handle application-wide buttons or settings. If respond_per_app returns a true value, the dispatcher treats it as the render page object. Otherwise, the dispatcher continues by calling respond_per_page, which must return a render object. The default respond_per_page returns $self, meaning that you don't have to write a method for pages that don't have individualized responses.

Because self is passed to the template, a template needing additional heavy lifting can call back to the render page object easily. And since these objects (should) inherit from the application object, the template can also access global methods (or even regional methods if an additional layer of inheritance is introduced).

For example, to fetch a list of values for display, a page class can define the method to return the value:

  sub lotto_picks {
    my $self = shift;
    my @data = map { 1 + int rand 100 } 1 .. 10;
    return \@data;
  }

and then the template can pick them up:

  [% numbers = self.lotto_picks %]
  Today's lucky numbers are:
  [% FOR n = numbers %][% n %]
  [% IF loop.last; ", and "; ELSE; ", "; END %]
  [% END %]

This callback can start in the page object, but if I discover that I need it on more than one page, I just move it (cut, paste) into the My/App.pm file, and now all pages can access the same callback.

Another means for getting the data to the template is data push. Instead of waiting for the template to ask for the data, compute it once and install it as a slot:

  sub render_enter_per_page {
    my $self = shift;
    my @data = map { 1 + int rand 100 } 1 .. 10;
    $self->reflect->addSlot(lotto_picks => \@data);
  }

Since the page objects inherit from the application object, which inherits from CGIPH and therefore CGI::Prototype, which inherits from Class::Prototyped, we get ``slot management'' for free. Any new data value or method can be added at runtime, with the appropriate getters and setters being installed. And as an added bonus, Template Toolkit calls this kind of slot to get an array ref in the very same way as it called the method callback. Yeay.

In a long-running application (such as from mod_perl, you might want to free up the data space by removing the slot in render_leave. However, for CGI-based applications, the data will die shortly after the page is shown, so we have no big concern.

Another nice use for created-at-runtime slots is application-wide notes, such as errors and notices discovered during the processing of a given web hit. Again, this is quite straightforward. First, add a slot during app_enter (defined in My/App.pm):

  sub app_enter {
    my $self = shift;
    $self->reflect->addSlot(errors => []);
  }

and define an easy access method to add a new error:

  sub add_errors {
    push @{shift->errors}, @_
  }

Now, any step that notices an error can note it, such as an error check in respond_enter_per_page:

  unless ($self->param("first") {
    $self->add_errors("You forgot your first name");
    return $self; # stay on this page
  }

And the template can show the errors, perhaps in the WRAPPER.tt to ensure uniformity in display:

  [% FOR e = self.errors %]
  [% IF loop.first %]
  <h2>Errors:</h2>
  <ul>
  [% END %]
  <li> [% e | html %]
  [% IF loop.last %]
  </ul>
  [% END %]
  [% END %]

So, that's about all there is to the mechanics of CGIPH. I'm slowly collecting ``best practices'' that I'm becoming aware of while creating projects for clients, and hope to be gathering that into CGI::Prototype::Cookbook, Real Soon Now (hopefully by the time you see this).

But the one thing that's become obvious to me repeatedly is that the inversion of logic is really helping the design of my web applications. It really does feel like I'm ``calling the user to fill out this form'' instead of the user ``yelling at me to respond to his next hit''. To add a new form and response, I create the view, start with a mostly empty class (just the inheritance and a ``1;''), then flesh out all the heavy lifting things for the form, and then slowly add the plumbing to respnd to the form parameters. The default ``stay here until you get it right'' is a natural user-interface loop design.

So, in summary, consider CGI::Prototype::Hidden for your next medium-sized web application. Until next time, enjoy!


Randal L. Schwartz is a renowned expert on the Perl programming language (the lifeblood of the Internet), having contributed to a dozen top-selling books on the subject, and over 200 magazine articles. Schwartz runs a Perl training and consulting company (Stonehenge Consulting Services, Inc of Portland, Oregon), and is a highly sought-after speaker for his masterful stage combination of technical skill, comedic timing, and crowd rapport. And he's a pretty good Karaoke singer, winning contests regularly.

Schwartz can be reached for comment at merlyn@stonehenge.com or +1 503 777-0095, and welcomes questions on Perl and other related topics.