modulereview
rob_au
<br/> <br/>
<font size="+2"><b>CGI::Application</b></font>
<br/> <br/>
<br/> <br/>
<i>Item description :</i> Framework for building reusable web-applications in an object-orientated and extensible fashion<br/>
<i>Review Synopsis :</i> An excellent and well-thought out module implementing powerful and downright easy methods to write and build CGI-based applications.
<br/> <br/>
<br/> <br/>
<font size="+1"><b>Why use CGI::Application?</b></font>
<br/> <br/>
<br/> <br/>
The [cpan://CGI::Application] module implements this object-orientated framework within which to build your application by creating a super-class within which specific 'run-modes' can be defined. Each run-mode can be correlated to a particular stage of the HTML/CGI user interface. Furthermore, the [cpan://CGI::Application] module implements methods to address the [cpan://CGI].pm and [cpan://HTML::Template] modules, facilitating powerful methods by which to build extensible and portable web applications - It is obvious that the module author, Jesse Erlbaum (jesse at vm dot com), has put a lot of work into the development and writing of this module.
<br/> <br/>
This module allows you to do away with ugly code through the combination of [cpan://CGI].pm, [cpan://HTML::Template] and methods provided by [cpan://CGI::Application] to implement persistent variables across execution states.
<br/> <br/>
(Part of the reason too as to my personal usage of this module is its integration with my preferred templating framework, [cpan://HTML::Template] - Different web application frameworks were reviewed by [princepawn] at [Web Application Frameworks and their Templating Engines with a Comparative Study of Template and HTML::Template])
<br/> <br/>
<br/> <br/>
<font size="+1"><b>Why avoid CGI::Application?</b></font>
<br/> <br/>
<br/> <br/>
There seems to be few reasons why to avoid using the [cpan://CGI::Application] module - Usage may not be necessary if persistence and state methods are implemented with other frameworks such as [cpan://Apache::Session], [cpan://HTML::Mason] or [cpan://HTML::Embperl].
<br/> <br/>
<br/> <br/>
<font size="+1"><b>How to use CGI::Application?</b></font>
<br/> <br/>
<br/> <br/>
The documentation for the [cpan://CGI::Application] module is excellent and covers the building of a (theoretical) database search application. In short, this module promotes the building of applications as self-styled modules based on the [cpan://CGI::Application] framework - The end script (application) consists of an instance script and a module package.
<br/> <br/>
An example instance script may look like this:
<br/> <br/>
<dl><dd><code>
#!/usr/bin/perl
# Use our self-styled application module built on the CGI::Application framework
#
use self;
# Create constructor for our application module (self->new()) and execute this module in the desired run mode (self->run()) - The desired run mode is set via the value of a CGI parameter specified by the mode_param() method of this module (see self-styled CGI::Application module package).
#
my ($application) = self->new();
$application->run();
exit 0;
</code></dd></dl>
<br/> <br/>
The corresponding module (self) based on the [cpan://CGI::Application] framework may look like this:
<br/> <br/>
<dl><dd><code>
package self;
sub setup {
my ($self) = shift;
# Set the CGI parameter from which the run-mode of the application is derived to be 'stage' - This method allows you to set your own run-mode specifier, passed to your CGI script via hidden HTML form input tags
#
$self->mode_param('stage');
# Set the matched run-mode / subroutine functions to determine which function should be executed for a given run-mode - This method is that which allows reusable code to be easily implemented for separate run-mode.
#
# In this example, the subroutines 'display_form' and 'display_results' have been specified to run for run-modes '1' and '2' respectively. The subroutines can be defined as either a hard reference to the run-mode method or the name of the run-mode method to be called.
#
$self->run_modes({
'1' => \&display_form,
'2' => 'display_results',
});
# Set the mode which should be run in the first instance of the script, where no run-mode may be specified by a passed CGI variable - By default, this mode is called 'start', which too must be referenced to a subroutine via the run_modes() method.
#
$self->start_mode('1');
};
1;
</code></dd></dl>
<br/> <br/>
This is a very basic example of the totality of module framework required to implement the [cpan://CGI::Application] framework - The example above is lacking the referenced subroutines display_form and display_results but provides a clear example of HOW the module framework works.
<br/> <br/>
Additional methods within the [cpan://CGI::Application] framework include:
<br/> <br/>
<dl><dd>
<b>param()</b>
<br/> <br/>
<dl><dd>This method allows to create parameter references which can be referenced across all module/application run modes - This method is most obviously used in the setup() method to implement such references such as [cpan://DBI] connections, [cpan://HTML::FormValidator] schema, etc. eg.
<dl><dd><code>
sub setup {
my ($self) = shift;
$self->mode_param('stage');
$self->run_modes({
'1' => \&display_form,
'2' => 'display_results',
});
$self->start_mode('1');
# Create DBI connection handle and make accessible to all run-modes via CGI::Application param() method
#
$self->param('dbh' => DBI->connect());
};
</code></dd></dl></dd></dl>
<b>teardown()</b>
<br/> <br/>
<dl><dd>The paired partner of setup(), this method is implemented automatically after the application is run and can be used for clean up persistent variable and database connections. eg.
<br/> <br/>
<dl><dd><code>
sub teardown {
my ($self) = shift;
# Disconnect the (persistent, with Apache::DBI) DBI handle created in setup() and passed via the param() method
#
$self->param('dbh')->disconnect;
};
</code></dd></dl></dd></dl>
<br/> <br/>
<b>query()</b>
<br/> <br/>
<dl><dd>This method retrieves the [cpan://CGI].pm object (<code>CGI->new()</code>) created with the instance of your self-styled [cpan://CGI::Application] module. All methods for [cpan://CGI].pm can be applied to the blessed reference returned.</dd></dl>
<br/> <br/>
<b>load_tmpl()</b>
<br/> <br/>
<dl><dd>This method creates a [cpan://HTML::Template] object (<code>HTML::Template->new()</code>), allowing HTML templates to be employed, aiding in the pyrrhic (depending on your viewpoint) goal of separating code and design. All methods for [cpan://HTML::Template] can be applied to the blessed reference returned.</dd></dl>
</dd></dl>
<br/> <br/>
<font size="+1"><b>Tips and Gotchas for CGI::Application</b></font>
<br/> <br/>
<br/> <br/>
The primary note made about run-mode methods in the [cpan://CGI::Application] documentation is to avoid printing directly to STDOUT, instead returning the HTML output (<code>$html->output</code>, if $html is a [cpan://HTML::Template] blessed reference created via <code>load_tmpl()</code>) at the end of the run-mode subroutine to the [cpan://CGI::Application] framework.
<br/> <br/>
For example:
<br/> <br/>
<dl><dd><code>
# An example run-mode method
#
sub display_page {
my ($self) = shift;
# Create a HTML::Template blessed reference with the template file, page.html
#
my ($html) = $self->load_tmpl('page.html');
print STDOUT $html->output; # printing template output directly to STDOUT (*BAD*)
return $html->output; # return template output to CGI::Application framework for display (*GOOD*)
};
</code></dd></dl>
<br/> <br/>
With the handling of HTML output to STDOUT by the [cpan://CGI::Application] framework rather than within the run-mode subroutine itself, header types and properties should also not be directly manipulated via CGI methods within run-mode methods. Instead, the [cpan://CGI::Application] framework provides two methods for handling header types and properties indirectly - These methods are described below:
<br/> <br/>
<dl><dd>
<b>header_type(<'header' || 'redirect'>)</b>
<br/> <br/>
<dl><dd>This method specifies the type of HTTP headers which should be sent back to the client browser by the [cpan://CGI::Application] framework.</dd></dl>
<br/> <br/>
<b>header_props()</b>
<br/> <br/>
<dl><dd>This method specifies the HTTP header properties which should be sent back to the client browser by the [cpan://CGI::Application] framework - This method correlates to the <code>header()</code> (and <code>redirect()</code>) methods of the [cpan://CGI].pm module.</dd></dl>
</dd></dl>
<br/> <br/>
Another tip in the documentation of [cpan://CGI::Application] is the definition the run-mode '<code>AUTOLOAD</code>' - This run-mode is evoked if the <code>mode_param()</code> CGI parameter calls a run-mode definition not matched to a package subroutine via <code>run_modes()</code> method. This allows the the implementation of 'user-friendly' error pages rather than the default [cpan://CGI::Application] behaviour to <code>croak()</code> on such errors. If evoked, the name of the intended run-mode passed via the <code>mode_param()</code> CGI parameter is passed to the <code>AUTOLOAD</code> run-mode as an argument.
Framework for building reusable web-applications in an object-orientated and extensible fashion