in reply to Abstracting away layout details when using large HTML::Template-based sites?

I may be missing something here, but this seems to work, at the price of (partially) re-mixing content and layout. Further, from the description of your project, I'm guessing that you will be taking the title from the command line or yet another file, hence the new var, $input.

#!/usr/bin/perl -w # 655823 use strict; use warnings; use HTML::Template; # new; replace to use from ARGV or some other project file my $input = "STEVE"; my $layout = HTML::Template->new( filename => "layout.tmpl" ); my $page = HTML::Template->new( filename => "page.inc" ); $layout->param( page => $page->output() ); # Now setup title with $input, rather than hardcoding $layout->param( title => "$input" ); # spit out the page print $layout->output();

When layout.tmpl is modified by moving the line <h2>...</h2> from page.inc, to line 6 here:

<html> <head> <title><!-- tmpl_var name='title' --></title> </head> <body> <h2><!-- tmpl_var name='title' --></h2> <!-- tmpl_var name='page' --> </body> </html>

after which, page.inc becomes simply

<p>Imagine content here ..</p>

and the output is:

<html> <head> <title>STEVE</title> </head> <body> <h2>STEVE</h2> <p>Imagine content here ..</p> </body> </html>

This leaves various issues, however; the most obvious being any case in which your page.inc was more complex -- eg, has body content intended to appear before the <h2...> pair. That's because this writer tackled the question only to begin acquiring more than my current, mimimal knowledge of HTML::Template.

Replies are listed 'Best First'.
Re^2: Abstracting away layout details when using large HTML::Template-based sites?
by skx (Parson) on Dec 08, 2007 at 17:31 UTC

    Thanks for the reply, as you suggest my content will be coming from an external source, along with all other page data. In this case it will be coming from a database.

    Your solution of moving things around doesn't really apply terribly well when I consider how I would be using this in practise I'm afraid.

    For the simple case which I've presented it does work fine, but the general problem of recursively expanding templates doesn't.

    One thing that I notice is if you have a layout.tmpl like this:

    <html> <head> <title><!-- tmpl_var name='title' --></title> </head> <body> <!-- tmpl_include name='page.inc' --> </body> </html>

    Things work! The page.inc containing:

    <h2><!-- tmpl_var name='title' --></h2>

    Is correctly processed via this code:

    my $template = HTML::Template->new( filename => 'layout.tmpl' ); $template->param( title => "Steve" ); print $template->output();

    So suddenly my problem is reduced to including variable files! Unfortunately a similar lack of recusive support means this doesn't work:

    <!-- tmpl_include name='<!-- tmpl_var name='filename' -->'>

    But via a filter I can get this same aim:

    # # Replace ### with environmental variable variable 'page' # sub filter { my ($text_ref ) = shift; my $val = $ENV{'page'}; $$text_ref =~ s/###/$val/g; }; # # Load 'layout.tmpl' - and have that include 'page.inc'. # # THis will expand the following in *both* files! # # <!-- tmpl_var name='title' --> # # $ENV{'page'} = 'page.inc'; my $template = HTML::Template->new(filename => 'layout.tmpl', filter => \&filter ); $template->param( title => "Something here" ); print $template->output();

    I don't know whether to feel pleased or dirty ..

    Steve
    --
      So suddenly my problem is reduced to including variable files! Unfortunately a similar lack of recusive support means this doesn't work: <!-- tmpl_include name='<!-- tmpl_var name='filename' -->'>
      try HTML::Template::Compiled*) - it offers TMPL_INCLUDE_VAR which includes the template file given (it also offers TMPL_INCLUDE_STRING, so that you can pass a template string into another template, but that might cost a bit of performance)
      *) disclaimer: i'm the author.
      I would also suggest HTML::Template::Compiled, but your filter solution is pretty nice too. You can work around the ENV variable by building a filter based on the variable, using an embedded sub:
      sub mk_include_filter { my $page = shift; return sub { my $text_ref = shift; $$text_ref =~ s/###/$page/g; }; } my $template = HTML::Template->new(filename => 'layout.tmpl', filter => mk_include_filter('page.i +nc') );

        Thanks for that; I fiddled a couple of times and couldn't quite work out why it was failing. Your solution works properly ++.

        Steve
        --