On Tue, 2005-01-04 at 00:14 +0000, Tony Bowden wrote:
> On Mon, Jan 03, 2005 at 06:21:14PM -0500, Perrin Harkins wrote:
> > I structure my web applications so that common code can be added to all
> > requests in a central place (some kind of common "setup" hook).  I
> > usually put my $tt->process inside of some wrapper function as well,
> > since I want it to be a singleton.  
> 
> Care to share an example?

Using something like CGI::Application does provide an easy place to put
common code.  When I use it, I make a base class that contains my common
setup code.

I've also rolled my own controller many times, and in those I typically
have a base class with a run() method that wraps the request handler in
an eval block and deals with logging errors.  That's a place to put
common code, or I might divide it further with subclasses
(My::Controller subclassed by My::Controller::Protected or some such).

At the end of a request, I will call a template wrapper method something
like this (the "P3" namespace is for Plus Three, my employer):

sub process_template {
    # this is a class method, not an object method!
    my $class = shift;
    my %args = @_;

    # add in the config object
    my $config = P3::Model::Config->new();
    $args{'DATA'}->{'config'} = $config->view();

    # put in the escaping functions
    $args{'DATA'}->{'html'} = \&Apache::Util::escape_html;
    $args{'DATA'}->{'url'}  = \&Apache::Util::escape_uri;

    my $output;
    my $template_path = $class->template_path();

    # Add document root to include path
    push @{$template_path}, P3::Util->get_request()->document_root();

    my $te = P3::Util->get_template({
                                      INCLUDE_PATH => $template_path,
                                     });

    my $rc = $te->process($args{'TEMPLATE'},
                          $args{'DATA'},
                          \$output);

    unless ($rc) {
        # Handle TT error.  This is supposed to be a Template::Error
        # object, but is actually a string in some cases.
        my $error = $te->error();
        my $error_text = (ref($error) ? $error->as_string() : $error);
        throw P3::Error::System::Template(-text => $error_text);
    }
    
    $class->send_page(\$output);
}

The send_page() method deals with setting Content-Length, Last-Modified,
etc.  get_template() just grabs a cached TT object (or creates a new one
if there isn't one cached) and sets INCLUDE_PATH on it.  Note that
P3::Model::Config is always added to provide access to some common
values, and this is the sort of thing I was suggesting to do with the
data that started this thread.  I also use the mod_perl escaping
functions because they're very fast.

Here's an example of how this all fits together, from the synopsis:

In httpd.conf:

  <Location /foo>
    SetHandler perl-script
    PerlHandler P3::Control::Foo->run
  </Location>

In P3::Control::Foo:

  package P3::Control::Foo;
  use strict;
  use base qw(P3::Control);

  sub handler {
      my $class = shift;
      # do some work
      $class->process_template(
                               TEMPLATE => 'foo.html',
                               DATA     => \%view_data,
                              );
  }

  sub last_modified {
      # override parent class
      return time;
  }

These days, I am using CGI::Application to do this kind of thing, just
because it has convenient hooks for Data::FormValidator and
HTML::FillInForm.  I'm keeping a close eye on OpenInteract2 though.
Just need to test out how well it deals with using Class::DBI instead of
SPOPS.

- Perrin


_______________________________________________
templates mailing list
[email protected]
http://lists.template-toolkit.org/mailman/listinfo/templates

Reply via email to