Catalyst-View-TT
view release on metacpan or search on metacpan
lib/Catalyst/View/TT.pm view on Meta::CPAN
package Catalyst::View::TT;
use strict;
use warnings;
use base qw/Catalyst::View/;
use Data::Dump 'dump';
use Template;
use Template::Timer;
use MRO::Compat;
use Scalar::Util qw/blessed weaken/;
our $VERSION = '0.46';
$VERSION =~ tr/_//d;
__PACKAGE__->mk_accessors('template');
__PACKAGE__->mk_accessors('expose_methods');
__PACKAGE__->mk_accessors('include_path');
__PACKAGE__->mk_accessors('content_type');
*paths = \&include_path;
=head1 NAME
Catalyst::View::TT - Template View Class
=head1 SYNOPSIS
# use the helper to create your View
myapp_create.pl view Web TT
# add custom configuration in View/Web.pm
__PACKAGE__->config(
# any TT configuration items go here
TEMPLATE_EXTENSION => '.tt',
CATALYST_VAR => 'c',
TIMER => 0,
ENCODING => 'utf-8'
# Not set by default
PRE_PROCESS => 'config/main',
WRAPPER => 'site/wrapper',
render_die => 1, # Default for new apps, see render method docs
expose_methods => [qw/method_in_view_class/],
);
# add include path configuration in MyApp.pm
__PACKAGE__->config(
'View::Web' => {
INCLUDE_PATH => [
__PACKAGE__->path_to( 'root', 'src' ),
__PACKAGE__->path_to( 'root', 'lib' ),
],
},
);
# render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm
sub message : Global {
my ( $self, $c ) = @_;
$c->stash->{template} = 'message.tt2';
$c->stash->{message} = 'Hello World!';
$c->forward( $c->view('Web') );
}
# access variables from template
The message is: [% message %].
lib/Catalyst/View/TT.pm view on Meta::CPAN
unless ( defined $dlim ) {
$dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
}
return split( /$dlim/, $paths );
}
sub new {
my ( $class, $c, $arguments ) = @_;
my $config = {
EVAL_PERL => 0,
TEMPLATE_EXTENSION => '',
CLASS => 'Template',
%{ $class->config },
%{$arguments},
};
if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
my $delim = $config->{DELIMITER};
my @include_path
= _coerce_paths( $config->{INCLUDE_PATH}, $delim );
if ( !@include_path ) {
my $root = $c->config->{root};
my $base = Path::Class::dir( $root, 'base' );
@include_path = ( "$root", "$base" );
}
$config->{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} ) {
if ( $config->{CONTEXT} ) {
$c->log->error(
'Cannot use Template::Timer - a TT CONTEXT is already defined'
);
}
else {
$config->{CONTEXT} = Template::Timer->new(%$config);
}
}
if ( $c->debug && $config->{DUMP_CONFIG} ) {
$c->log->debug( "TT Config: ", dump($config) );
}
my $self = $class->next::method(
$c, { %$config },
);
# Set base include paths. Local'd in render if needed
$self->include_path($config->{INCLUDE_PATH});
$self->expose_methods($config->{expose_methods});
$self->config($config);
# Creation of template outside of call to new so that we can pass [ $self ]
# as INCLUDE_PATH config item, which then gets ->paths() called to get list
# of include paths to search for templates.
# Use a weakened copy of self so we don't have loops preventing GC from working
my $copy = $self;
Scalar::Util::weaken($copy);
$config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
if ( $config->{PROVIDERS} ) {
my @providers = ();
if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
foreach my $p (@{$config->{PROVIDERS}}) {
my $pname = $p->{name};
my $prov = 'Template::Provider';
if($pname eq '_file_')
{
$p->{args} = { %$config };
}
else
{
if($pname =~ s/^\+//) {
$prov = $pname;
}
else
{
$prov .= "::$pname";
}
# We copy the args people want from the config
# to the args
$p->{args} ||= {};
if ($p->{copy_config}) {
map { $p->{args}->{$_} = $config->{$_} }
grep { exists $config->{$_} }
@{ $p->{copy_config} };
}
}
local $@;
eval "require $prov";
if(!$@) {
push @providers, "$prov"->new($p->{args});
}
else
{
$c->log->warn("Can't load $prov, ($@)");
}
}
}
delete $config->{PROVIDERS};
if(@providers) {
$config->{LOAD_TEMPLATES} = \@providers;
}
}
$self->{template} =
$config->{CLASS}->new($config) || do {
my $error = $config->{CLASS}->error();
$c->log->error($error);
$c->error($error);
return undef;
};
return $self;
}
sub process {
lib/Catalyst/View/TT.pm view on Meta::CPAN
return 1;
}
sub _rendering_error {
my ($self, $c, $err) = @_;
my $error = qq/Couldn't render template "$err"/;
$c->log->error($error);
$c->error($error);
return 0;
}
sub render {
my ($self, $c, $template, $args) = @_;
$c->log->debug(qq/Rendering template "$template"/) if $c && $c->debug;
my $output;
my $vars = {
(ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
$self->template_vars($c)
};
local $self->{include_path} =
[ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ]
if ref $vars->{additional_template_paths};
unless ( $self->template->process( $template, $vars, \$output ) ) {
if (exists $self->{render_die}) {
die $self->template->error if $self->{render_die};
return $self->template->error;
}
$c->log->debug('The Catalyst::View::TT render() method will start dying on error in a future release. Unless you are calling the render() method manually, you probably want the new behaviour, so set render_die => 1 in config for ' . blessed($...
return $self->template->error;
}
return $output;
}
sub template_vars {
my ( $self, $c ) = @_;
return () unless $c;
my $cvar = $self->config->{CATALYST_VAR};
my %vars = defined $cvar
? ( $cvar => $c )
: (
c => $c,
base => $c->req->base,
name => $c->config->{name}
);
if ($self->expose_methods) {
my $meta = $self->meta;
foreach my $method_name (@{$self->expose_methods}) {
my $method = $meta->find_method_by_name( $method_name );
unless ($method) {
Catalyst::Exception->throw( "$method_name not found in TT view" );
}
my $method_body = $method->body;
my $weak_ctx = $c;
weaken $weak_ctx;
my $sub = sub {
my @args = @_;
my $ret;
eval {
$ret = $self->$method_body($weak_ctx, @args);
};
if ($@) {
if (blessed($@)) {
die $@;
} else {
Catalyst::Exception->throw($@);
}
}
return $ret;
};
$vars{$method_name} = $sub;
}
}
return %vars;
}
1;
__END__
=head1 DESCRIPTION
This is the Catalyst view class for the L<Template Toolkit|Template>.
Your application should defined a view class which is a subclass of
this module. Throughout this manual it will be assumed that your application
is named F<MyApp> and you are creating a TT view named F<Web>; these names
are placeholders and should always be replaced with whatever name you've
chosen for your application and your view. The easiest way to create a TT
view class is through the F<myapp_create.pl> script that is created along
with the application:
$ script/myapp_create.pl view Web TT
This creates a F<MyApp::View::Web.pm> module in the F<lib> directory (again,
replacing C<MyApp> with the name of your application) which looks
something like this:
package FooBar::View::Web;
use Moose;
extends 'Catalyst::View::TT';
__PACKAGE__->config(DEBUG => 'all');
Now you can modify your action handlers in the main application and/or
controllers to forward to your view class. You might choose to do this
in the end() method, for example, to automatically forward all actions
to the TT view class.
# In MyApp or MyApp::Controller::SomeController
sub end : Private {
my( $self, $c ) = @_;
$c->forward( $c->view('Web') );
}
( run in 2.185 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )