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

NAME

Konstrukt::Plugin::template - Konstrukt templating engine

SYNOPSIS

Tag interface

        <& template src="some.template" &>
                <$ field $>will be inserted in the template<$ / $>
        <& / &>

Perl interface

        use_plugin 'template';
        $self->add_node($template->node('path/to/some.template', { 
                field1 => 'value1',
                some_list => [
                        { field1 => 'a', field2 => 'b' },
                        { field1 => 'c', field2 => 'd' },
                        ...
                ]
        }));

DESCRIPTION

An important goal of this framework is the fast creation of maintainable static content. Therefore the template (Konstrukt::Plugin::template) plugin was developed.

You are enouraged to encapsulate your web site components that are used in several places in templates, which then can be reused to avoid redundancy. A website usually consists of several components, that are used in many pages (layout, navigation, frames, tables, ...).

Each template consists of static text and variable parts, that can be substituted on the usage of the template.

There are two interfaces to this plugin. You may use special tags within your documents that will not annoy a non-programmer and fit seemlessly into the other markup. You may also use a perl-interface that will fit into your perl code (plugins or embedded perl).

Tag interface / Syntax

Fields

Templates can contain single variable fields, which can be substituted on the usage of the template and may have a default value.

Definition: some.template

        some text here
        this <+$ field_name $+>should be<+$ / $> replaced.
        some text there
        a field without a default value: <+$ no_default / $+>
        end

Usage:

        here we will use the template:
        <& template src="some.template" &>
                <$ field_name $>has been<$ / $>
                <$ no_default $>foo<$ / $>
        <& / &>
        
        you can also define the field values with a tag attribute:
        <& template src="some.template" no_default="bar" / &>

Result: (whitespaces may vary...)

        here we will use the template:
        
        some text here
        this has been replaced.
        some text there
        a field without a default value: foo
        end
        
        you can also define the field values with a tag attribute:
        
        some text here
        this should be replaced.
        some text there
        a field without a default value: bar
        end

Lists

You may define lists to generate repetitive content inside a template.

Definition: some.template

        <table>
                <tr><th><+$ head1 / $+></th><th><+$ head2 / $+></th></tr>
                <+@ items @+>
                <tr><td><+$ col1 / $+></td><td><+$ col2 / $+></td></tr>
                <+@ / @+>
        </table>

Usage:

        <& template src="some.template" head1="Name" head2="Telephone number" &>
                <@ items @>
                        <$ col1 $>foo<$ / $><$ col2 $>555-123456<$ / $>
                        <$ col1 $>bar<$ / $><$ col2 $>555-654321<$ / $>
                        <$ col1 $>baz<$ / $><$ col2 $>555-471123<$ / $>
                <@ / @>
        <& / &>

Result: (whitespaces may vary...)

        <table>
                <tr><th>Name</th><th>Telephone number</th></tr>
                <tr><td>foo</td><td>555-123456</td></tr>
                <tr><td>bar</td><td>555-654321</td></tr>
                <tr><td>baz</td><td>555-471123</td></tr>
        </table>

Note that lists of lists are currently not supported.

Special values:

Additionally to the explicitly specified values, you can access these additional values in each row:

  • index - The sequential number of that row. Starts with 1.

  • odd - 1 if it's an odd row. 0 otherwise.

  • even - 1 if it's an even row. 0 otherwise.

  • start - 1 if it's the first row. 0 otherwise.

  • end - 1 if it's the last row. 0 otherwise.

  • inner - 1 if it's not the first and not the last row. 0 otherwise.

Example:

        <table>
                <tr>
                        <th>ID</th>
                        <th>Name</th>
                </tr>
                <+@ items @+>
                <tr<& if condition="<+$ even / $+>" &> style="background-color: #8888FF;"<& / &>>
                        <th><+$ index / $+></th>
                        <th><+$ name / $+></th>
                </tr>
                <+@ / @+>
        </table>

Nested templates

Templates can be nested (as any Konstrukt tag):

        <& template src="layout.template" title="perl links" &>
                <$ content $>
                        Some perl links:
                        <& template src="linklist.template" &>
                                <@ links @>
                                        <$ target      $>http://www.cpan.org/<$ / $>
                                        <$ description $>Comprehensive Perl Archive Network<$ / $>
                                        
                                        <$ target      $>http://dev.perl.org/perl6/<$ / $>
                                        <$ description $>Perl 6 Development Page<$ / $>
                                        
                                        <$ target      $>http://www.perlfoundation.org/<$ / $>
                                        <$ description $>The Perl Foundation<$ / $>
                                <@ / @>
                        <& / &>
                <$ / $>
        <& / &>

Each used template can in turn contain template tags (and other special Konstrukt tags):

linklist.template:

        <ul>
        <+@ links @+>
                <li><a href="<+$ target / $+>"><+$ description $+>(No Description)<+$ / $+></a></li>
        <+@ / @+>
        <& template src="linkdisclaimer.template" / &>

The templates will be recursively processed.

Nested field definitions

You can also nest field definitions. So you can say that the default for one field is the value of another field:

        <+$ some_field $+><+$ default_for_some_field / $+><+$ / $+>
        

So if no value for some_field is defined, it will default to the value of default_for_some_field, which in turn could also have a default value and so on.

Perl interface

You may also use a template from your perl code. It will be inserted at the current position in the document where your perl code has been executed. This will be done with the "node" method:

        #get a plugin-object
        my $template = use_plugin 'template';
        
        #values that should be inserted to the template
        my $data = { 
                field1 => 'value1',
                field2 => 'value2'
                some_list => [
                        { field1 => 'a', field2 => 'b' },
                        { field1 => 'c', field2 => 'd' },
                        ...
                ]
        };
        #insert the template
        $self->add_node($template->node('path/to/some.template', $data));
        

You may also pass tag nodes as the field's content, so nested templates are possible:

        $self->add_node($template->node('some.template', { some_field => $template->node('some_other.template') }));
        

If you want to pass several nodes as the field's content, you must put them into a field node, which will act like a container:

        #create new field node as a container for some other nodes:
        my $container = Konstrukt::Parser::Node->new({ type => 'tag', handler_type => '$' });
        #add some nodes:
        $container->add_child($some_node);
        #...
        #create template node
        $self->add_node($template->node('some.template', { some_field => $container }));

Take a look at </node> (which has been used in the examples above), which explains the passing of template values a bit more.

CONFIGURATION

For some uncommon situations you may control the behaviour of this plugin with these settings:

        #this setting controls what to do when you have multiple <$ field $>-definitions:
        #0 = overwrite (default). only the last definition will be used
        #1 = join. join all values
        #2 = ignore. only the first definition will be used
        template/join_multiple_fields 0
        
        #this will allow the dynamic generation of <$ field $>'s like this:
        #<& template src="some.template" &>
        #       <$ static_field $>value<$ / $>
        #       <& perl &>print '<$ dynamic_field $>value<$ / $>'<& / &>
        #<& / &>
        #usally you shouldn't do this as it will slow down the execution.
        #if you want dynamic values, you should use the native perl-interface (L</node>) of this plugin.
        #FIXME: additionally this feature doesn't work correctly right now
        template/allow_dynamic_field_value_generation 0
        

SPEED

This plugin needs another modules to clone data structures. It will try to load them in this order:

        1) Clone
        2) Clone::Fast
        3) Scalar::Util::Clone
        4) Storable
        5) Clone::More
        6) Clone::PP

This precedence list is approximateley built to try the module with the best performance first. So you should check, if you've got any of the first modules installed.

METHODS

init

Initialization.

execute_again

Yes, this plugin may return dynamic nodes. E.g. by loading a template containing an perl node.

prepare

Prepare method

Parameters:

  • $tag - Reference to the tag (and its children) that shall be handled.

execute

Execute method

Parameters:

  • $tag - Reference to the tag (and its children) that shall be handled.

process

As prepare and execute are almost the same each run will just call this method.

Parameters:

  • $tag - Reference to the tag (and its children) that shall be handled.

  • $execute - Should be a true value, when we're in the execute-run

check_preliminary_tags

Traverses the tree and looks for preliminary tags that now may have only plaintext children (as a <+$ variable / $+> might have been replaced by a plaintext node) and thus can be prepared.

Parameters:

  • $tag - The root tag of the tree to process

scan_for_values

Traverses the tree and creates a handy data structure to easily access the values.

Parameters:

  • $tag - The root tag of the tree to process

  • $current - The current list values, which will be merged with the new ones

scan_for_templates

Traverses the tree (prepare-result of the block) and creates a handy data structure to easily access the templates.

Parameters:

  • $tag- The root tag of the result tree

substitute

Does the template substitution. It will do no parsing, it will just do the substitution on the passed trees.

Parameters:

  • $template - The hashref which points to the template elements inside the template file.

  • $values - The hashref which points to the field elements.

  • $tag - The template tag

set_hints

Traverses the tree and adds a reference to the field values to each plugin tag node inside the template (if not already set). Also adds a hint with the path of the current template, which will be used by the parser to track the correct current directory.

The values will then be accessible through $tag->{template_values} and $tag->{template_path}.

Parameters:

  • $tag - The root tag of the tree to process

  • $values - Reference to the template values

  • $path - The absolute path of the template file

node

Return a tag node that will load a template. See "SYNOPSIS" for an example.

Parameters:

  • $filename - The filename of the template to load

  • $data - Hash reference with the data to put into the template. Will look like this:

            #generic form (see SYNOPSIS):
            my $data = {
                    fields => {
                            field1 => 'value1',
                            field2 => 'value2'
                    },
                    lists => {
                            list1 => [
                                    { fields => { field1 => 'a', field2 => 'b' } },
                                    { fields => { field1 => 'c', field2 => 'd' } },
                                    ...
                            ]
                    }
            };
            
            #short form:
            #all hash keys that do not point to an hash- or array-reference will be interpreted as a field-value.
            #all hash keys that point to array references will be interpreted as lists.
            #so the short form of the example above would look like this:
            my $data = {
                    field1 => 'value1',
                    field2 => 'value2',
                    list1 => [
                            { field1 => 'a', field2 => 'b' },
                            { field1 => 'c', field2 => 'd' },
                            ...
                    ]
            }
            #this will lead to some ambiguities in the short form:
            # - you cannot define a list and a field with the same name.
            # - you cannot define fields or lists with the name 'fields' or 'lists'
            #   as they will be interpreted as the container for those.

normalize_input_data

Will convert the input data, that may be passed in a short form, into the generic form.

Will only be used internally by "node".

Parameters:

  • $data - Hash reference with the data to put into the template

AUTHOR

Copyright 2006 Thomas Wittek (mail at gedankenkonstrukt dot de). All rights reserved.

This document is free software. It is distributed under the same terms as Perl itself.

SEE ALSO

Konstrukt::Plugin, Konstrukt