1 package Catalyst::View::TT;
6 use base qw/Catalyst::View/;
12 our $VERSION = '0.30';
14 __PACKAGE__->mk_accessors('template');
15 __PACKAGE__->mk_accessors('include_path');
17 *paths = \&include_path;
21 Catalyst::View::TT - Template View Class
25 # use the helper to create your View
26 myapp_create.pl view TT TT
28 # configure in lib/MyApp.pm (Could be set from configfile instead)
32 root => MyApp->path_to('root'),
34 # any TT configurations items go here
36 MyApp->path_to( 'root', 'src' ),
37 MyApp->path_to( 'root', 'lib' ),
39 TEMPLATE_EXTENSION => '.tt',
43 PRE_PROCESS => 'config/main',
44 WRAPPER => 'site/wrapper',
48 # render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm
50 sub message : Global {
51 my ( $self, $c ) = @_;
52 $c->stash->{template} = 'message.tt2';
53 $c->stash->{message} = 'Hello World!';
54 $c->forward( $c->view('TT') );
57 # access variables from template
59 The message is: [% message %].
61 # example when CATALYST_VAR is set to 'Catalyst'
62 Context is [% Catalyst %]
63 The base is [% Catalyst.req.base %]
64 The name is [% Catalyst.config.name %]
66 # example when CATALYST_VAR isn't set
68 The base is [% base %]
69 The name is [% name %]
74 my ( $paths, $dlim ) = shift;
75 return () if ( !$paths );
76 return @{$paths} if ( ref $paths eq 'ARRAY' );
78 # tweak delim to ignore C:/
79 unless ( defined $dlim ) {
80 $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
82 return split( /$dlim/, $paths );
86 my ( $class, $c, $arguments ) = @_;
89 TEMPLATE_EXTENSION => '',
93 if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
94 my $delim = $config->{DELIMITER};
96 = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
97 if ( !@include_path ) {
98 my $root = $c->config->{root};
99 my $base = Path::Class::dir( $root, 'base' );
100 @include_path = ( "$root", "$base" );
102 $config->{INCLUDE_PATH} = \@include_path;
105 # if we're debugging and/or the TIMER option is set, then we install
106 # Template::Timer as a custom CONTEXT object, but only if we haven't
107 # already got a custom CONTEXT defined
109 if ( $config->{TIMER} ) {
110 if ( $config->{CONTEXT} ) {
112 'Cannot use Template::Timer - a TT CONTEXT is already defined'
116 $config->{CONTEXT} = Template::Timer->new(%$config);
120 if ( $c->debug && $config->{DUMP_CONFIG} ) {
121 $c->log->debug( "TT Config: ", dump($config) );
124 my $self = $class->next::method(
128 # Set base include paths. Local'd in render if needed
129 $self->include_path($config->{INCLUDE_PATH});
131 $self->config($config);
133 # Creation of template outside of call to new so that we can pass [ $self ]
134 # as INCLUDE_PATH config item, which then gets ->paths() called to get list
135 # of include paths to search for templates.
137 # Use a weakend copy of self so we dont have loops preventing GC from working
139 Scalar::Util::weaken($copy);
140 $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
142 if ( $config->{PROVIDERS} ) {
144 if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
145 foreach my $p (@{$config->{PROVIDERS}}) {
146 my $pname = $p->{name};
147 my $prov = 'Template::Provider';
148 if($pname eq '_file_')
150 $p->{args} = { %$config };
154 if($pname =~ s/^\+//) {
161 # We copy the args people want from the config
164 if ($p->{copy_config}) {
165 map { $p->{args}->{$_} = $config->{$_} }
166 grep { exists $config->{$_} }
167 @{ $p->{copy_config} };
170 eval "require $prov";
172 push @providers, "$prov"->new($p->{args});
176 $c->log->warn("Can't load $prov, ($@)");
180 delete $config->{PROVIDERS};
182 $config->{LOAD_TEMPLATES} = \@providers;
187 Template->new($config) || do {
188 my $error = Template->error();
189 $c->log->error($error);
199 my ( $self, $c ) = @_;
201 my $template = $c->stash->{template}
202 || $c->action . $self->config->{TEMPLATE_EXTENSION};
204 unless (defined $template) {
205 $c->log->debug('No template specified for rendering') if $c->debug;
209 my $output = $self->render($c, $template);
211 if (UNIVERSAL::isa($output, 'Template::Exception')) {
212 my $error = qq/Couldn't render template "$output"/;
213 $c->log->error($error);
218 unless ( $c->response->content_type ) {
219 $c->response->content_type('text/html; charset=utf-8');
222 $c->response->body($output);
228 my ($self, $c, $template, $args) = @_;
230 $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
234 (ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
235 $self->template_vars($c)
238 local $self->{include_path} =
239 [ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ]
240 if ref $vars->{additional_template_paths};
242 unless ($self->template->process( $template, $vars, \$output ) ) {
243 return $self->template->error;
250 my ( $self, $c ) = @_;
252 my $cvar = $self->config->{CATALYST_VAR};
258 base => $c->req->base,
259 name => $c->config->{name}
270 This is the Catalyst view class for the L<Template Toolkit|Template>.
271 Your application should defined a view class which is a subclass of
272 this module. The easiest way to achieve this is using the
273 F<myapp_create.pl> script (where F<myapp> should be replaced with
274 whatever your application is called). This script is created as part
275 of the Catalyst setup.
277 $ script/myapp_create.pl view TT TT
279 This creates a MyApp::View::TT.pm module in the F<lib> directory (again,
280 replacing C<MyApp> with the name of your application) which looks
283 package FooBar::View::TT;
288 use base 'Catalyst::View::TT';
290 __PACKAGE__->config->{DEBUG} = 'all';
292 Now you can modify your action handlers in the main application and/or
293 controllers to forward to your view class. You might choose to do this
294 in the end() method, for example, to automatically forward all actions
295 to the TT view class.
297 # In MyApp or MyApp::Controller::SomeController
300 my( $self, $c ) = @_;
301 $c->forward( $c->view('TT') );
306 There are a three different ways to configure your view class. The
307 first way is to call the C<config()> method in the view subclass. This
308 happens when the module is first loaded.
310 package MyApp::View::TT;
313 use base 'Catalyst::View::TT';
315 MyApp::View::TT->config({
317 MyApp->path_to( 'root', 'templates', 'lib' ),
318 MyApp->path_to( 'root', 'templates', 'src' ),
320 PRE_PROCESS => 'config/main',
321 WRAPPER => 'site/wrapper',
324 The second way is to define a C<new()> method in your view subclass.
325 This performs the configuration when the view object is created,
326 shortly after being loaded. Remember to delegate to the base class
327 C<new()> method (via C<$self-E<gt>next::method()> in the example below) after
328 performing any configuration.
334 MyApp->path_to( 'root', 'templates', 'lib' ),
335 MyApp->path_to( 'root', 'templates', 'src' ),
337 PRE_PROCESS => 'config/main',
338 WRAPPER => 'site/wrapper',
340 return $self->next::method(@_);
343 The final, and perhaps most direct way, is to define a class
344 item in your main application configuration, again by calling the
345 uniquitous C<config()> method. The items in the class hash are
346 added to those already defined by the above two methods. This happens
347 in the base class new() method (which is one reason why you must
348 remember to call it via C<MRO::Compat> if you redefine the C<new()>
349 method in a subclass).
358 root => MyApp->path_to('root'),
361 MyApp->path_to( 'root', 'templates', 'lib' ),
362 MyApp->path_to( 'root', 'templates', 'src' ),
364 PRE_PROCESS => 'config/main',
365 WRAPPER => 'site/wrapper',
369 Note that any configuration items defined by one of the earlier
370 methods will be overwritten by items of the same name provided by the
373 =head2 DYNAMIC INCLUDE_PATH
375 Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
377 Additional paths can be added to the start of INCLUDE_PATH via the stash as
380 $c->stash->{additional_template_paths} =
381 [$c->config->{root} . '/test_include_path'];
383 If you need to add paths to the end of INCLUDE_PATH, there is also an
384 include_path() accessor available:
386 push( @{ $c->view('TT')->include_path }, qw/path/ );
388 Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
389 MUST check for duplicate paths. Without such checking, the above code will add
390 "path" to INCLUDE_PATH at every request, causing a memory leak.
392 A safer approach is to use include_path() to overwrite the array of paths
393 rather than adding to it. This eliminates both the need to perform duplicate
394 checking and the chance of a memory leak:
396 @{ $c->view('TT')->include_path } = qw/path another_path/;
398 If you are calling C<render> directly then you can specify dynamic paths by
399 having a C<additional_template_paths> key with a value of additonal directories
400 to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this.
402 =head2 RENDERING VIEWS
404 The view plugin renders the template specified in the C<template>
407 sub message : Global {
408 my ( $self, $c ) = @_;
409 $c->stash->{template} = 'message.tt2';
410 $c->forward( $c->view('TT') );
413 If a stash item isn't defined, then it instead uses the
414 stringification of the action dispatched to (as defined by $c->action)
415 in the above example, this would be C<message>, but because the default
416 is to append '.tt', it would load C<root/message.tt>.
418 The items defined in the stash are passed to the Template Toolkit for
419 use as template variables.
421 sub default : Private {
422 my ( $self, $c ) = @_;
423 $c->stash->{template} = 'message.tt2';
424 $c->stash->{message} = 'Hello World!';
425 $c->forward( $c->view('TT') );
428 A number of other template variables are also added:
430 c A reference to the context object, $c
431 base The URL base, from $c->req->base()
432 name The application name, from $c->config->{ name }
434 These can be accessed from the template in the usual way:
438 The message is: [% message %]
439 The base is [% base %]
440 The name is [% name %]
443 The output generated by the template is stored in C<< $c->response->body >>.
445 =head2 CAPTURING TEMPLATE OUTPUT
447 If you wish to use the output of a template for some other purpose than
448 displaying in the response, e.g. for sending an email, this is possible using
449 L<Catalyst::Plugin::Email> and the L<render> method:
451 sub send_email : Local {
456 To => 'me@localhost',
457 Subject => 'A TT Email',
459 body => $c->view('TT')->render($c, 'email.tt', {
460 additional_template_paths => [ $c->config->{root} . '/email_templates'],
461 email_tmpl_param1 => 'foo'
465 # Redirect or display a message
468 =head2 TEMPLATE PROFILING
470 See L<C<TIMER>> property of the L<config> method.
476 The constructor for the TT view. Sets up the template provider,
477 and reads the application config.
481 Renders the template specified in C<< $c->stash->{template} >> or
482 C<< $c->action >> (the private name of the matched action. Calls L<render> to
483 perform actual rendering. Output is stored in C<< $c->response->body >>.
485 =head2 render($c, $template, \%args)
487 Renders the given template and returns output, or a L<Template::Exception>
490 The template variables are set to C<%$args> if $args is a hashref, or
491 $C<< $c->stash >> otherwise. In either case the variables are augmented with
492 C<base> set to C< << $c->req->base >>, C<c> to C<$c> and C<name> to
493 C<< $c->config->{name} >>. Alternately, the C<CATALYST_VAR> configuration item
494 can be defined to specify the name of a template variable through which the
495 context reference (C<$c>) can be accessed. In this case, the C<c>, C<base> and
496 C<name> variables are omitted.
498 C<$template> can be anything that Template::process understands how to
499 process, including the name of a template file or a reference to a test string.
500 See L<Template::process|Template/process> for a full list of supported formats.
504 Returns a list of keys/values to be used as the catalyst variables in the
509 This method allows your view subclass to pass additional settings to
510 the TT configuration hash, or to set the options as below:
514 The list of paths TT will look for templates in.
516 =head2 C<CATALYST_VAR>
518 Allows you to change the name of the Catalyst context object. If set, it will also
519 remove the base and name aliases, so you will have access them through <context>.
525 root => MyApp->path_to('root'),
527 CATALYST_VAR => 'Catalyst',
533 The base is [% Catalyst.req.base %]
534 The name is [% Catalyst.config.name %]
538 If you have configured Catalyst for debug output, and turned on the TIMER setting,
539 C<Catalyst::View::TT> will enable profiling of template processing
540 (using L<Template::Timer>). This will embed HTML comments in the
541 output from your templates, such as:
543 <!-- TIMER START: process mainmenu/mainmenu.ttml -->
544 <!-- TIMER START: include mainmenu/cssindex.tt -->
545 <!-- TIMER START: process mainmenu/cssindex.tt -->
546 <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
547 <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
551 <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
554 =head2 C<TEMPLATE_EXTENSION>
556 a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
560 package MyApp::Controller::Test;
561 sub test : Local { .. }
563 Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
568 Allows you to specify the template providers that TT will use.
572 root => MyApp->path_to('root'),
578 DBI_DSN => 'dbi:DB2:books',
589 The 'name' key should correspond to the class name of the provider you
590 want to use. The _file_ name is a special case that represents the default
591 TT file-based provider. By default the name is will be prefixed with
592 'Template::Provider::'. You can fully qualify the name by using a unary
595 name => '+MyApp::Provider::Foo'
597 You can also specify the 'copy_config' key as an arrayref, to copy those keys
598 from the general config, into the config for the provider:
600 DEFAULT_ENCODING => 'utf-8',
604 copy_config => [qw(DEFAULT_ENCODING INCLUDE_PATH)]
608 This can prove useful when you want to use the additional_template_paths hack
609 in your own provider, or if you need to use Template::Provider::Encoding
613 The L<Catalyst::Helper::View::TT> and
614 L<Catalyst::Helper::View::TTSite> helper modules are provided to create
615 your view module. There are invoked by the F<myapp_create.pl> script:
617 $ script/myapp_create.pl view TT TT
619 $ script/myapp_create.pl view TT TTSite
621 The L<Catalyst::Helper::View::TT> module creates a basic TT view
622 module. The L<Catalyst::Helper::View::TTSite> module goes a little
623 further. It also creates a default set of templates to get you
624 started. It also configures the view module to locate the templates
629 L<Catalyst>, L<Catalyst::Helper::View::TT>,
630 L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
634 Sebastian Riedel, C<sri@cpan.org>
636 Marcus Ramberg, C<mramberg@cpan.org>
638 Jesse Sheidlower, C<jester@panix.com>
640 Andy Wardley, C<abw@cpan.org>
644 This program is free software, you can redistribute it and/or modify it
645 under the same terms as Perl itself.