1 package Catalyst::View::TT;
4 use base qw/Catalyst::View/;
11 __PACKAGE__->mk_accessors('template');
12 __PACKAGE__->mk_accessors('include_path');
16 Catalyst::View::TT - Template View Class
20 # use the helper to create View
21 myapp_create.pl view TT TT
23 # configure in lib/MyApp.pm
27 root => MyApp->path_to('root');,
29 # any TT configurations items go here
31 MyApp->path_to( 'root', 'src' ),
32 MyApp->path_to( 'root', 'lib' ),
34 PRE_PROCESS => 'config/main',
35 WRAPPER => 'site/wrapper',
36 TEMPLATE_EXTENSION => '.tt',
38 # two optional config items
39 CATALYST_VAR => 'Catalyst',
44 # render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm
46 sub message : Global {
47 my ( $self, $c ) = @_;
48 $c->stash->{template} = 'message.tt2';
49 $c->stash->{message} = 'Hello World!';
50 $c->forward('MyApp::V::TT');
53 # access variables from template
55 The message is: [% message %].
57 # example when CATALYST_VAR is set to 'Catalyst'
58 Context is [% Catalyst %]
59 The base is [% Catalyst.req.base %]
60 The name is [% Catalyst.config.name %]
62 # example when CATALYST_VAR isn't set
64 The base is [% base %]
65 The name is [% name %]
69 This is the Catalyst view class for the L<Template Toolkit|Template>.
70 Your application should defined a view class which is a subclass of
71 this module. The easiest way to achieve this is using the
72 F<myapp_create.pl> script (where F<myapp> should be replaced with
73 whatever your application is called). This script is created as part
74 of the Catalyst setup.
76 $ script/myapp_create.pl view TT TT
78 This creates a MyApp::V::TT.pm module in the F<lib> directory (again,
79 replacing C<MyApp> with the name of your application) which looks
82 package FooBar::V::TT;
85 use base 'Catalyst::View::TT';
87 __PACKAGE__->config->{DEBUG} = 'all';
89 Now you can modify your action handlers in the main application and/or
90 controllers to forward to your view class. You might choose to do this
91 in the end() method, for example, to automatically forward all actions
94 # In MyApp or MyApp::Controller::SomeController
98 $c->forward('MyApp::V::TT');
103 There are a three different ways to configure your view class. The
104 first way is to call the C<config()> method in the view subclass. This
105 happens when the module is first loaded.
107 package MyApp::V::TT;
110 use base 'Catalyst::View::TT';
112 MyApp::V::TT->config({
114 MyApp->path_to( 'root', 'templates', 'lib' ),
115 MyApp->path_to( 'root', 'templates', 'src' ),
117 PRE_PROCESS => 'config/main',
118 WRAPPER => 'site/wrapper',
121 The second way is to define a C<new()> method in your view subclass.
122 This performs the configuration when the view object is created,
123 shortly after being loaded. Remember to delegate to the base class
124 C<new()> method (via C<$self-E<gt>NEXT::new()> in the example below) after
125 performing any configuration.
131 MyApp->path_to( 'root', 'templates', 'lib' ),
132 MyApp->path_to( 'root', 'templates', 'src' ),
134 PRE_PROCESS => 'config/main',
135 WRAPPER => 'site/wrapper',
137 return $self->NEXT::new(@_);
140 The final, and perhaps most direct way, is to define a class
141 item in your main application configuration, again by calling the
142 uniquitous C<config()> method. The items in the class hash are
143 added to those already defined by the above two methods. This happens
144 in the base class new() method (which is one reason why you must
145 remember to call it via C<NEXT> if you redefine the C<new()> method in a
155 root => MyApp->path_to('root'),
158 MyApp->path_to( 'root', 'templates', 'lib' ),
159 MyApp->path_to( 'root', 'templates', 'src' ),
161 PRE_PROCESS => 'config/main',
162 WRAPPER => 'site/wrapper',
166 Note that any configuration items defined by one of the earlier
167 methods will be overwritten by items of the same name provided by the
170 =head2 DYNAMIC INCLUDE_PATH
172 Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
174 Additional paths can be added to the start of INCLUDE_PATH via the stash as
177 $c->stash->{additional_template_paths} =
178 [$c->config->{root} . '/test_include_path'];
180 If you need to add paths to the end of INCLUDE_PATH, there is also an
181 include_path() accessor available:
183 push( @{ $c->view('TT')->include_path }, qw/path/ );
185 Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
186 MUST check for duplicate paths. Without such checking, the above code will add
187 "path" to INCLUDE_PATH at every request, causing a memory leak.
189 A safer approach is to use include_path() to overwrite the array of paths
190 rather than adding to it. This eliminates both the need to perform duplicate
191 checking and the chance of a memory leak:
193 @{ $c->view('TT')->include_path } = qw/path another_path/;
195 =head2 RENDERING VIEWS
197 The view plugin renders the template specified in the C<template>
200 sub message : Global {
201 my ( $self, $c ) = @_;
202 $c->stash->{template} = 'message.tt2';
203 $c->forward('MyApp::V::TT');
206 If a class item isn't defined, then it instead uses the
207 current match, as returned by C<$c-E<gt>match>. In the above
208 example, this would be C<message>.
210 The items defined in the stash are passed to the Template Toolkit for
211 use as template variables.
213 sub message : Global {
214 sub default : Private {
215 my ( $self, $c ) = @_;
216 $c->stash->{template} = 'message.tt2';
217 $c->stash->{message} = 'Hello World!';
218 $c->forward('MyApp::V::TT');
221 A number of other template variables are also added:
223 c A reference to the context object, $c
224 base The URL base, from $c->req->base()
225 name The application name, from $c->config->{ name }
227 These can be accessed from the template in the usual way:
231 The message is: [% message %]
232 The base is [% base %]
233 The name is [% name %]
236 The output generated by the template is stored in
237 C<$c-E<gt>response-E<gt>output>.
239 =head2 TEMPLATE PROFILING
247 The constructor for the TT view. Sets up the template provider,
248 and reads the application config.
253 my ( $paths, $dlim ) = shift;
254 return () if ( !$paths );
255 return @{$paths} if ( ref $paths eq 'ARRAY' );
257 # tweak delim to ignore C:/
258 unless ( defined $dlim ) {
259 $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
261 return split( /$dlim/, $paths );
265 my ( $class, $c, $arguments ) = @_;
268 TEMPLATE_EXTENSION => '',
272 if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
273 my $delim = $config->{DELIMITER};
275 = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
276 if ( !@include_path ) {
277 my $root = $c->config->{root};
278 my $base = Path::Class::dir( $root, 'base' );
279 @include_path = ( "$root", "$base" );
281 $config->{INCLUDE_PATH} = \@include_path;
286 # if we're debugging and/or the TIMER option is set, then we install
287 # Template::Timer as a custom CONTEXT object, but only if we haven't
288 # already got a custom CONTEXT defined
290 if ( $config->{TIMER} ) {
291 if ( $config->{CONTEXT} ) {
293 'Cannot use Template::Timer - a TT CONFIG is already defined'
297 $config->{CONTEXT} = Template::Timer->new(%$config);
301 if ( $c->debug && $config->{DUMP_CONFIG} ) {
303 $c->log->debug( "TT Config: ", Dumper($config) );
305 if ( $config->{PROVIDERS} ) {
307 if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
308 foreach my $p (@{$config->{PROVIDERS}}) {
309 my $pname = $p->{name};
310 eval "require Template::Provider::$pname";
312 push @providers, "Template::Provider::${pname}"->new($p->{args});
316 delete $config->{PROVIDERS};
318 $config->{LOAD_TEMPLATES} = \@providers;
322 my $self = $class->NEXT::new(
324 { template => Template->new($config) || do {
325 my $error = Template->error();
326 $c->log->error($error);
333 $self->include_path($config->{INCLUDE_PATH});
334 $self->config($config);
341 Renders the template specified in C<$c-E<gt>stash-E<gt>{template}> or
342 C<$c-E<gt>action> (the private name of the matched action.
343 Template variables are set up from the contents of C<$c-E<gt>stash>,
344 augmented with C<base> set to C<$c-E<gt>req-E<gt>base>, C<c> to C<$c> and
345 C<name> to C<$c-E<gt>config-E<gt>{name}>. Alternately, the C<CATALYST_VAR>
346 configuration item can be defined to specify the name of a template
347 variable through which the context reference (C<$c>) can be accessed.
348 In this case, the C<c>, C<base> and C<name> variables are omitted.
349 Output is stored in C<$c-E<gt>response-E<gt>output>.
354 my ( $self, $c ) = @_;
356 my $template = $c->stash->{template}
357 || $c->action . $self->config->{TEMPLATE_EXTENSION};
360 $c->log->debug('No template specified for rendering') if $c->debug;
364 $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
367 my $vars = { $self->template_vars($c) };
369 unshift @{ $self->include_path },
370 @{ $c->stash->{additional_template_paths} }
371 if ref $c->stash->{additional_template_paths};
372 unless ( $self->template->process( $template, $vars, \$output ) ) {
373 my $error = $self->template->error;
374 $error = qq/Couldn't render template "$error"/;
375 $c->log->error($error);
379 splice @{ $self->include_path }, 0,
380 scalar @{ $c->stash->{additional_template_paths} }
381 if ref $c->stash->{additional_template_paths};
383 unless ( $c->response->content_type ) {
384 $c->response->content_type('text/html; charset=utf-8');
387 $c->response->body($output);
394 Returns a list of keys/values to be used as the variables in the
400 my ( $self, $c ) = @_;
402 my $cvar = $self->config->{CATALYST_VAR};
408 base => $c->req->base,
409 name => $c->config->{name}
416 This method allows your view subclass to pass additional settings to
417 the TT configuration hash, or to set the options as below:
421 =item C<CATALYST_VAR>
423 Allows you to change the name of the Catalyst context object. If set, it will also
424 remove the base and name aliases, so you will have access them through <context>.
430 root => MyApp->path_to('root'),
432 CATALYST_VAR => 'Catalyst',
438 The base is [% Catalyst.req.base %]
439 The name is [% Catalyst.config.name %]
443 If you have configured Catalyst for debug output, and turned on the TIMER setting,
444 C<Catalyst::View::TT> will enable profiling of template processing
445 (using L<Template::Timer>). This will embed HTML comments in the
446 output from your templates, such as:
448 <!-- TIMER START: process mainmenu/mainmenu.ttml -->
449 <!-- TIMER START: include mainmenu/cssindex.tt -->
450 <!-- TIMER START: process mainmenu/cssindex.tt -->
451 <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
452 <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
456 <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
459 =item C<TEMPLATE_EXTENSION>
461 a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
465 package MyApp::C::Test;
466 sub test : Local { .. }
468 Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
477 The L<Catalyst::Helper::View::TT> and
478 L<Catalyst::Helper::View::TTSite> helper modules are provided to create
479 your view module. There are invoked by the F<myapp_create.pl> script:
481 $ script/myapp_create.pl view TT TT
483 $ script/myapp_create.pl view TT TTSite
485 The L<Catalyst::Helper::View::TT> module creates a basic TT view
486 module. The L<Catalyst::Helper::View::TTSite> module goes a little
487 further. It also creates a default set of templates to get you
488 started. It also configures the view module to locate the templates
493 L<Catalyst>, L<Catalyst::Helper::View::TT>,
494 L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
498 Sebastian Riedel, C<sri@cpan.org>
500 Marcus Ramberg, C<mramberg@cpan.org>
502 Jesse Sheidlower, C<jester@panix.com>
504 Andy Wardley, C<abw@cpan.org>
508 This program is free software, you can redistribute it and/or modify it
509 under the same terms as Perl itself.