NAME
CGI::Prototype - Create a CGI application by subclassing
SYNOPSIS
package My::HelloWorld;
use base CGI::Prototype;
sub template { \ <<'END_OF_TEMPLATE' }
[% self.CGI.header; %]
Hello world at [% USE Date; Date.format(date.now) | html %]!
END_OF_TEMPLATE
My::HelloWorld->activate;
DESCRIPTION
The core of every CGI application seems to be roughly the same:
Analyze the incoming parameters, cookies, and URLs to determine the state of the application (let's call this "dispatch").
Based on the current state, analyze the incoming parameters to respond to any form submitted ("respond").
From there, decide what response page should be generated, and produce it ("render").
CGI::Prototype creates a Class::Prototyped engine for doing all this, with the right amount of callback hooks to customize the process. Because I'm biased toward Template Toolkit for rendering HTML, I've also integrated that as my rendering engine of choice. And, being a fan of clean MVC designs, the classes become the controllers, and the templates become the views, with clean separation of responsibilities, and CGI::Prototype a sort of "archetypal" controller.
You can create the null application by simply activating it:
use CGI::Prototype;
CGI::Prototype->activate;
But this won't be very interesting. You'll want to subclass this class in a Class::Prototyped-style manner to override most of its behavior. Slots can be added to add or alter behavior. You can subclass your subclasses when groups of your CGI pages share similar behavior. The possibilities are mind-boggling.
Within the templates, self refers to the current controller. Thus, you can define callbacks trivially. In your template, if you need some data, you can pull it as a request:
[% my_data = self.get_some_big_data %]
which is supplied by simply adding the same slot (method or data) in the controlling class:
sub get_some_big_data {
my $self = shift;
return $self->some_other_method(size => 'big');
}
And since the classes are hierarchical, you can start out with an implementation for one page, then move it to a region or globally quickly.
Although the name CGI::Prototype implies a CGI protocol, I see no reason that this would not work with Apache::Registry in a mod_perl environment, or a direct content handler such as:
package My::App;
use base CGI::Prototype;
sub handler {
__PACKAGE__->activate;
}
Note that the $r request object will have to be created if needed if you use this approach.
CORE SLOTS
These slots provide core functionality. You will probably not need to override these.
- activate
-
Invoke the
activateslot to "activate" your application, causing it to process the incoming CGI values, select a page to be respond to the parameters, which in turn selects a page to render, and then responds with that page. For example, your App might consist only of:package My::App; use base qw(CGI::Prototype); My::App->activate;Again, this will not be interesting, but it shows that the null app is easy to create. Almost always, you will want to override some of the "callback" slots below.
- CGI
-
Invoking
$self->CGIgives you access to the CGI.pm object representing the incoming parameters and other CGI.pm-related values. For example,$self->CGI->self_urlgenerates a self-referencing URL. From a template, this is:
[% self.CGI.self_url %]for the same thing.
- render
-
The
rendermethod uses the results fromengineandtemplateto process a selected template through Template Toolkit. If the result does not throw an error,$self->displayis called to show the result. - display
-
The
displaymethod is called to render the output of the template under normal circumstances, normally dumping the first parameter toSTDOUT. Test harnesses may override this method to cause the output to appear into a variable, but normally this method is left alone. - param
-
The
parammethod is a convenience method that maps to$self->CGI->param, because accessing params is a very common thing.
CALLBACK SLOTS
- engine
-
The engine returns a Template object that will be generating any response. The default Template object has no parameters passed to
new. Almost all real applications overrideengineto define search paths and other Template Toolkit configuration items.If you're using this in a mod_perl environment, you should use
Class::Prototyped's "autoload" field, to avoid recreating the object repeatedly. Or, a lower-tech approach might be:sub engine { my $self = shift; require Template; our $engine ||= Template->new({ POST_CHOMP => 1 }); return $engine; # (excessive redundancy) } - app_enter
-
Called when the application is entered, at the very beginning of each hit. Defaults to no action.
- app_leave
-
Called when the application is left, at the very end of each hit. Defaults to no action.
- control_enter
-
Called when a page gains control, either at the beginning for a response, or in the middle when switched for rendering. Defaults to nothing.
This is a great place to hang per-page initialization, because you'll get this callback at most once per hit.
- control_leave
-
Called when a page loses control, either after a response phase because we're switching to a new page, or render phase after we've delivered the new text to the browser.
This is a great place to hang per-page teardown, because you'll get this callback at most once per hit.
- render_enter
-
Called when a page gains control specifically for rendering (delivering text to the browser), just after
control_enterif needed. - render_leave
-
Called when a page loses control specifically for rendering (delivering text to the browser), just before
control_leave. - respond_enter
-
Called when a page gains control specifically for responding (understanding the incoming parameters, and deciding what page should render the response), just after
control_enter. - respond_leave
-
Called when a page loses control specifically for rendering (understanding the incoming parameters, and deciding what page should render the response), just before
control_leave(if needed). - template
-
Delivers a template document object (something compatible to the
Templateprocessmethod, such as aTemplate::Documentor a filehandle or a reference to a scalar). The default is a simple "this page intentionally left blank" template.When rendered, the only extra global variable passed into the template is the
selfvariable, representing the controller object. However, as seen earlier, this is sufficient to allow access to anything you need from the template, thanks to Template Toolkit's ability to call methods on an object and understand the results.For example, to get at the
barneyparameter:The barney field is [% self.param("barney") | html %]. - error
-
Called if an uncaught error is triggered in any of the other steps, passing the error text or object as the first method parameter. The default callback simply displays the output to the browser, which is highly insecure and should be overridden, perhaps with something that logs the error and puts up a generic error message with an incident code for tracking.
- dispatch
-
Called to analyze the incoming parameters to define which page object gets control based on the incoming CGI parameters.
This callback must return a page object (the object taking control during the response phase). By default, this callback returns the application itself.
- respond
-
Called to determine how to respond specifically to this set of incoming parameters. Probably updates databases and such.
This callback must return a page object (the object taking control during the render phase). By default, this callback returns the same object that had control during the response phase ("stay here" logic), which works most of the time.
SEE ALSO
Class::Prototyped, Template::Manual, http://www.stonehenge.com/merlyn/LinuxMag/col56.html.
AUTHOR
Randal L. Schwartz, <merlyn@stonehenge.com>
Special thanks to Geekcruises.com and an unnamed large university for providing funding for the development of this module.
COPYRIGHT AND LICENSE
Copyright (C) 2003, 2004 by Randal L. Schwartz
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.5 or, at your option, any later version of Perl 5 you may have available.