package Catalyst::View::TT;
use strict;
-use base qw/Catalyst::Base/;
+use base qw/Catalyst::View/;
use Template;
use Template::Timer;
use NEXT;
-our $VERSION = '0.13';
+our $VERSION = '0.20';
__PACKAGE__->mk_accessors('template');
+__PACKAGE__->mk_accessors('include_path');
=head1 NAME
# configure in lib/MyApp.pm
- our $ROOT = '/home/dent/catalyst/MyApp';
-
MyApp->config({
name => 'MyApp',
- root => $ROOT,
- 'MyApp::V::TT' => {
+ root => MyApp->path_to('root');,
+ 'V::TT' => {
# any TT configurations items go here
INCLUDE_PATH => [
- "$ROOT/templates/src",
- "$ROOT/templates/lib"
+ MyApp->path_to( 'root', 'src' ),
+ MyApp->path_to( 'root', 'lib' ),
],
- PRE_PROCESS => 'config/main',
- WRAPPER => 'site/wrapper',
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ TEMPLATE_EXTENSION => '.tt',
# two optional config items
CATALYST_VAR => 'Catalyst',
use strict;
use base 'Catalyst::View::TT';
- our $ROOT = '/home/dent/catalyst/MyApp';
-
MyApp::V::TT->config({
- INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ INCLUDE_PATH => [
+ MyApp->path_to( 'root', 'templates', 'lib' ),
+ MyApp->path_to( 'root', 'templates', 'src' ),
+ ],
PRE_PROCESS => 'config/main',
WRAPPER => 'site/wrapper',
});
sub new {
my $self = shift;
$self->config({
- INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ INCLUDE_PATH => [
+ MyApp->path_to( 'root', 'templates', 'lib' ),
+ MyApp->path_to( 'root', 'templates', 'src' ),
+ ],
PRE_PROCESS => 'config/main',
WRAPPER => 'site/wrapper',
});
use strict;
use Catalyst;
- our $ROOT = '/home/dent/catalyst/MyApp';
-
MyApp->config({
name => 'MyApp',
- root => $ROOT,
- 'MyApp::V::TT' => {
- INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
+ root => MyApp->path_to('root'),
+ 'V::TT' => {
+ INCLUDE_PATH => [
+ MyApp->path_to( 'root', 'templates', 'lib' ),
+ MyApp->path_to( 'root', 'templates', 'src' ),
+ ],
PRE_PROCESS => 'config/main',
WRAPPER => 'site/wrapper',
},
methods will be overwritten by items of the same name provided by the
latter methods.
+=head2 DYNAMIC INCLUDE_PATH
+
+It is sometimes needed to dynamically add additional paths to the
+INCLUDE_PATH variable of the template object. This can be done by setting
+'additional_include_paths' on stash to a referrence to an array with
+additional paths:
+
+ $c->stash->{additional_template_paths} = [$c->config->{root} . '/test_include_path'];
+
=head2 RENDERING VIEWS
The view plugin renders the template specified in the C<template>
The base is [% base %]
The name is [% name %]
-If you prefer, you can set the C<CATALYST_VAR> configuration item to
-define the name of a template variable through which the context can
-be referenced.
-
- MyApp->config({
- name => 'MyApp',
- root => $ROOT,
- 'MyApp::V::TT' => {
- CATALYST_VAR => 'Catalyst',
- },
- });
-
-F<message.tt2>:
-
- The base is [% Catalyst.req.base %]
- The name is [% Catalyst.config.name %]
The output generated by the template is stored in
C<$c-E<gt>response-E<gt>output>.
=head2 TEMPLATE PROFILING
-If you have configured Catalyst for debug output,
-C<Catalyst::View::TT> will enable profiling of template processing
-(using L<Template::Timer>). This will embed HTML comments in the
-output from your templates, such as:
-
- <!-- TIMER START: process mainmenu/mainmenu.ttml -->
- <!-- TIMER START: include mainmenu/cssindex.tt -->
- <!-- TIMER START: process mainmenu/cssindex.tt -->
- <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
- <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
-
- ....
-
- <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
-
-You can suppress template profiling by setting the C<TIMER> configuration
-item to a false value.
-
- MyApp->config({
- 'MyApp::V::TT' => {
- TIMER => 0,
- },
- });
-
=head2 METHODS
=over 4
=cut
-sub new {
- my ( $class, $c, $arguments ) = @_;
+sub _coerce_paths {
+ my ( $paths, $dlim ) = shift;
+ return () if ( !$paths );
+ return @{$paths} if ( ref $paths eq 'ARRAY' );
- my $root = $c->config->{root};
+ # tweak delim to ignore C:/
+ unless ( defined $dlim ) {
+ $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
+ }
+ return split( /$dlim/, $paths );
+}
+sub new {
+ my ( $class, $c, $arguments ) = @_;
+ my $delim = $class->config->{DELIMITER} || $arguments->{DELIMITER};
+ my $include_path;
+ if ( ref $arguments->{INCLUDE_PATH} eq 'ARRAY' ) {
+ $include_path = $arguments->{INCLUDE_PATH};
+ }
+ elsif ( ref $class->config->{INCLUDE_PATH} eq 'ARRAY' ) {
+ $include_path = $class->config->{INCLUDE_PATH};
+ }
+ else {
+ my @include_path
+ = _coerce_paths( $arguments->{INCLUDE_PATH}, $delim );
+ if ( !@include_path ) {
+ @include_path
+ = _coerce_paths( $class->config->{INCLUDE_PATH}, $delim );
+ }
+ if ( !@include_path ) {
+ my $root = $c->config->{root};
+ my $base = Path::Class::dir( $root, 'base' );
+ @include_path = ( "$root", "$base" );
+ }
+ $include_path = \@include_path;
+ }
my $config = {
- EVAL_PERL => 0,
- INCLUDE_PATH => [ $root, "$root/base" ],
+ EVAL_PERL => 0,
+ TEMPLATE_EXTENSION => '',
%{ $class->config },
- %{$arguments}
+ %{$arguments},
+ INCLUDE_PATH => $include_path,
};
# if we're debugging and/or the TIMER option is set, then we install
# Template::Timer as a custom CONTEXT object, but only if we haven't
# already got a custom CONTEXT defined
- if ( $config->{TIMER} || ( $c->debug() && !exists $config->{TIMER} ) ) {
+ if ( $config->{TIMER} ) {
if ( $config->{CONTEXT} ) {
$c->log->error(
- 'Cannot use Template::Timer - a TT CONFIG is already defined');
+ 'Cannot use Template::Timer - a TT CONFIG is already defined'
+ );
}
else {
$config->{CONTEXT} = Template::Timer->new(%$config);
$c->log->debug( "TT Config: ", Dumper($config) );
}
- return $class->NEXT::new(
+ my $self = $class->NEXT::new(
$c,
- {
- template => Template->new($config) || do {
+ { template => Template->new($config) || do {
my $error = Template->error();
$c->log->error($error);
$c->error($error);
return undef;
- }
- }
+ },
+ %{$config},
+ },
);
+ $self->include_path($include_path);
+ $self->config($config);
+
+ return $self;
}
=item process
sub process {
my ( $self, $c ) = @_;
- my $template = $c->stash->{template} || $c->request->match;
+ my $template = $c->stash->{template}
+ || ( $c->request->match || $c->request->action )
+ . $self->config->{TEMPLATE_EXTENSION};
unless ($template) {
$c->log->debug('No template specified for rendering') if $c->debug;
my $vars = {
defined $cvar
? ( $cvar => $c )
- : (
- c => $c,
+ : ( c => $c,
base => $c->req->base,
name => $c->config->{name}
),
%{ $c->stash() }
};
-
+ unshift @{ $self->include_path },
+ @{ $c->stash->{additional_template_paths} }
+ if ref $c->stash->{additional_template_paths};
unless ( $self->template->process( $template, $vars, \$output ) ) {
my $error = $self->template->error;
$error = qq/Couldn't render template "$error"/;
$c->error($error);
return 0;
}
+ splice @{ $self->include_path }, 0,
+ scalar @{ $c->stash->{additional_template_paths} }
+ if ref $c->stash->{additional_template_paths};
unless ( $c->response->content_type ) {
$c->response->content_type('text/html; charset=utf-8');
=item config
This method allows your view subclass to pass additional settings to
-the TT configuration hash, or to set the C<CATALYST_VAR> and C<TIMER>
-options.
+the TT configuration hash, or to set the options as below:
+
+=over 2
+
+=item C<CATALYST_VAR>
+
+Allows you to change the name of the Catalyst context object. If set, it will also
+remove the base and name aliases, so you will have access them through <context>.
+
+For example:
+
+ MyApp->config({
+ name => 'MyApp',
+ root => MyApp->path_to('root'),
+ 'V::TT' => {
+ CATALYST_VAR => 'Catalyst',
+ },
+ });
+
+F<message.tt2>:
+
+ The base is [% Catalyst.req.base %]
+ The name is [% Catalyst.config.name %]
+
+=item C<TIMER>
+
+If you have configured Catalyst for debug output, and turned on the TIMER setting,
+C<Catalyst::View::TT> will enable profiling of template processing
+(using L<Template::Timer>). This will embed HTML comments in the
+output from your templates, such as:
+
+ <!-- TIMER START: process mainmenu/mainmenu.ttml -->
+ <!-- TIMER START: include mainmenu/cssindex.tt -->
+ <!-- TIMER START: process mainmenu/cssindex.tt -->
+ <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
+ <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
+
+ ....
+
+ <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
+
+
+=item C<TEMPLATE_EXTENSION>
+
+a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
+
+For example:
+
+ package MyApp::C::Test;
+ sub test : Local { .. }
+
+Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
+<root>/test/test.tt.
+
+=back
=back