Introduction to CGI::Prototype, Part One

Read why Randal invents yet another CGI framework
It’s a rite of passage, they say. Every new Perl programmer seems to want to create their own CGI form parser. And their own templating system. And their own way to parse @ARGV. And eventually, they even get fancy and try to write their own SQL- eliminating database-as-objects wrapper. Or accessor autogenerator. Or lazy loader.
Or CGI framework. Yes, I’m now guilty of that, too, having created CGI::Prototype in recent months and loosing it on the rest of the world. I hope to explain in the following paragraphs exactly why I created CGI::Prototype, what it does, how it does it, and why it works better than anything else I could find at the time. Please read on.

The Problem

The main problem with web program design is that web applications are backwards. Let me explain.
In a traditional graphical user interface (GUI) application, the program is in control. The program puts up a widget onto the display, and drives the user into action. When the user is finished, the application then decides what to do and displays another GUI widget for the user to then deal with. In other words, the application drives the user.
In a web application, the user says, “Hey, I’ll visit a web site”. The web application then has to respond to the user, providing some sort of web form (the web equivalent of the GUI) back to the user, after which, the web application is gone. Dead. Terminated. The user then examines the form, and if he or she so chooses, fills out values and submits that form. A new web application invocation has to respond to this form, hopefully relying on notes that the previous application invocation left laying around in some server side database. And this happens repeatedly. In other words, the user drives the application.
So, every web application must figure out how to make sense of these seemingly unrelated hits coming inward. How does the web application maintain state, including credentials, intermediate results, database connections, and so on? This is a big problem, because although the highest level logic is common, the specifics are, well, specific to each application.
At the end of 2003, I was hired by a large university on the east coast (who shall remain nameless) to help develop a web application, getting as far as I could within the week that they had allocated for me. The application had some interesting goals: it had to talk to an existing Oracle application through a database; the look of the web application had already been prescribed by some HTML designers (a traditional multi-page form with the freedom to wander to any tab at any time); and it had to be flexible, because it was likely that the interfaces would change as more information was understood.
After spending the morning of the first day with the client trying to figure out what they really hired me to do, I got on IRC and PerlMonks (#perlmonks at irc.slashnet.org) and asked about existing frameworks with some particular requirements. After examining a few solutions, I realized by mid-afternoon that no one had yet created a framework in a way that could be applied to this situation as I wanted. So, being the resourceful guy I am, I wrote my own.
I knew I wanted to use Class::DBI for the database interface and the Template Toolkit for the display driver (both having large user communities, a bonus for my client). I also thought that I’d rely on the ole workhorse of CGI.pm, mostly because it’s had the most goings-over of any CGI form processor and HTML generator in the business, and I wanted to be conservative for my client.
This gave me the “model” and “view” of the famous “model-view-controller” (MVC) triad, a classic way of breaking down GUI frameworks into manageable pieces. The model is for the data, and the view is for the results. But where was the controller? There didn’t seem to be any detailed controllers in the CPAN that fit my client’s needs directly (or configurably), nor anything like an abstract controller that I could subclass and extend as I saw fit. And that’s where I sat back to think about every web application I had written.

Every Web Application

Every web application seems to have the following steps:
1.Look at the incoming hit, and figure out the approximate state (initial hit, responding to some form, and so on). Then, dispatch to the code that will handle that broad category of hit.
2.Attempt to respond to the hit, figuring out the details of the incoming parameters and cookies. Next, figure out the state again and select code to handle that.
3.Finally, render a response, displaying results, errors, and most
likely new forms to fill out.
The problem is that errors can happen and usually at bad times. For example, let’s take the typical two-page” form-and-response” written with CGI.pm:
use CGI qw(param);

unless (param) {
# no incoming parameters
... display the form ...
} else {
# incoming parameters
... respond to the incoming params ...
And this works fine. The first hit has no params, so the form is shown. The response points back at the same script, so the params are sent and the code handles the form.
But what if the form wasn’t filled out properly? Now you either have to figure out how to detect that before you dispatch to the “display the form” or “respond to the params” part, or you have to somehow get back up to the upper code after the lower code has been selected. Ugh.

My Implementation

I decided that I wanted a very generic CGI controller, using an object-oriented model. Further, I had recently played around a bit with Class::Prototyped and really liked the way that subclasses could be created on the fly and how accessors were smart, auto-generated, and dynamic. So, I decided that my top-level generic controller would be a Class::Prototyped- based object, and that helped define the name: CGI::Protoype.
The basic strategy is simple. The top-level application gets activated by the incoming hit, and calls the application’s dispatch method. The dispatch method is responsible for determining the application’s state and determines a particular controller to return to respond to that state. The respond controller then examines all of the available inputs, updating any external data, and then decides the new state in the form of returning a render controller. The render controller spits out a page to send back to the user, usually by calling Template Toolkit on a particular template, and sending the result to stdout.
That sounds very complicated in theory, but in practice, it works out to be rather straightforward. You create an application class that inherits from CGI::Prototype. You then create one or more “page/state” classes that inherit from your application class, and a template for each page class that is rendered to the user. You also need to create a dispatcher to decide which page class gets selected for a given state.

A Sample Program

The most trivial application you can create using CGI::Prototype is one that uses all of the defaults:
use base CGI::Prototype;
Here, I’ve cheated, using main as my application class. Generally, you’ll want to push this out into a real class for better testing. But this is indeed a complete application, and when hit, results in a small plain-text page that says “This page intentionally left blank,” using CGI.pm for the header. Cute? I know.
But this isn’t a very interesting application. However, by overriding just one method, I can get a template of my choosing instead of the built-in template:
sub template { ’mypage.tt’ }
Now the main class has an overridden template method, which defines the template to hand to Template Toolkit. There, I’ve now got a template-running CGI application.

Looking Under the Hood

Let’s look at what activate is doing, in essence:
my $self = shift;
my $this_page = $self->dispatch;
my $next_page = $this_page->respond;
First, the application’s dispatch method runs to get a page controller object, which generally inherits from the application controller itself. (This makes it easy to move page-created methods up to the application level so that all pages can share them if needed.)
Next, the page controller object is asked to respond() to the incoming parameters. When it completes, it’s expected to return an object to render. Again, this is typically a page controller object that inherits from this application controller, and frequently even just itself (“$next_page”eq”$this_page”), especially when there are errors.
Finally, the $next_page object is asked to render() something to the user, usually resulting in Template Toolkit being called on the result of $next_page ’s template() method.
So how did the empty application work? Through the clever use of defaults. The default dispatch() and respond() return $self. The default template() method returns the “this page intentionally left blank” template. So, it all “just works.”
Of course, in practice, this is all enclosed in an eval block, like so:
eval {
my $self = shift;
my $this_page = $self->dispatch;
my $next_page = $this_page->respond;
$self->error($@) if $@;
The default error() method simply displays the string to stdout, with a text/plain MIME type so that most browsers will leave it alone. You’ll almost certainly want to override that.
I’ve run out of space, and barely scratched the surface! Next time, I’ll talk about overriding the dispatch and respond methods to create a real application, and about before and after hooks on all the steps to hang interesting behavior alterations. I’ll also look at Class::Prototyped::Hidden, which handles the state recognition in an extensible consistent way.
Until next time, enjoy!

Randal Schwartz is the chief Perl guru at Stonehenge Consulting. You can reach Randal at class="emailaddress">merlyn@stonehenge.com.

Comments are closed.