Commit | Line | Data |
8077080c |
1 | package Catalyst::View::TT; |
2 | |
3 | use strict; |
6229ce0d |
4 | use warnings; |
5 | |
7d8aa5ec |
6 | use base qw/Catalyst::View/; |
9e739e1e |
7 | use Data::Dump 'dump'; |
8077080c |
8 | use Template; |
9 | use Template::Timer; |
e8693f1b |
10 | use MRO::Compat; |
4a70bc59 |
11 | use Scalar::Util qw/blessed weaken/; |
8077080c |
12 | |
036d5905 |
13 | our $VERSION = '0.43'; |
85ea459d |
14 | $VERSION = eval $VERSION; |
8077080c |
15 | |
16 | __PACKAGE__->mk_accessors('template'); |
46cdc47d |
17 | __PACKAGE__->mk_accessors('expose_methods'); |
e2bbd784 |
18 | __PACKAGE__->mk_accessors('include_path'); |
59a2e92a |
19 | __PACKAGE__->mk_accessors('content_type'); |
8077080c |
20 | |
9d574573 |
21 | *paths = \&include_path; |
22 | |
8077080c |
23 | =head1 NAME |
24 | |
25 | Catalyst::View::TT - Template View Class |
26 | |
27 | =head1 SYNOPSIS |
28 | |
bd4ee63a |
29 | # use the helper to create your View |
ad50568f |
30 | |
226c1dd3 |
31 | myapp_create.pl view Web TT |
8077080c |
32 | |
9b2e9e13 |
33 | # add custom configuration in View/Web.pm |
8cd017a8 |
34 | |
940a2e8a |
35 | __PACKAGE__->config( |
226c1dd3 |
36 | # any TT configuration items go here |
226c1dd3 |
37 | TEMPLATE_EXTENSION => '.tt', |
38 | CATALYST_VAR => 'c', |
39 | TIMER => 0, |
61e9ca2a |
40 | ENCODING => 'utf-8' |
226c1dd3 |
41 | # Not set by default |
42 | PRE_PROCESS => 'config/main', |
43 | WRAPPER => 'site/wrapper', |
44 | render_die => 1, # Default for new apps, see render method docs |
a6fa99df |
45 | expose_methods => [qw/method_in_view_class/], |
ae035767 |
46 | ); |
f5b61ad7 |
47 | |
61e9ca2a |
48 | # add include path configuration in MyApp.pm |
49 | |
50 | __PACKAGE__->config( |
51 | 'View::Web' => { |
52 | INCLUDE_PATH => [ |
53 | __PACKAGE__->path_to( 'root', 'src' ), |
54 | __PACKAGE__->path_to( 'root', 'lib' ), |
55 | ], |
56 | }, |
57 | ); |
58 | |
6229ce0d |
59 | # render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm |
f5b61ad7 |
60 | |
8cd017a8 |
61 | sub message : Global { |
94b3529a |
62 | my ( $self, $c ) = @_; |
63 | $c->stash->{template} = 'message.tt2'; |
64 | $c->stash->{message} = 'Hello World!'; |
226c1dd3 |
65 | $c->forward( $c->view('Web') ); |
8cd017a8 |
66 | } |
8077080c |
67 | |
8cd017a8 |
68 | # access variables from template |
69 | |
70 | The message is: [% message %]. |
f5b61ad7 |
71 | |
8cd017a8 |
72 | # example when CATALYST_VAR is set to 'Catalyst' |
f5b61ad7 |
73 | Context is [% Catalyst %] |
74 | The base is [% Catalyst.req.base %] |
75 | The name is [% Catalyst.config.name %] |
76 | |
8cd017a8 |
77 | # example when CATALYST_VAR isn't set |
78 | Context is [% c %] |
79 | The base is [% base %] |
80 | The name is [% name %] |
81 | |
bd4ee63a |
82 | =cut |
83 | |
84 | sub _coerce_paths { |
85 | my ( $paths, $dlim ) = shift; |
86 | return () if ( !$paths ); |
87 | return @{$paths} if ( ref $paths eq 'ARRAY' ); |
88 | |
89 | # tweak delim to ignore C:/ |
90 | unless ( defined $dlim ) { |
91 | $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':'; |
92 | } |
93 | return split( /$dlim/, $paths ); |
94 | } |
95 | |
96 | sub new { |
97 | my ( $class, $c, $arguments ) = @_; |
98 | my $config = { |
99 | EVAL_PERL => 0, |
100 | TEMPLATE_EXTENSION => '', |
7bd88b61 |
101 | CLASS => 'Template', |
bd4ee63a |
102 | %{ $class->config }, |
103 | %{$arguments}, |
104 | }; |
105 | if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) { |
106 | my $delim = $config->{DELIMITER}; |
107 | my @include_path |
108 | = _coerce_paths( $config->{INCLUDE_PATH}, $delim ); |
109 | if ( !@include_path ) { |
110 | my $root = $c->config->{root}; |
111 | my $base = Path::Class::dir( $root, 'base' ); |
112 | @include_path = ( "$root", "$base" ); |
113 | } |
114 | $config->{INCLUDE_PATH} = \@include_path; |
115 | } |
116 | |
117 | # if we're debugging and/or the TIMER option is set, then we install |
118 | # Template::Timer as a custom CONTEXT object, but only if we haven't |
119 | # already got a custom CONTEXT defined |
120 | |
121 | if ( $config->{TIMER} ) { |
122 | if ( $config->{CONTEXT} ) { |
123 | $c->log->error( |
124 | 'Cannot use Template::Timer - a TT CONTEXT is already defined' |
125 | ); |
126 | } |
127 | else { |
128 | $config->{CONTEXT} = Template::Timer->new(%$config); |
129 | } |
130 | } |
131 | |
132 | if ( $c->debug && $config->{DUMP_CONFIG} ) { |
9e739e1e |
133 | $c->log->debug( "TT Config: ", dump($config) ); |
bd4ee63a |
134 | } |
6175bba7 |
135 | |
e8693f1b |
136 | my $self = $class->next::method( |
f5b61ad7 |
137 | $c, { %$config }, |
6175bba7 |
138 | ); |
139 | |
140 | # Set base include paths. Local'd in render if needed |
141 | $self->include_path($config->{INCLUDE_PATH}); |
f5b61ad7 |
142 | |
46cdc47d |
143 | $self->expose_methods($config->{expose_methods}); |
6175bba7 |
144 | $self->config($config); |
145 | |
146 | # Creation of template outside of call to new so that we can pass [ $self ] |
147 | # as INCLUDE_PATH config item, which then gets ->paths() called to get list |
148 | # of include paths to search for templates. |
f5b61ad7 |
149 | |
9b2e9e13 |
150 | # Use a weakened copy of self so we don't have loops preventing GC from working |
6175bba7 |
151 | my $copy = $self; |
152 | Scalar::Util::weaken($copy); |
153 | $config->{INCLUDE_PATH} = [ sub { $copy->paths } ]; |
154 | |
bd4ee63a |
155 | if ( $config->{PROVIDERS} ) { |
156 | my @providers = (); |
157 | if ( ref($config->{PROVIDERS}) eq 'ARRAY') { |
158 | foreach my $p (@{$config->{PROVIDERS}}) { |
159 | my $pname = $p->{name}; |
160 | my $prov = 'Template::Provider'; |
161 | if($pname eq '_file_') |
162 | { |
163 | $p->{args} = { %$config }; |
164 | } |
165 | else |
166 | { |
51199593 |
167 | if($pname =~ s/^\+//) { |
168 | $prov = $pname; |
169 | } |
170 | else |
171 | { |
172 | $prov .= "::$pname"; |
173 | } |
6175bba7 |
174 | # We copy the args people want from the config |
175 | # to the args |
176 | $p->{args} ||= {}; |
177 | if ($p->{copy_config}) { |
178 | map { $p->{args}->{$_} = $config->{$_} } |
179 | grep { exists $config->{$_} } |
180 | @{ $p->{copy_config} }; |
181 | } |
bd4ee63a |
182 | } |
fc0ffed0 |
183 | local $@; |
bd4ee63a |
184 | eval "require $prov"; |
185 | if(!$@) { |
186 | push @providers, "$prov"->new($p->{args}); |
187 | } |
188 | else |
189 | { |
190 | $c->log->warn("Can't load $prov, ($@)"); |
191 | } |
192 | } |
193 | } |
194 | delete $config->{PROVIDERS}; |
195 | if(@providers) { |
196 | $config->{LOAD_TEMPLATES} = \@providers; |
197 | } |
198 | } |
f5b61ad7 |
199 | |
200 | $self->{template} = |
7bd88b61 |
201 | $config->{CLASS}->new($config) || do { |
202 | my $error = $config->{CLASS}->error(); |
bd4ee63a |
203 | $c->log->error($error); |
204 | $c->error($error); |
205 | return undef; |
206 | }; |
207 | |
208 | |
209 | return $self; |
210 | } |
211 | |
212 | sub process { |
213 | my ( $self, $c ) = @_; |
214 | |
215 | my $template = $c->stash->{template} |
216 | || $c->action . $self->config->{TEMPLATE_EXTENSION}; |
217 | |
218 | unless (defined $template) { |
219 | $c->log->debug('No template specified for rendering') if $c->debug; |
220 | return 0; |
221 | } |
222 | |
fc0ffed0 |
223 | local $@; |
cad820fe |
224 | my $output = eval { $self->render($c, $template) }; |
225 | if (my $err = $@) { |
c5c3c6bd |
226 | return $self->_rendering_error($c, $template . ': ' . $err); |
316f014a |
227 | } |
228 | if (blessed($output) && $output->isa('Template::Exception')) { |
229 | $self->_rendering_error($c, $output); |
bd4ee63a |
230 | } |
231 | |
232 | unless ( $c->response->content_type ) { |
e0bcfc98 |
233 | my $default = $self->content_type || 'text/html; charset=UTF-8'; |
59a2e92a |
234 | $c->response->content_type($default); |
bd4ee63a |
235 | } |
236 | |
237 | $c->response->body($output); |
238 | |
239 | return 1; |
240 | } |
241 | |
316f014a |
242 | sub _rendering_error { |
243 | my ($self, $c, $err) = @_; |
244 | my $error = qq/Couldn't render template "$err"/; |
245 | $c->log->error($error); |
246 | $c->error($error); |
247 | return 0; |
248 | } |
249 | |
bd4ee63a |
250 | sub render { |
251 | my ($self, $c, $template, $args) = @_; |
252 | |
cbb149dc |
253 | $c->log->debug(qq/Rendering template "$template"/) if $c && $c->debug; |
bd4ee63a |
254 | |
255 | my $output; |
f5b61ad7 |
256 | my $vars = { |
bd4ee63a |
257 | (ref $args eq 'HASH' ? %$args : %{ $c->stash() }), |
258 | $self->template_vars($c) |
259 | }; |
260 | |
f5b61ad7 |
261 | local $self->{include_path} = |
bd4ee63a |
262 | [ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ] |
263 | if ref $vars->{additional_template_paths}; |
264 | |
596ff245 |
265 | unless ( $self->template->process( $template, $vars, \$output ) ) { |
266 | if (exists $self->{render_die}) { |
267 | die $self->template->error if $self->{render_die}; |
268 | return $self->template->error; |
269 | } |
ee816c02 |
270 | $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($self) . '. If you wish to continue to return the exception rather than throwing it, add render_die => 0 to your config.') if $c && $c->debug; |
596ff245 |
271 | return $self->template->error; |
272 | } |
cad820fe |
273 | return $output; |
bd4ee63a |
274 | } |
275 | |
276 | sub template_vars { |
277 | my ( $self, $c ) = @_; |
278 | |
cbb149dc |
279 | return () unless $c; |
bd4ee63a |
280 | my $cvar = $self->config->{CATALYST_VAR}; |
281 | |
a6fa99df |
282 | my %vars = defined $cvar |
bd4ee63a |
283 | ? ( $cvar => $c ) |
284 | : ( |
285 | c => $c, |
286 | base => $c->req->base, |
287 | name => $c->config->{name} |
a6fa99df |
288 | ); |
289 | |
46cdc47d |
290 | if ($self->expose_methods) { |
a6fa99df |
291 | my $meta = $self->meta; |
46cdc47d |
292 | foreach my $method_name (@{$self->expose_methods}) { |
1cb1d672 |
293 | my $method = $meta->find_method_by_name( $method_name ); |
a6fa99df |
294 | unless ($method) { |
295 | Catalyst::Exception->throw( "$method_name not found in TT view" ); |
296 | } |
297 | my $method_body = $method->body; |
4a70bc59 |
298 | my $weak_ctx = $c; |
299 | weaken $weak_ctx; |
a6fa99df |
300 | my $sub = sub { |
4a70bc59 |
301 | $self->$method_body($weak_ctx, @_); |
a6fa99df |
302 | }; |
303 | $vars{$method_name} = $sub; |
304 | } |
305 | } |
306 | return %vars; |
bd4ee63a |
307 | } |
308 | |
bd4ee63a |
309 | 1; |
310 | |
311 | __END__ |
312 | |
8cd017a8 |
313 | =head1 DESCRIPTION |
314 | |
315 | This is the Catalyst view class for the L<Template Toolkit|Template>. |
316 | Your application should defined a view class which is a subclass of |
226c1dd3 |
317 | this module. Throughout this manual it will be assumed that your application |
318 | is named F<MyApp> and you are creating a TT view named F<Web>; these names |
319 | are placeholders and should always be replaced with whatever name you've |
320 | chosen for your application and your view. The easiest way to create a TT |
321 | view class is through the F<myapp_create.pl> script that is created along |
322 | with the application: |
8cd017a8 |
323 | |
226c1dd3 |
324 | $ script/myapp_create.pl view Web TT |
8cd017a8 |
325 | |
226c1dd3 |
326 | This creates a F<MyApp::View::Web.pm> module in the F<lib> directory (again, |
8cd017a8 |
327 | replacing C<MyApp> with the name of your application) which looks |
328 | something like this: |
329 | |
226c1dd3 |
330 | package FooBar::View::Web; |
62a61466 |
331 | use Moose; |
f5b61ad7 |
332 | |
62a61466 |
333 | extends 'Catalyst::View::TT'; |
8077080c |
334 | |
a1b7968f |
335 | __PACKAGE__->config(DEBUG => 'all'); |
8077080c |
336 | |
8cd017a8 |
337 | Now you can modify your action handlers in the main application and/or |
338 | controllers to forward to your view class. You might choose to do this |
339 | in the end() method, for example, to automatically forward all actions |
340 | to the TT view class. |
722fede4 |
341 | |
8cd017a8 |
342 | # In MyApp or MyApp::Controller::SomeController |
f5b61ad7 |
343 | |
8cd017a8 |
344 | sub end : Private { |
94b3529a |
345 | my( $self, $c ) = @_; |
226c1dd3 |
346 | $c->forward( $c->view('Web') ); |
8cd017a8 |
347 | } |
8077080c |
348 | |
2844488f |
349 | But if you are using the standard auto-generated end action, you don't even need |
350 | to do this! |
351 | |
352 | # in MyApp::Controller::Root |
353 | sub end : ActionClass('RenderView') {} # no need to change this line |
354 | |
355 | # in MyApp.pm |
356 | __PACKAGE__->config( |
357 | ... |
226c1dd3 |
358 | default_view => 'Web', |
2844488f |
359 | ); |
360 | |
361 | This will Just Work. And it has the advantages that: |
362 | |
363 | =over 4 |
364 | |
365 | =item * |
366 | |
367 | If you want to use a different view for a given request, just set |
368 | << $c->stash->{current_view} >>. (See L<Catalyst>'s C<< $c->view >> method |
369 | for details. |
370 | |
371 | =item * |
372 | |
373 | << $c->res->redirect >> is handled by default. If you just forward to |
226c1dd3 |
374 | C<View::Web> in your C<end> routine, you could break this by sending additional |
2844488f |
375 | content. |
376 | |
377 | =back |
378 | |
379 | See L<Catalyst::Action::RenderView> for more details. |
380 | |
8cd017a8 |
381 | =head2 CONFIGURATION |
4687ac0d |
382 | |
8cd017a8 |
383 | There are a three different ways to configure your view class. The |
384 | first way is to call the C<config()> method in the view subclass. This |
385 | happens when the module is first loaded. |
8077080c |
386 | |
226c1dd3 |
387 | package MyApp::View::Web; |
adb2ce78 |
388 | use Moose; |
389 | extends 'Catalyst::View::TT'; |
722fede4 |
390 | |
226c1dd3 |
391 | __PACKAGE__->config({ |
8cd017a8 |
392 | PRE_PROCESS => 'config/main', |
393 | WRAPPER => 'site/wrapper', |
394 | }); |
395 | |
226c1dd3 |
396 | You may also override the configuration provided in the view class by adding |
adb2ce78 |
397 | a 'View::Web' section to your application config. |
398 | |
399 | This should generally be used to inject the include paths into the view to |
400 | avoid the view trying to load the application to resolve paths. |
401 | |
402 | .. inside MyApp.pm .. |
403 | __PACKAGE__->config( |
404 | 'View::Web' => { |
405 | INCLUDE_PATH => [ |
406 | __PACKAGE__->path_to( 'root', 'templates', 'lib' ), |
407 | __PACKAGE__->path_to( 'root', 'templates', 'src' ), |
408 | ], |
409 | }, |
410 | ); |
411 | |
412 | You can also configure your view from within your config file if you're |
413 | using L<Catalyst::Plugin::ConfigLoader>. This should be reserved for |
226c1dd3 |
414 | deployment-specific concerns. For example: |
8cd017a8 |
415 | |
226c1dd3 |
416 | # MyApp_local.conf (Config::General format) |
f5b61ad7 |
417 | |
226c1dd3 |
418 | <View Web> |
419 | WRAPPER "custom_wrapper" |
420 | INCLUDE_PATH __path_to('root/templates/custom_site')__ |
421 | INCLUDE_PATH __path_to('root/templates')__ |
422 | </View> |
8cd017a8 |
423 | |
226c1dd3 |
424 | might be used as part of a simple way to deploy different instances of the |
425 | same application with different themes. |
8cd017a8 |
426 | |
e2bbd784 |
427 | =head2 DYNAMIC INCLUDE_PATH |
428 | |
f7dfca06 |
429 | Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time. |
f5b61ad7 |
430 | |
f7dfca06 |
431 | Additional paths can be added to the start of INCLUDE_PATH via the stash as |
432 | follows: |
433 | |
434 | $c->stash->{additional_template_paths} = |
435 | [$c->config->{root} . '/test_include_path']; |
436 | |
437 | If you need to add paths to the end of INCLUDE_PATH, there is also an |
438 | include_path() accessor available: |
439 | |
226c1dd3 |
440 | push( @{ $c->view('Web')->include_path }, qw/path/ ); |
f7dfca06 |
441 | |
442 | Note that if you use include_path() to add extra paths to INCLUDE_PATH, you |
443 | MUST check for duplicate paths. Without such checking, the above code will add |
444 | "path" to INCLUDE_PATH at every request, causing a memory leak. |
445 | |
446 | A safer approach is to use include_path() to overwrite the array of paths |
447 | rather than adding to it. This eliminates both the need to perform duplicate |
448 | checking and the chance of a memory leak: |
e2bbd784 |
449 | |
226c1dd3 |
450 | @{ $c->view('Web')->include_path } = qw/path another_path/; |
e2bbd784 |
451 | |
f5b61ad7 |
452 | If you are calling C<render> directly then you can specify dynamic paths by |
9b2e9e13 |
453 | having a C<additional_template_paths> key with a value of additional directories |
1bc9fc55 |
454 | to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this. |
455 | |
93c63aff |
456 | =head2 Unicode (pre Catalyst v5.90080) |
e22ff352 |
457 | |
e0bcfc98 |
458 | B<NOTE> Starting with L<Catalyst> v5.90080 unicode and encoding has been |
459 | baked into core, and the default encoding is UTF-8. The following advice |
93c63aff |
460 | is for older versions of L<Catalyst>. |
e0bcfc98 |
461 | |
e22ff352 |
462 | Be sure to set C<< ENCODING => 'utf-8' >> and use |
463 | L<Catalyst::Plugin::Unicode::Encoding> if you want to use non-ascii |
93c63aff |
464 | characters (encoded as utf-8) in your templates. This is only needed if |
465 | you actually have UTF8 literals in your templates and the BOM is not |
466 | properly set. Setting encoding here does not magically encode your |
467 | template output. If you are using this version of L<Catalyst> you need |
468 | to all the Unicode plugin, or upgrade (preferred) |
469 | |
470 | =head2 Unicode (Catalyst v5.90080+) |
471 | |
472 | This version of L<Catalyst> will automatically encode your body output |
473 | to UTF8. This means if your variables contain multibyte characters you don't |
474 | need top do anything else to get UTF8 output. B<However> if your templates |
475 | contain UTF8 literals (like, multibyte characters actually in the template |
476 | text), then you do need to either set the BOM mark on the template file or |
477 | instruct TT to decode the templates at load time via the ENCODING configuration |
478 | setting. Most of the time you can just do: |
479 | |
480 | MyApp::View::HTML->config( |
481 | ENCODING => 'UTF-8'); |
482 | |
483 | and that will just take care of everything. This configuration setting will |
484 | force L<Template> to decode all files correctly, so that when you hit |
485 | the finalize_encoding step we can properly encode the body as UTF8. If you |
486 | fail to do this you will get double encoding issues in your output (but again, |
487 | only for the UTF8 literals in your actual template text.) |
488 | |
489 | Again, this ENCODING configuration setting only instructs template toolkit |
490 | how (and if) to decode the contents of your template files when reading them from |
491 | disk. It has no other effect. |
e22ff352 |
492 | |
8cd017a8 |
493 | =head2 RENDERING VIEWS |
494 | |
495 | The view plugin renders the template specified in the C<template> |
f5b61ad7 |
496 | item in the stash. |
8cd017a8 |
497 | |
498 | sub message : Global { |
94b3529a |
499 | my ( $self, $c ) = @_; |
500 | $c->stash->{template} = 'message.tt2'; |
226c1dd3 |
501 | $c->forward( $c->view('Web') ); |
8cd017a8 |
502 | } |
722fede4 |
503 | |
c969f23a |
504 | If a stash item isn't defined, then it instead uses the |
505 | stringification of the action dispatched to (as defined by $c->action) |
506 | in the above example, this would be C<message>, but because the default |
507 | is to append '.tt', it would load C<root/message.tt>. |
8cd017a8 |
508 | |
509 | The items defined in the stash are passed to the Template Toolkit for |
510 | use as template variables. |
511 | |
8cd017a8 |
512 | sub default : Private { |
94b3529a |
513 | my ( $self, $c ) = @_; |
514 | $c->stash->{template} = 'message.tt2'; |
515 | $c->stash->{message} = 'Hello World!'; |
226c1dd3 |
516 | $c->forward( $c->view('Web') ); |
8cd017a8 |
517 | } |
7b592fc7 |
518 | |
8cd017a8 |
519 | A number of other template variables are also added: |
8077080c |
520 | |
8cd017a8 |
521 | c A reference to the context object, $c |
522 | base The URL base, from $c->req->base() |
523 | name The application name, from $c->config->{ name } |
524 | |
525 | These can be accessed from the template in the usual way: |
526 | |
527 | <message.tt2>: |
528 | |
529 | The message is: [% message %] |
530 | The base is [% base %] |
531 | The name is [% name %] |
532 | |
8cd017a8 |
533 | |
1bc9fc55 |
534 | The output generated by the template is stored in C<< $c->response->body >>. |
535 | |
536 | =head2 CAPTURING TEMPLATE OUTPUT |
537 | |
538 | If you wish to use the output of a template for some other purpose than |
539 | displaying in the response, e.g. for sending an email, this is possible using |
161400d1 |
540 | other views, such as L<Catalyst::View::Email::Template>. |
8cd017a8 |
541 | |
542 | =head2 TEMPLATE PROFILING |
543 | |
1bc9fc55 |
544 | See L<C<TIMER>> property of the L<config> method. |
545 | |
caa61517 |
546 | =head2 METHODS |
8077080c |
547 | |
b63ddd04 |
548 | =head2 new |
2774dc77 |
549 | |
f5b61ad7 |
550 | The constructor for the TT view. Sets up the template provider, |
2774dc77 |
551 | and reads the application config. |
552 | |
81b7f2a2 |
553 | =head2 process($c) |
8077080c |
554 | |
1bc9fc55 |
555 | Renders the template specified in C<< $c->stash->{template} >> or |
ad50568f |
556 | C<< $c->action >> (the private name of the matched action). Calls L<render> to |
1bc9fc55 |
557 | perform actual rendering. Output is stored in C<< $c->response->body >>. |
8077080c |
558 | |
81b7f2a2 |
559 | It is possible to forward to the process method of a TT view from inside |
560 | Catalyst like this: |
561 | |
226c1dd3 |
562 | $c->forward('View::Web'); |
81b7f2a2 |
563 | |
564 | N.B. This is usually done automatically by L<Catalyst::Action::RenderView>. |
f2ee4d6c |
565 | |
b63ddd04 |
566 | =head2 render($c, $template, \%args) |
1bc9fc55 |
567 | |
cad820fe |
568 | Renders the given template and returns output. Throws a L<Template::Exception> |
f5b61ad7 |
569 | object upon error. |
1bc9fc55 |
570 | |
75dc0329 |
571 | The template variables are set to C<%$args> if C<$args> is a hashref, or |
572 | C<< $c->stash >> otherwise. In either case the variables are augmented with |
3d543eda |
573 | C<base> set to C<< $c->req->base >>, C<c> to C<$c>, and C<name> to |
1bc9fc55 |
574 | C<< $c->config->{name} >>. Alternately, the C<CATALYST_VAR> configuration item |
575 | can be defined to specify the name of a template variable through which the |
3d543eda |
576 | context reference (C<$c>) can be accessed. In this case, the C<c>, C<base>, and |
1bc9fc55 |
577 | C<name> variables are omitted. |
578 | |
f5b61ad7 |
579 | C<$template> can be anything that Template::process understands how to |
1bc9fc55 |
580 | process, including the name of a template file or a reference to a test string. |
581 | See L<Template::process|Template/process> for a full list of supported formats. |
582 | |
f59953e1 |
583 | To use the render method outside of your Catalyst app, just pass a undef context. |
cbb149dc |
584 | This can be useful for tests, for instance. |
585 | |
81b7f2a2 |
586 | It is possible to forward to the render method of a TT view from inside Catalyst |
587 | to render page fragments like this: |
588 | |
226c1dd3 |
589 | my $fragment = $c->forward("View::Web", "render", $template_name, $c->stash->{fragment_data}); |
f2ee4d6c |
590 | |
3715305f |
591 | =head3 Backwards compatibility note |
592 | |
593 | The render method used to just return the Template::Exception object, rather |
594 | than just throwing it. This is now deprecated and instead the render method |
595 | will throw an exception for new applications. |
596 | |
597 | This behaviour can be activated (and is activated in the default skeleton |
598 | configuration) by using C<< render_die => 1 >>. If you rely on the legacy |
599 | behaviour then a warning will be issued. |
600 | |
601 | To silence this warning, set C<< render_die => 0 >>, but it is recommended |
602 | you adjust your code so that it works with C<< render_die => 1 >>. |
603 | |
604 | In a future release, C<< render_die => 1 >> will become the default if |
605 | unspecified. |
606 | |
b63ddd04 |
607 | =head2 template_vars |
850ee226 |
608 | |
1bc9fc55 |
609 | Returns a list of keys/values to be used as the catalyst variables in the |
850ee226 |
610 | template. |
611 | |
b63ddd04 |
612 | =head2 config |
8077080c |
613 | |
8cd017a8 |
614 | This method allows your view subclass to pass additional settings to |
4729c102 |
615 | the TT configuration hash, or to set the options as below: |
616 | |
b63ddd04 |
617 | =head2 paths |
618 | |
619 | The list of paths TT will look for templates in. |
4729c102 |
620 | |
a6fa99df |
621 | =head2 expose_methods |
622 | |
623 | The list of methods in your View class which should be made available to the templates. |
624 | |
625 | For example: |
626 | |
582a5059 |
627 | expose_methods => [qw/uri_for_css/], |
a6fa99df |
628 | |
629 | ... |
630 | |
631 | sub uri_for_css { |
632 | my ($self, $c, $filename) = @_; |
633 | |
634 | # additional complexity like checking file exists here |
635 | |
636 | return $c->uri_for('/static/css/' . $filename); |
637 | } |
638 | |
639 | Then in the template: |
640 | |
641 | [% uri_for_css('home.css') %] |
642 | |
59a2e92a |
643 | =head2 content_type |
644 | |
645 | This lets you override the default content type for the response. If you do |
646 | not set this and if you do not set the content type in your controllers, the |
647 | default is C<text/html; charset=utf-8>. |
648 | |
649 | Use this if you are creating alternative view responses, such as text or JSON |
650 | and want a global setting. |
651 | |
652 | Any content type set in your controllers before calling this view are respected |
653 | and have priority. |
654 | |
f5b61ad7 |
655 | =head2 C<CATALYST_VAR> |
4729c102 |
656 | |
657 | Allows you to change the name of the Catalyst context object. If set, it will also |
658 | remove the base and name aliases, so you will have access them through <context>. |
659 | |
226c1dd3 |
660 | For example, if CATALYST_VAR has been set to "Catalyst", a template might |
661 | contain: |
4729c102 |
662 | |
663 | The base is [% Catalyst.req.base %] |
664 | The name is [% Catalyst.config.name %] |
665 | |
b63ddd04 |
666 | =head2 C<TIMER> |
4729c102 |
667 | |
668 | If you have configured Catalyst for debug output, and turned on the TIMER setting, |
669 | C<Catalyst::View::TT> will enable profiling of template processing |
670 | (using L<Template::Timer>). This will embed HTML comments in the |
671 | output from your templates, such as: |
672 | |
673 | <!-- TIMER START: process mainmenu/mainmenu.ttml --> |
674 | <!-- TIMER START: include mainmenu/cssindex.tt --> |
675 | <!-- TIMER START: process mainmenu/cssindex.tt --> |
676 | <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) --> |
677 | <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) --> |
678 | |
679 | .... |
680 | |
681 | <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) --> |
682 | |
683 | |
b63ddd04 |
684 | =head2 C<TEMPLATE_EXTENSION> |
4729c102 |
685 | |
9b2e9e13 |
686 | a suffix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>. |
4729c102 |
687 | |
688 | For example: |
689 | |
6229ce0d |
690 | package MyApp::Controller::Test; |
f5b61ad7 |
691 | sub test : Local { .. } |
4729c102 |
692 | |
693 | Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for |
694 | <root>/test/test.tt. |
695 | |
51199593 |
696 | =head2 C<PROVIDERS> |
697 | |
698 | Allows you to specify the template providers that TT will use. |
699 | |
adb2ce78 |
700 | MyApp->config( |
51199593 |
701 | name => 'MyApp', |
702 | root => MyApp->path_to('root'), |
226c1dd3 |
703 | 'View::Web' => { |
51199593 |
704 | PROVIDERS => [ |
705 | { |
706 | name => 'DBI', |
707 | args => { |
708 | DBI_DSN => 'dbi:DB2:books', |
709 | DBI_USER=> 'foo' |
710 | } |
711 | }, { |
712 | name => '_file_', |
713 | args => {} |
714 | } |
715 | ] |
716 | }, |
adb2ce78 |
717 | ); |
51199593 |
718 | |
719 | The 'name' key should correspond to the class name of the provider you |
720 | want to use. The _file_ name is a special case that represents the default |
721 | TT file-based provider. By default the name is will be prefixed with |
722 | 'Template::Provider::'. You can fully qualify the name by using a unary |
723 | plus: |
724 | |
725 | name => '+MyApp::Provider::Foo' |
726 | |
6175bba7 |
727 | You can also specify the 'copy_config' key as an arrayref, to copy those keys |
728 | from the general config, into the config for the provider: |
f5b61ad7 |
729 | |
6175bba7 |
730 | DEFAULT_ENCODING => 'utf-8', |
731 | PROVIDERS => [ |
732 | { |
733 | name => 'Encoding', |
734 | copy_config => [qw(DEFAULT_ENCODING INCLUDE_PATH)] |
735 | } |
736 | ] |
f5b61ad7 |
737 | |
6175bba7 |
738 | This can prove useful when you want to use the additional_template_paths hack |
739 | in your own provider, or if you need to use Template::Provider::Encoding |
740 | |
7bd88b61 |
741 | =head2 C<CLASS> |
742 | |
743 | Allows you to specify a custom class to use as the template class instead of |
744 | L<Template>. |
745 | |
746 | package MyApp::View::Web; |
62a61466 |
747 | use Moose; |
748 | extends 'Catalyst::View::TT'; |
7bd88b61 |
749 | |
750 | use Template::AutoFilter; |
751 | |
752 | __PACKAGE__->config({ |
753 | CLASS => 'Template::AutoFilter', |
754 | }); |
755 | |
756 | This is useful if you want to use your own subclasses of L<Template>, so you |
757 | can, for example, prevent XSS by automatically filtering all output through |
758 | C<| html>. |
759 | |
8cd017a8 |
760 | =head2 HELPERS |
761 | |
762 | The L<Catalyst::Helper::View::TT> and |
763 | L<Catalyst::Helper::View::TTSite> helper modules are provided to create |
764 | your view module. There are invoked by the F<myapp_create.pl> script: |
765 | |
226c1dd3 |
766 | $ script/myapp_create.pl view Web TT |
8cd017a8 |
767 | |
226c1dd3 |
768 | $ script/myapp_create.pl view Web TTSite |
8cd017a8 |
769 | |
770 | The L<Catalyst::Helper::View::TT> module creates a basic TT view |
771 | module. The L<Catalyst::Helper::View::TTSite> module goes a little |
772 | further. It also creates a default set of templates to get you |
773 | started. It also configures the view module to locate the templates |
774 | automatically. |
775 | |
02c64502 |
776 | =head1 NOTES |
777 | |
778 | If you are using the L<CGI> module inside your templates, you will |
779 | experience that the Catalyst server appears to hang while rendering |
780 | the web page. This is due to the debug mode of L<CGI> (which is |
781 | waiting for input in the terminal window). Turning off the |
782 | debug mode using the "-no_debug" option solves the |
783 | problem, eg.: |
784 | |
785 | [% USE CGI('-no_debug') %] |
786 | |
8077080c |
787 | =head1 SEE ALSO |
788 | |
8cd017a8 |
789 | L<Catalyst>, L<Catalyst::Helper::View::TT>, |
790 | L<Catalyst::Helper::View::TTSite>, L<Template::Manual> |
8077080c |
791 | |
c0eb0527 |
792 | =head1 AUTHORS |
8077080c |
793 | |
794 | Sebastian Riedel, C<sri@cpan.org> |
c0eb0527 |
795 | |
d938377b |
796 | Marcus Ramberg, C<mramberg@cpan.org> |
c0eb0527 |
797 | |
722fede4 |
798 | Jesse Sheidlower, C<jester@panix.com> |
c0eb0527 |
799 | |
8cd017a8 |
800 | Andy Wardley, C<abw@cpan.org> |
8077080c |
801 | |
0696d072 |
802 | Luke Saunders, C<luke.saunders@gmail.com> |
803 | |
8077080c |
804 | =head1 COPYRIGHT |
805 | |
f5b61ad7 |
806 | This program is free software. You can redistribute it and/or modify it |
2774dc77 |
807 | under the same terms as Perl itself. |
8077080c |
808 | |
809 | =cut |