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 )