Recently in Web/CGI Category

Advanced HTML::Template: Widgets

My previous article, looked at extending HTML::Template through custom tags and filters. This article looks at ways to manage large, more complex pages, by bundling HTML::Template into something like GUI "widgets" (or "controls").

Imagine you have a basic page layout following the standard setup, with a header, a lefthand navbar, and the main body in the bottom right. The header and navbar are the same for all pages of the site, but of course the main body differs from page to page:

Header
Navbar

Body

Naturally, you don't want to repeat the information for the header and the navbar explicitly on each page. Furthermore, if the HTML for the navbar changes, you don't want to have to modify each and every page. The <TMPL_INCLUDE> tag can help in this situation.

Create separate files for header and navbar, then include them in the template for each page (by convention, I use the filename extension .tpf for page fragments, to distinguish them from full-page templates: .tpl):

<html>
  <head></head>
  <body>
    <table>
    <tr colspan="2">
      <td><TMPL_INCLUDE NAME=header.tpf></td>
    </tr>
    <tr>
      <td><TMPL_INCLUDE NAME=navbar.tpf></td>
      <td> 
        <!-- Body goes here! -->
        ...
      </td>
    </tr>
    </table>
  </body>
</html>

Now HTML::Template will include the page fragments for the header and navbar in the page when it evaluates the template. Changes to either of the fragments will affect the entire site immediately.

(For simplicity of presentation, I am going to use the old familiar <table> method to fix the layout--this article is about HTML::Template, not CSS positioning!)

Note that both the header and the navbar may include other HTML::Template tags, such as <TMPL_VAR> or <TMPL_LOOP>: file fragment inclusion occurs before tag substitution. If you need dynamic content in either header or navbar, all you need to do is set the value of the corresponding parameter using the param() function before evaluating the template.

Better Encapsulation through Widgets

If there are only a few dynamic parameters in header and navbar, you can simply assign values to them together with the parameters required by the main body of the page. However, if the header and navbar themselves become sufficiently complicated, you probably don't want to repeat their parameter-setting logic with the actual Perl code managing the main business logic for each page of our site. Instead, you can control them through an API.

To establish a Perl API for a page fragment, hide the entire template handling, including parameter setting and template substitution, in a subroutine. The subroutine takes several parameters and returns a string containing the fully expanded HTML code corresponding to the page fragment. You can then include this string in the current page through a simple <TMPL_VAR> tag.

As an example, consider a navbar that contains the username of the currently logged-in user.

Here is the page-fragment template for the navbar:

Current User: <TMPL_VAR NAME=login>
<br />
<ul>
  <li><a href="page1.html">Page 1</a>
  <li><a href="page2.html">Page 2</a>
  <li><a href="page3.html">Page 3</a>
</ul>

For this example, the corresponding subroutine is very simple. It's easy to imagine a situation where the navbar requires some complex logic that you are glad to hide behind a function call--for instance, when the selection of links depends on the permissions (found through a DB call) of the logged-in user.

Demonstrating the principle is straightforward; find the template fragment, set the required parameter, and render the template:

sub navbar { 
  my ( $login ) = shift;

  my $tpl = HTML::Template->new( filename => 'navbar.tpf' );
  $tpl->param( login => $login );
  return $tpl->output();
}

The master-page template then includes the navbar string using a <TMPL_VAR> tag. (Note the header inclusion through a <TMPL_INCLUDE> tag.)

<html>
  <head></head>
  <body>
    <table>
    <tr colspan="2">
      <td><TMPL_INCLUDE NAME=header.tpf></td>
    </tr>
    <tr>
      <td><TMPL_VAR NAME=navbar></td>
      <td> 
        <!-- Body goes here! -->
        ...
      </td>
    </tr>
    </table>
  </body>
</html>

This approach provides pretty good encapsulation: the code calling the navbar() routine does not need to know anything about its implementation--in fact, the subroutine can be in a separate module entirely. It is not far-fetched to imagine a shared module for all reusable page fragments used on the site.

Building Pages Inside Out

This development model still uses a separate, top-level template file for each page. All shared parts of the page are then included in this master template.

The widget approach can go a step further to do away entirely with the notion of having a separate master template for each page, by turning even the main body of the page into a widget or a collection of widgets. At this point, there may be only a single top-level template:

<html>
  <head></head>
  <body>
    <table>
    <tr colspan="2">
      <td><TMPL_INCLUDE NAME=header.tpf></td>
    </tr>
    <tr>
      <td><TMPL_VAR NAME=navbar></td>
      <td><TMPL_VAR NAME=mainbody></td>
    </tr>
    </table>
  </body>
</html>

A central Perl "controller" component dispatches page requests to the appropriate main-body widget (assuming you specify destination pages through a request parameter called action):

use CGI;
use HTML::Template;

my $q = CGI->new;
my $action = $q->param( 'action' );

# Dispatch to the desired main function
my $body_string = '';
if(    $action eq 'act1' ) { $body_string = act1( $q ); }
elsif( $action eq 'act2' ) { $body_string = act2( $q ); }
elsif( $action eq 'act3' ) { $body_string = act3( $q ); }

# Pull the current user from the query object and pass to the navbar
my $navbar_string = navbar( $q->param( 'login' ) );

# Set the rendered navbar and mainbody in the master template
my $tpl = HTML::Template->new( filename => 'tmpl3.tpl' );
$tpl->param( mainbody => $body_string );
$tpl->param( navbar   => $navbar_string );

print $q->header(), $tpl->output;

sub navbar { ... }

sub act1{ ... }
sub act2{ ... }
sub act3{ ... }

A Drop-down Widget

At this point, you may ask why you still need a template for the page fragment at all. Well, you don't--unless you find it convenient, of course.

There are two reasons to use a template: as a more suitable method of generating HTML than having to program a whole bunch of print statements, and to ensure separation of presentation from behavior. By encapsulating the nitty-gritty of HTML generation behind an API, you achieve the latter. How you go about the former depends entirely on the context. If you need to generate a lot of straight up HTML, with lots of <table>, <img>, and <form> tags, a template fragment makes perfect sense. But if it is actually easier to program the print statements yourself, there is nothing wrong with that--by encapsulating the HTML generation in a subroutine, you still achieve separation of presentation and main control flow and business logic.

As a classic example for something that is hard to express as a template, consider a drop-down menu with a default that has to be set programmatically. Attempting to do this using a template leads to a mess of template loops and conditionals. However, doing it in a widget subroutine is clean and easy, in particular if you use the appropriate functions from the standard CGI module:

sub color_select {
  my ( $default_color ) = @_;

  my @colors = qw( red green blue yellow cyan magenta );

  return popup_menu( 'color_select', \@colors, $default_color );
}

Include the string returned by this subroutine in a page template using <TMPL_VAR> tags as discussed previously.

Conclusion

This concludes a brief overview of some useful techniques for using HTML::Template that go beyond straight up variable replacement. I hope you enjoyed the trip.

There remains the question of when all of this is useful and suitable. To me, the beauty of HTML::Template is its utter simplicity. There isn't much in the way of creature comforts or "framework" features (such as forms processing or automated request dispatch). On the other hand, there is virtually no overhead: it's possible to understand the basic ideas of HTML::Template in five minutes or fewer, and it's easy to add to any simple CGI script. You don't need to design the project around the framework (as is often the case with more powerful but inevitably more complex toolsets). In fact, HTML::Template is so trivial to use that I use it in any CGI script that produces more than, say, 10 to 15 lines of HTML output. It's just convenient.

Filters and "widgets" as described in this series are easy ways to add some convenience features that are missing from HTML::Template. By bundling some repetitive code segments into a custom tag or a widget, you can keep both the code and template cleaner and simpler while at the same time continuing to enjoy the low overhead of HTML::Template.

However, there is only so much lipstick you can put on a pig. When you find ourselves building extensive libraries of custom tags or specific widgets, maybe you want to look more deeply into one of the existing frameworks for Perl web development, such as the Template Toolkit.

Of course, as long as you are happy with HTML::Template and it works for you, there is no reason to change. It works for me--and very well indeed.

Sidebar: Three Hidden Gems

HTML::Template has several useful and often overlooked minor features and options, (despite being clearly documented in POD). I want to point out three of the ones that are most commonly useful--all of which, by default, are (unfortunately, I think) turned off.

Permit Unused Parameters
my $tpl = HTML::Template->new( filename => '...', die_on_bad_params => 0 );

HTML::Template will die when it encounters an unused parameter in the template. In other words, if you set a parameter with $tpl->param(), but there is no corresponding <TMPL_VAR> in the template, template processing will fail by default. Setting the option die_on_bad_params to 0 disables this behavior.

Make Global Variables Visible In Loops
my $tpl = HTML::Template->new( filename => '...', global_vars => 1 );

By default, template loops open up a new scope, which makes all template parameters from outside the loop invisible within the loop. In particular, code like this will (by default) not work as expected:

Verbosity level: <TMPL_VAR NAME=isVerbose>
<ul>
<TMPL_LOOP NAME=rows>
  <li><TMPL_VAR NAME=rowitem>
    <TMPL_IF NAME=isVerbose>
      ... <!-- print additional, 'verbose' info -->
    </TMPL_IF>
</TMPL_LOOP>
</ul>

The verbose parameter, defined outside the loop scope will by default not be visible within the loop. Change this by setting the option global_vars to 1.

Special Loop Variables
my $tpl = HTML::Template->new( filename => '...', loop_context_vars => 1 );

Finally, enable a very useful little feature by setting loop_context_vars to 1. This defines several Boolean variables within each loop; they take on the appropriate value for each row:

  • __first__
  • __inner__
  • __last__
  • __odd__
  • __even__

There is also an integer variable __counter__, which is incremented for each row. Note that __counter__ starts at 1, in contrast to Perl arrays!

These variables are extremely useful in a variety of ways. For example, they make it easy to give every other row in a table a different background color to improve legibility. Together with filters (as described in my previous article), this allows for rather elegant template code:

<html>
<head>
  <style type="text/css">
    .odd  { background-color: yellow }
    .even { background-color: cyan }
  </style>
</head>

<body>
  <table>
  <TMPL_LOOP NAME=rows>
    <CSTM_ROW EVEN=even ODD=odd>
      <td> <TMPL_VAR NAME=__counter__> Cell contents... </td>
    </tr>
  </TMPL_LOOP>
  </table>
</body>
</html>

The appropriate filter for the new custom tag is:

sub cstmrow_filter {
  my $text_ref = shift;
  $$text_ref =~ s/<CSTM_ROW\s+EVEN=(.+)\s+ODD=(.*)\s*>
                 /<TMPL_IF NAME=__odd__>
                    <tr class="$1">
                  <TMPL_ELSE>
                    <tr class="$2">
                  <\/TMPL_IF>
                 /gx;
}

Note that, as implemented, the EVEN attribute must precede the ODD attribute in the <CSTM_ROW> tag.

Advanced HTML::Template: Filters

The CPAN module HTML::Template is a very simple, yet extremely useful module to achieve true separation of presentation and logic when programming CGI scripts. The basic idea is that, rather than having print statements scattered all through your code (the "classic" CGI approach), or mixing logic in with HTML (as in JSP, ASP, and Perl Mason), you maintain two files. One is the actual Perl script containing the business logic and the other one is a template file, containing exclusively presentation layer statements.

The template is straight-up HTML, augmented by a small set of special tags. The templating system replaces these tags by dynamic content. The dynamic content comes from a Perl data structure that you have built in your code.

Here is a minimal template and the corresponding script:

<html>
  <head></head>
  <body>
    <h1><TMPL_VAR NAME=title></h1>
    
    <ul>
      <TMPL_LOOP NAME=rows>
        <li><TMPL_VAR NAME=item>
      </TMPL_LOOP>
    </ul>
  </body>
</html>
#!/usr/bin/perl -w
use HTML::Template;

# Create the template object
my $tpl = HTML::Template->new( filename => 'tmpl1.tpl' );

# Set the parameter values
$tpl->param( title => "Useful Books" );
$tpl->param( rows => [ { item => "Learning Perl" },
                       { item => "Programming Perl" },
                       { item => "Perl Cookbook" } ] );

# Print
print "Content-Type: text/html\n\n", $tpl->output;

That's really all there is to it.

As Simple as Possible, but Not Simpler?

One of the nice things about HTML::Template is that doesn't try to do too much. It is a templating system for HTML, period. That keeps it simple and avoids complementary features, which could get in the way.

In this spirit, the module only offers a very, very limited set of tags, and no obvious way to extend this selection. Here is the complete list:

  • <TMPL_VAR>
  • <TMPL_LOOP>
  • <TMPL_IF>
  • <TMPL_ELSE>
  • <TMPL_UNLESS>
  • <TMPL_INLCUDE>

All of these tags do pretty much what you might expect: <TMPL_VAR> expands to dynamic text; <TMPL_LOOP> loops over an array; <TMPL_IF>, <TMPL_ELSE>, and <TMPL_UNLESS> provide a mechanism for conditional display; and <TMPL_INLCUDE> allows you to include pieces of other documents (such as a shared page header).

Most of the time, this is precisely what you want. All the facilities are there to control the display, but there is no danger in mixing general-purpose code in with the HTML template.

Yet, sometimes things can become unnecessarily clumsy--in particular, concerning the conditional display of information. A typical example concerns optional information. Suppose that you want to display a list of library books with their due dates, but should display the due date only if the book is currently checked out. (This is a surprisingly common pattern. Think of items with an optional sales price, accounts with an optional bad account status, a flight schedule with optional delay information, etc.)

Sometimes you can simply leave the corresponding variable blank:

<ul>
  <TMPL_LOOP NAME=books>
    <li><TMPL_VAR NAME=title>   <TMPL_VAR NAME=duedate>
  </TMPL_LOOP>
</ul>

and use the code:

$tpl->param( books => [ { title => 'Learning Perl', duedate => '' },
                        { title => 'Programming Perl', duedate => '29. Feb. 2008' } ] );

This will work. There will be no output for the due date if there is no due date. However, what if you want to have some additional text, in addition to the actual due date? That template might resemble:

<ul>
  <TMPL_LOOP NAME=books>
    <li><TMPL_VAR NAME=title>   
        <TMPL_IF NAME=duedate>
          Date due: <TMPL_VAR NAME=duedate>
        </TMPL_IF>
  </TMPL_LOOP>
</ul>

Do this a lot, and you will start looking for a better solution! (The main problem here is not actually the additional typing, but the fact that the template itself is becoming increasingly unwieldy and its structure harder to follow.)

One solution is to put the additional text in code:

$tpl->param( books => [ { title => 'Learning Perl', duedate => '' },
                        { title => 'Programming Perl', duedate => 'Date due: 29. Feb. 2008' } ] );

However, this is clumsy: it breaks the separation of presentation and behavior, as there is now strictly presentational material such as "Date due: " in the Perl code, and it makes the parameter less generally useful. If you want the plain date somewhere else in the template, it now comes bundled with a string that you may not want.

Wouldn't it be nice if you could bundle the entire optional part of each list entry ("encapsulate it," if you will) and simply call it by name? To put it in other words, what if you had the ability to define a custom tag?

Enabling Custom Tags Using Filters

This is where filters come in. A filter is a subroutine called on the template text before tag substitution takes place. A filter can do anything. In particular, it can modify the template programmatically.

A filter is precisely the hook into the template processing that is necessary to enable custom tags. Write your template in terms of standard template tags and your own custom tags. Then provide a filter (or filters) to replace these custom tags with the appropriate combinations of standard tags. The HTML::Template "engine" then does the final substitutions and renders the ultimate output.

For the library example, suppose that you have chosen to use a custom tag <CSTM_DUEDATE> to display the optional due date. This makes the template look very clean and simple:

<ul>
  <TMPL_LOOP NAME=books>
    <li><TMPL_VAR NAME=title>   <CSTM_DUEDATE>
  </TMPL_LOOP>
</ul>

The code to set the template parameter values does not change, but you now need to define the filter (and note that you need to escape the slash in the </TMPL_IF>):

sub duedate_filter {
  my $text_ref = shift;
  $$text_ref =~ s/<CSTM_DUEDATE>/<TMPL_IF NAME=duedate>Date due: <TMPL_VAR NAME=duedate><\/TMPL_IF>/g;
}

Finally, you need to register this filter, so that the module will call it before tag substitution takes place. Filters are options to the template object, so registration takes place when you construct the template:

$tpl = HTML::Template->new( filename => 'books.tpl', 
                            filter => \&duedate_filter );

That's the basic idea. If you wanted to, you could register a sequential collection of filters (one filter per custom tag?) or you can put all required substitutions into a single routine. I can certainly perceive of the possibility of developing reusable "tag libraries" as Perl modules with filter definitions. Interestingly (and in contrast to JSP), the template files themselves do not need to know about the definitions and behavior of the "custom tags." I think this is exactly right: the templates are plain ("dumb") text files, which define the presentation layer. All the behavior is in the Perl code, where it belongs.

Data-Sensitive Displays and Data Filters

Consider another example application. Rather than dealing with optional information, this one uses conditional formatting.

Assume that you have a list of accounts, and each account has a various state: "Good," "Bad," and "Canceled." You would like to display the account number in a different color, depending on the state: green for "Good," yellow for "Bad," and red for "Canceled."

If you tried to do this using <TMPL_IF> tags, this would be a real mess, for two reasons: You have more than two choices, so that we can't use a <TMPL_IF>...<TMPL_ELSE>...</TMPL_IF> construct; instead you would have to use a sequence of individual conditionals: <TMPL_IF>...</TMPL_IF><TMPL_IF>...</TMPL_IF><TMPL_IF>...</TMPL_IF>. Moreover, <TMPL_IF> does not allow for arbitrary conditional expressions (such as $status eq 'good'). All it does is test a Boolean variable. The classic approach is to introduce three Boolean dummy variables: $isGood, $isBad, and $isCancelled to use in these tests. There's certainly a better way!

Instead, introduce a custom tag that allows for configurable formatting:

<CSTM_SPAN NAME=...>

Here is the associated filter:

sub span_filter {
  my $text_ref = shift;
  $$text_ref =~ s/<CSTM_SPAN\s+NAME=(.*?)\s*>
                 /<span class='<TMPL_VAR NAME=$1_class>'>
                    <TMPL_VAR NAME=$1>
                  <\/span>
                 /gx;
}

If you use this custom tag in your template as <CSTM_SPAN NAME=account>, then the template in the intermediate state, after filter application, but before template parameter substitution, will look like:

<span class='<TMPL_VAR NAME=account_class>'>
  <TMPL_VAR NAME=account>
</span>

The original single custom tag has expanded into an HTML <span> tag wrapping the actual dynamic content. The <span> defines a CSS class to provide formatting to the dynamic content. The name of the CSS class itself is dynamic, too--so that you can select the classes .bad or .good depending on the value of the account status. The name of the CSS class comes from the name of the displayed parameter. If this class is defined in a stylesheet or within the HTML document itself, a CSS-capable client will apply it to the dynamic text as expected.

In other words, the innocuous <CSTM_SPAN> tag actually requires two parameters: one containing the text to display and the other specifying the CSS class to apply. All you need to do is to set the account_class parameter to the appropriate value in Perl code (and, of course, define the CSS classes somewhere in the stylesheet.)

Here is a slick way to stay in control doing this. You can call the param() function either with individual name/value-pairs (as I have shown before), or with a hash-ref: $tpl->param( { key1 => value1, key2 => value2 } ). In other words, rather than calling param() repeatedly throughout your code, setting individual parameters, you can build up one large hash, containing all parameters, and then pass it to the template in a single call.

Now you can apply the filter trick that worked so well for the template itself, on the parameters as well! In other words, before calling $tpl->param( \%parameter_hash), pass the hash to a subroutine, which performs data filtering operations on the parameters. In this case, it adds the CSS class appropriate for the account status for each account in the data structure.

This approach centralizes all data-dependent display decisions in a single subroutine. If you add further status codes, or if you want to change the display class, there is only a single location to edit.

Here is a Perl program demonstrating these concepts:

#!/usr/bin/perl -w
use HTML::Template;

# Create the template object
my $tpl = HTML::Template->new( filename => 'tmpl4.tpl',
                               filter => \&span_filter );

# Build a data structure containing all the parameters
my %params = ( title => "Accounts",
               accounts => [ { account => 'Good' }, { account => 'Bad' } ] );

apply_display_logic( \%params );

# Set all parameters for the template at once
$tpl->param( \%params );

# Print
print "Content-Type: text/html\n\n", $tpl->output;

# ---

sub span_filter {
  my $text_ref = shift;
  $$text_ref =~ s/<CSTM_SPAN\s+NAME=(.*?)\s*>
                 /<span class='<TMPL_VAR NAME=$1_class>'>
                    <TMPL_VAR NAME=$1>
                  <\/span>
                 /gx;
}

sub apply_display_logic {
  my $hash_ref = shift;

  my %account_classes = ( Good => 'good', Bad => 'bad' );

  foreach my $acc ( @{ $hash_ref->{ accounts } } ) {
    $acc->{account_class} = $account_classes{ $acc->{account} };
  }
}

#%@$! Happens

When I first explained this idea to a colleague, his reaction was: "Great. You go down that path and you are going to end up with JSP. Is that what you want?" To which my response was: "Well, fertilizer happens."

GUI development is a pain. Always. You cannot avoid all issues regarding the separation of presentation and logic in GUI development. The challenge in my opinion is therefore not to find the ideal web development framework, but the optimal one for the task at hand.

HTML::Template is very, very good for rather simple, minimum fuss, straightforward websites (of which there are significantly more than anyone might want to admit). It is particularly well-suited for reports and stats. In this application domain, the ability to the define custom tags to take care of formatting and special presentation issues is a distinct advantage.

Conclusion

In the second part of this series, I will take these ideas a step further and explore how to use HTML::Template to create GUI-like widgets in a web/CGI situation.

Rapid Website Development with CGI::Application

This article provides an update on the popular and mature CGI::Application framework for web applications. It assumes a basic understanding of the system, so reviewing the previous Perl.com article about CGI::Application may be helpful background reading.

CGI::Application and Catalyst Compared

You may recall the Perl.com article on another MVC web framework, Catalyst. First, I want to clear up possible confusion by explaining how the CGI::Application and Catalyst relate.

With the many plugins available for CGI::Application and Catalyst, both frameworks offer many of the same features.

Both provide convenient methods to access many of the same underlying modules including Data::FormValidator, HTML::FillInForm and templating systems such as Template Toolkit and HTML::Template.

Both frameworks work in CGI and mod_perl environments, although CGI::Application loads faster in CGI. Each one provides unique features to help with development and debugging. Catalyst includes a built-in web server for easy offline testing and development. CGI::Application provides a persistent development pop-up window that provides convenient reports on HTML validation, application performance, and more.

While CGI::Application and Catalyst share many of the same strengths, they also face the same challenge of attracting users and developers.

As the expectations for web site features and quality increase, the toolkit that a web developer depends on must increase and expand as well. The more plugins that are compatible with our framework, the easier our job is. We each have a selfish incentive to attract others to use the same framework. Users become contributors, and contributors write plugins to make our lives easier.

CGI::Application and Catalyst already share users and developers of many of the Perl modules they depend on. With PHP and Ruby on Rails both on the rise as web development solutions, those who prefer Perl have an incentive to promote the best the language has to offer.

What A Difference Half A Decade Makes

CGI::Application development took off around the 4.0 release for two reasons. To start with, it formalized a plugin system, which led to the release of some initial plugins. Next, the 4.0 release added a callback system, allowing the plugin authors to automatically add actions that take place at particular points in the request cycle.

For example, the AutoRunmode plugin registers itself at the "prerun" phase, allowing it to adjust which run mode is selected. Another plugin might register to add a cleanup action in the "teardown" phase.

The combined result was a boom in plugin development. While the core of CGI::Application has remained small and stable, there are over three dozen plugins now on the CPAN.

Here's a tour of some of the enhancements that have come about as a result of the new plugin and callback system.

Simplified Runmode Syntax

The built-in way to register a run mode typically involves calling run_modes() within setup():

sub setup {
   my $self = shift;
   $self->run_modes([qw/
        my_run_mode
   /]);
}

# later...
sub my_run_mode {
 ...
}

With the AutoRunmode plugin, it's now very easy to declare that a method is a "run mode" handling a CGI request rather than an internal function. The syntax is simply:

    sub my_run_mode : Runmode {
        my $self = shift;
        # ...    
    }

You can still use setup(), but it's no longer necessary.

New Dispatcher Provides Clean URLS

A large project built with CGI::Application typically has many small "instance scripts" that drive modules full of run modes. All of these instance scripts look basically the same:

use Project::Widget::View;
my $app = Project::Widget::View->new();
$app->run();

A corresponding URL might look like:

/cgi-bin/project/widget/view.cgi?widget_id=23

CGI::Application::Dispatch 2.0 allows you to replace all of these instance scripts with a single dispatch script to produce much cleaner URLs. Such a dispatch script might look like:

#!/usr/bin/perl
use CGI::Application::Dispatch;
CGI::Application::Dispatch->dispatch(
        prefix              => '',
        table               => [
            ':app/:rm/:id'  => {},
        ],

);

Now add a dash of mod_rewrite magic provided in the documentation, and the URL will transform from:

/cgi-bin/project/widget/view.cgi/detailed_view?widget_id=23

to:

/widget/detailed_view/23

Clean and simple.

The widget_id is easily accessible from within the run mode:

my $widget_id = $self->param('id');

The dispatcher takes care of that detail for you, saving some manual munging of PATH_INFO.

First-Class Templating Support

While CGI::Application integrates by default with HTML::Template, it seems an equal number of the users prefer the Template Toolkit templating system. Both camps now have access to several new templating-related features.

Default template names

To keep the code cleaner and consistent, it's now possible to generate template names automatically. Typically, you want to load one template to correspond with each run mode. Simply loading a template might look like:

    sub my_run_mode: Runmode {
        my $self = shift;

        # XXX The old way, with redundant file name 
        # my $t = $self->load_tmpl('my_run_mode.html');

        # Look Ma! No explicit file name needed!
        my $t = $self->load_tmpl;
        return $t->output;
    }

Easy access to the application object from the template

The TT plugin introduced easy access to the CGI::Application object from the template, allowing easy constructions by using the c parameter to access the application object.

Hello [% c.session.param('username') || 'Anonymous User' %]
<a href="[% c.query.self_url %]">Reload this page</a>

Authors of open source web applications will surely appreciate the AnyTemplate plugin, which allows you to use a single templating syntax in your code, and lets users choose the templating system that best integrates with their existing project. There was no ready-made way to do this in the past.

Conveniently, HTML::Template and TT users can use a familiar syntax to drive AnyTemplate.

TT style:

$self->template->process('file_name', \%params);

HTML::Template style:

# Yes, it really can be identical to the standard load_tmpl() syntax!
my $template = $self->load_tmpl('file_name');
$template->param('foo' => 'bar');
$template->output;

A great example of this template abstraction is CGI::Application::Search, a reusable application that integrates with the Swish-E search engine. Whether you prefer HTML::Template or Template Toolkit, it's easy to add this as a search solution for a larger project--even if the rest of your website does not use CGI::Application.

CGI::Application also offers improved support for other output formats. The Stream plugin makes it a snap to stream a document to the user, such as a PDF or Excel file that is built on the fly. This saves the busy work of remembering the related details for unbuffered output, binmode, file chunking, and MIME types. That now takes basically one line of syntax:

$self->stream_file( $file );

The XSV plugin simplifies building CSV files. This tedium is now a single function call for simple cases:

  return $self->xsv_report_web({
    fields     => \@headers,
    # Get values from the database
    values     => $sth->fetchall_arrayref( {} );
    csv_opts   => { sep_char => "\t" },
    filename   => 'members.csv',
  });

Lazier Than Ever

One frequent feature you'll find in CGI::Application plugins is lazy loading. This means that loading and configuring the plugin often has little resource penalty. Take the DBH plugin. It's convenient to configure the database handle once for a whole website project and then use the handle whenever you want.

Before this plugin arrived, it would be tempting to stuff the database handle into the param method to achieve a similar effect:

sub cgiapp_init {
    my $self = shift;

    my $dbh = DBI->connect($data_source, $username, $auth, \%attr);

    # save for later!
    $self->param('dbh',$dbh);
}

That works OK, but it misses a valuable feature: lazy loading.

Lazy loading creates the database connection only if any code needs to use it. This avoids needlessly creating a database connection for scripts that don't need it, while still being very convenient. Here's an example:

# define the database connection parameters once in a super class, for a whole
# suite of child applications:

sub cgiapp_init  {
   my $self = shift;

   # use the same args as DBI->connect(); 
   $self->dbh_config($data_source, $username, $auth, \%attr);

}

Then, whenever you need a database handle:

sub my_run_mode : Runmode {
    my $self = shift;
    my $result = $self->dbh->selectrow("...");
    # ...
}

Easy. dbh_config() will get called on every request, but it simply stores the configuration details. The database handle gets created only during calls to the dbh() method.

Another notable lazy-loading plugin is the Session plugin, which provides easy access to a CGI::Session object. It further takes advantage of the CGI::Application framework by automatically setting the session cookie for you, so you don't have to deal with cookies unless you want to.

Ready for High-Performance Environments

I mostly use CGI::Application with plain CGI, because it performs well enough and works well in a shared hosting environment since no resources persist between requests.

However, CGI::Application is ready for high-performance applications.

Often, code written for CGI::Application will run without changes under mod_perl's Apache::Registry mode, as 1-800-Save-A-Pet.com does.

To squeeze a little more juice out of mod_perl, there is an Apache plugin, which uses Apache::Request instead of CGI.pm.

A current popular alternative for increasing performance is FastCGI. Use CGI::Application::FastCGI, and add, usually, just one line of code to make your application work in this environment.

Easy Form Handling

A lot of tedium can be involved in processing web forms. The first plugin, ValidateRM, helped with that.

my $results =  $self->check_rm('display_form', '_form_profile' ) 
   || return $self->dfv_error_page;

This simple syntax calls a Data::FormValidator profile into action. If validation fails, the page with the original form is redisplayed with the previous values intact, and error messages appear next to each field that is missing or invalid.

Fans of Data::FormValidator will appreciate an upcoming related module from the CGI::Application community: JavaScript::DataFormValidator.

This module makes it easy to use the same Perl data structure to add an additional level of validation in JavaScript. I expect Catalyst and CGI::App users alike will be putting this to use.

Finally, there's a new plugin to simplify filling in a web form from a database record. This is the FillInForm plugin. The syntax is simple:

   # fill in the HTML form from the query object
    $self->fill_form($html);

In part, this plugin solves bug #13913 in HTML::FillInForm, which means the interface detects what kind of input you are giving it, rather than requiring you to explicitly declare that you have hashref or scalarref and so forth. As you can see from the example, if you are using the query object as input, you don't need to pass it in at all.

DevPopUp: A Unique Developer Tool

CGI::Application offers a unique developer tool in the form of the DevPopUp plugin. You can see DevPopUp in action on Rhesa's demo site. (Make sure your pop-up blocker doesn't trap it!).

The tool creates a persistent pop-up window that gives you feedback about each run mode as soon as it completes. "What were the HTTP Headers? How long did it take? Was the resulting HTML valid?"

The real kicker is that DevPopUp is itself pluggable, allowing other developers to add their own reports. I look forward to Sam Tregar releasing his graphical DBI profiling tool, which would make a nice addition here.

Easier Error Messages with DebugScreen

CGI::Application users in Japan recently brought us the DebugScreen plugin. This is a welcome change from referencing the web server log to find the most recent line that needs debugging.

Hello, Web 2.0: AJAX Integration

In another story of cross-pollination with Catalyst, CGI::Application integrates easily with the JavaScript Prototype library. Prototype provides easy access to plenty of interesting AJAX effects, such as auto-completing based on a lookup to the server. This uses a thin plugin-wrapping HTML::Prototype, which was written with Catalyst in mind.

CGI::Application and Catalyst

The appearance of Catalyst has been a great benefit to the CGI::Application community. Both projects support the use and development of focused, reusable components. When a new patch arrives for a module both projects use, both projects benefit. As the maintainer of Data::FormValidator, I'm well aware that the two camps are collaborating through this project.

Catalyst releases its code under a license that allows CGI::Application to reuse and integrate their work (and vice-versa). Often a plugin written for Catalyst takes only a little effort to port to work with CGI::Application. For example, Catalyst recently added PAR support, which allows the distribution and execution of a complex web application as a single binary. This helps a Perl project with complex module dependencies compete with the installation ease of typical PHP software.

This will be a great reference as CGI::Application users evaluate options for easier web application deployment.

Finally, Catalyst demonstrates an alternate approach as a web framework. This helps the CGI::Application community better evaluate their own options.

Conclusion

CGI::Application has always been about providing a clean structure for web applications. With the advent of myriad plugins, it is also about simplifying access to the many great tools that Perl offers web developers through the CPAN. With more plugins being developed on a regular basis, the life of the web developer is getting easier by the day.

Visit the home of the Perl programming language: Perl.org

Sponsored by

Powered by Movable Type 5.02