package CGI::Prototype; use 5.006; use strict; use warnings; use base qw(Class::Prototyped); ## no exports our $VERSION = '0.9053'; our $_mirror = __PACKAGE__->reflect; # for slots that aren't subs =head1 NAME CGI::Prototype - Create a CGI application by subclassing =head1 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; =head1 DESCRIPTION The core of every CGI application seems to be roughly the same: =over 4 =item * Analyze the incoming parameters, cookies, and URLs to determine the state of the application (let's call this "dispatch"). =item * Based on the current state, analyze the incoming parameters to respond to any form submitted ("respond"). =item * From there, decide what response page should be generated, and produce it ("render"). =back L creates a C 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 C a sort of "archetypal" controller. You can create the null application by simply I it: use CGI::Prototype; CGI::Prototype->activate; But this won't be very interesting. You'll want to subclass this class in a C-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, C 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 C implies a CGI protocol, I see no reason that this would not work with C in a C environment, or a direct content handler such as: package My::App; use base CGI::Prototype; sub handler { __PACKAGE__->activate; } Note that the C<$r> request object will have to be created if needed if you use this approach. =head2 CORE SLOTS These slots provide core functionality. You will probably not need to override these. =over 4 =item activate Invoke the C slot 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. =cut sub activate { my $self = shift; eval { $self->prototype_enter; $self->app_enter; my $this_page = $self->dispatch; $this_page->control_enter; $this_page->respond_enter; my $next_page = $this_page->respond; $this_page->respond_leave; if ($this_page ne $next_page) { $this_page->control_leave; $next_page->control_enter; } $next_page->render_enter; $next_page->render; $next_page->render_leave; $next_page->control_leave; $self->app_leave; $self->prototype_leave; }; $self->error($@) if $@; # failed something, go to safe mode } =item CGI Invoking C<< $self->CGI >> gives you access to the CGI.pm object representing the incoming parameters and other CGI.pm-related values. For example, $self->CGI->self_url generates a self-referencing URL. From a template, this is: [% self.CGI.self_url %] for the same thing. See C for how this slot gets established. =cut $_mirror->addSlot (CGI => sub { die shift, "->initialize_CGI not called" }); =item render The C method uses the results from C and C