package Catalyst::View::HTML::Template::Compiled; use strict; use base 'Catalyst::Base'; use HTML::Template::Compiled (); use Path::Class (); our $VERSION = '0.16'; __PACKAGE__->mk_accessors(qw/htc catalyst/); =head1 NAME Catalyst::View::HTML::Template::Compiled - HTML::Template::Compiled View Class =head1 SYNOPSIS # use the helper script/myapp_create.pl view HTML::Template::Compiled HTML::Template::Compiled # lib/MyApp/View/HTML/Template.pm package MyApp::View::HTML::Template::Compiled; use base 'Catalyst::View::HTML::Template::Compiled'; __PACKAGE__->config( use_default_path => 0, # defaults to 1 # any HTML::Template::Compiled configurations items go here # see HTML::Template::Compiled documentation for more details ); 1; # Meanwhile, maybe in an 'end' action $c->forward('MyApp::View::HTML::Template::Compiled'); =head1 DESCRIPTION This is the C< HTML::Template::Compiled > view class. Your subclass should inherit from this class. =head1 METHODS =over 4 =item new Internally used by C. Used to configure some internal stuff. =cut sub new { my ( $class, $c, $arguments ) = @_; my $config = { use_perl => 0, %{ $class->config }, %{ $arguments }, }; my @config_names = $class->config_names; foreach (@config_names) { if(exists $c->config->{$_}) { $config = { %{ $config }, %{ $c->config->{$_} || {} }, }; } } $config->{use_default_path} = 1 unless defined $config->{use_default_path}; my $self = $class->NEXT::new( $c, { %$config }, ); $self->catalyst( $c ); $self->config($config); return $self; } =item process Renders the template specified in I< $c->stash->{template} >, I< $c->request->match >, I< $c->config->{template}->{filename} > or I< __PACKAGE__->config->{filename} >. Template params are set up from the contents of I< $c->stash >, augmented with C< base > set to I< $c->req->base >, I< name > to I< $c->config->{name} > and I< c > to I< $c >. Output is stored in I< $c->response->body >. =cut sub process { my ( $self, $c ) = @_; return 0 unless $self->prepare_process( $c ); return 0 unless $self->prepare_htc( $c ); return 0 unless $self->prepare_render( $c ); my $retval = 0; if( $retval = defined( my $body = $self->render( $c ) ) ) { $c->res->headers->content_type('text/html; charset=utf-8') unless ( $c->response->headers->content_type ); $c->response->body($body); } return $self->finalize_process( $c ); } =item prepare_process Pretty much the first thing called by I< process >. Only used for sub-classing. Return a i-value if everything is okay, otherwise I< process > will fail. =cut sub prepare_process { my ($self, $c ) = @_; return 1; } =item finalize_process Will be called right before I< process > finishes. Only used for sub-classing. Whatever it returns, I< process > will return. =cut sub finalize_process { my ($self, $c ) = @_; return 1; } =item prepare_htc Creates the C< HTML::Template::Compiled > object. On success, returns the filename to be rendered; undef otherwise. =cut sub prepare_htc { my ($self, $c ) = @_; $c ||= $self->catalyst; my $filename = $self->template( $c ); unless( $filename && $self->htc ) { my $error = "Nothing to render."; $c->log->error($error); $c->error($error); return undef; } return $self->htc->get_file; } =item htc Accessor to the C object. May returns undef then the object has not yet been created or creating has failed. =cut =item prepare_render First thing before C< render > is called. Assigns the parameters like the ones from the stash. =cut sub prepare_render { my ($self, $c ) = @_; $c ||= $self->catalyst; $self->htc->param( base => $c->request->base, name => $c->config->{name}, c => $c, %{ $c->stash } ); return 1; } =item render This is where the rendering magic happens. Returns the rendered output on success, or undef otherwise. =cut sub render { my ($self, $c ) = @_; $c ||= $self->catalyst; $c->log->debug(sprintf('Trying to render template "%s" ...', $self->htc->get_file)) if $c->debug; my $body; eval { $body = $self->htc->output }; if ( my $error = $@ ) { chomp $error; $error = sprintf( qq/Couldn't render template "%s". Error: "%s"/, $self->htc->get_file, $error ); $c->log->error($error); $c->error($error); return undef; } return $body; } =item template Tries to find the right template to render. Returns its filename or undef. Actually only used internally. =cut sub template { my ($self, $c ) = @_; $c ||= $self->catalyst; $c->log->debug('Finding template to render ...') if $c->debug; my %options = ( %{ $self->config }, path => $self->path( $c ), ); my $extension = $self->config->{extension} || ''; if ($extension) { $extension = ".$extension" unless substr( $extension, 0, 1 ) eq '.'; } my $prefix = $self->config->{prefix} || ''; my @filenames = ( $c->stash->{template}, $prefix . $c->request->match . $extension, $prefix . $c->request->action . $extension, $self->config->{filename}, $c->config->{template}->{filename}, ); my $htc; foreach my $filename (@filenames) { next unless $filename; $options{filename} = $filename; eval { $htc = HTML::Template::Compiled->new(%options); }; last unless $@; $c->log->debug( "HTC error: $@" ) if $c->debug; } $self->htc( $htc ); return $options{filename}; } =item path Returns a array ref with paths used to find the templates in. =cut sub path { my ($self, $c) = @_; $c ||= $self->catalyst; my $templ_path = $self->config->{path} || ''; $templ_path = [$templ_path] unless 'ARRAY' eq ref $templ_path; my $path = $self->_build_path( $templ_path, ( map { $c->path_to($_) } @$templ_path ), ( $self->config->{use_default_path} ? ( $c->config->{root}, $c->config->{root} . '/base' ) : () ), ); return $path; } sub _build_path { my ( $self, @paths ) = @_; my @retval = (); foreach my $path (@paths) { next unless defined $path; if ( ref($path) eq 'ARRAY' ) { push @retval, $self->_build_path( @{$path} ); } elsif ( ref($path) eq 'Path::Class::Dir' ) { # stringify it push @retval, "" . $path->absolute; } else { push @retval, $self->_build_path( Path::Class::dir($path) ); } } return wantarray ? @retval : [@retval]; } =item config C<< use_default_path >>: if set, will include I<< $c->config->{root} >> and I<< $c->config->{root} . '/base' >> to look for the template. I<< Defaults to 1 >>. This also allows your view subclass to pass additional settings to the C<< HTML::Template::Compiled >> config hash. =item config_names A list of names that are used to locate configuration parameters for the view inside C< $c->config >. =cut sub config_names { return qw/View::HTML::Template::Compiled V::HTML::Template::Compiled View::HTC V::HTC template/; } =item catalyst Normally all methods are called with the I< $c > as the first parameter. Just to insure that you have it as a method it case you need it. :) Will be initializes by C< new >. =cut =back =head1 SEE ALSO L, L, L. =head1 AUTHOR Sascha Kiefer, C =head1 COPYRIGHT This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1;