The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

DYNAMIC CONTENT GENERATION VIA CGI SCRIPT

The Template modules provides a simple front-end to the Template Toolkit for use in CGI scripts and Apache/mod_perl handlers. Simply 'use' the Template module, create an object instance with the new() method and then call the process() method on the object, passing the name of the template file as a parameter. The second parameter passed is a reference to a hash array of variables that we want made available to the template:

    #!/usr/bin/perl -w

    use strict;
    use Template;

    my $file = 'src/greeting.html';
    my $vars = {
       message  => "Hello World\n"
    };

    my $template->new();

    $template->process($file, $vars)
        || die "Template process failed: ", $template->error(), "\n";

So that our scripts will work with the same template files as our earlier examples, we'll can add some configuration options to the constructor to tell it about our environment:

    my $template->new({
        # where to find template files
        INCLUDE_PATH => '/home/abw/websrc/src:/home/abw/websrc/lib',
        # pre-process lib/config to define any extra values
        PRE_PROCESS  => 'config',
    });

Note that here we specify the 'config' file as a PRE_PROCESS option. This means that the templates we process can use the same global variables defined earlier for our static pages. We don't have to replicate their definitions in this script. However, we can supply additional data and functionality specific to this script via the hash of variables that we pass to the process() method.

These entries in this hash may contain simple text or other values, references to lists, others hashes, sub-routines or objects. The Template Toolkit will automatically apply the correct procedure to access these different types when you use the variables in a template.

Here's a more detailed example to look over. Amongst the different template variables we define in $vars, we create a reference to a CGI object and a 'get_user_projects' sub-routine.

    #!/usr/bin/perl -w

    use strict;
    use Template;
    use CGI;

    $| = 1;
    print "Content-type: text/html\n\n";

    my $file = 'userinfo.html';
    my $vars = {
        'version'  => 3.14,
        'days'     => [ qw( mon tue wed thu fri sat sun ) ],
        'worklist' => \&get_user_projects,
        'cgi'      => CGI->new(),
        'me'       => {
            'id'     => 'abw',
            'name'   => 'Andy Wardley',
        },
    };

    sub get_user_projects {
        my $user = shift;
        my @projects = ...   # do something to retrieve data
        return \@projects;
    }

    my $template = Template->new({
        INCLUDE_PATH => '/home/abw/websrc/src:/home/abw/websrc/lib',
        PRE_PROCESS  => 'config',
    });

    $template->process($userinfo, $vars)
        || die $template->error();

Here's a sample template file that we might create to build the output for this script.

$src/userinfo.html: [% INCLUDE header title = 'Template Toolkit CGI Test' %]

    <a href="mailto:[% email %]">Email [% me.name %]</a>

    <p>This is version [% version %]</p>

    <h3>Projects</h3>
    <ul>
    [% FOREACH project = worklist(me.id) %]
       <li> <a href="[% project.url %]">[% project.name %]</a>
    [% END %]
    </ul>

    [% INCLUDE footer %]

This example shows how we've separated the Perl implementation (code) from the presentation (HTML) which not only makes them easier to maintain in isolation, but also allows the re-use of existing template elements such as headers and footers, etc. By using template to create the output of your CGI scripts, you can give them the same consistency as your static pages built via ttree or other means.

Furthermore, we can modify our script so that it processes any one of a number of different templates based on some condition. A CGI script to maintain a user database, for example, might process one template to provide an empty form for new users, the same form with some default values set for updating an existing user record, a third template for listing all users in the system, and so on. You can use any Perl functionality you care to write to implement the logic of your application and then choose one or other template to generate the desired output for the application state.