[Templates] Flexible set of templates

Andy Wardley abw@wardley.org
Sat, 09 Dec 2006 08:57:11 +0000


David Vergin wrote:
> My best thought on this so far is to establish a model for clues to the 
> data requirements for each template (the script would read the clues to 
> determine what data to load for each template).

Perrin's reply pretty much covers the database abstraction side of
things.

It sounds like you're also looking for a simple way to define the
mapping between templates and the metadata (the "clues") for those 
templates.

One approach that I use it to define a sitemap that contains
all the metadata for the pages in a site.  You can stick it in a
database if necessary, but I find a YAML file more convenient
(certainly during development) because it's easier to dive in and
edit with a text editor.

    page/one.html:
      name: Page One
      title: The Title of My First Page
    page/two.html:
      name: Page Two
      title: The Title of My Second Page

It's then a trivial matter to write a plugin that loads the sitemap
file and returns the data for the current template (defined in the
template.name variable).

   package My::Plugin::Page;
   use base 'Template::Plugin';
   use YAML qw(LoadFile);
   our $SITEMAP = LoadFile('/path/to/my/sitemap.yaml');

   sub new {
       my $class   = shift;
       my $context = shift;
       my $name    = shift || $context->stash->get('template.name');
       my $page    = $SITEMAP->{ $page }; # or warn/barf/default
       bless $page, $class;
  }

Then in your template...

   [% USE Page %]
   [% Page.name %]  [% Page.title %]  etc...

You can add methods to your plugin to do things like fetching
records from a database.

   sub products {
      # $db->query('SELECT blah FROM blah ...etc..');
   }

Any data that you define in the YAML sitemap for a page will end
up as $self->{ xxx } data in the page plugin object.  So you can
add any metadata clues you like to the sitemap and have the plugin
method interpret them.

For example, to select some products from a particular category
in the datagbase you might define some metadata like this:

   product/widgets.html
     product_group: widgets
   products/doodahs.html
     product_group: doodahs

And then your products query would look something like this:

   sub products {
      # $db->query( 'SELECT blah FROM blah WHERE product_group=?',
                    $self->{ product_group } );
   }

Your template only has to load the Page plugin and call the products()
method.

   [% USE Page %]
   [% FOREACH product IN Page.products %]
      ...
   [% END %]

Hopefully that gives you some ideas.

Cheers
A