Added default extension configuration option.
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
1 package Catalyst::View::TT;
2
3 use strict;
4 use base qw/Catalyst::Base/;
5 use Template;
6 use Template::Timer;
7 use NEXT;
8
9 our $VERSION = '0.14';
10
11 __PACKAGE__->mk_accessors('template');
12
13 =head1 NAME
14
15 Catalyst::View::TT - Template View Class
16
17 =head1 SYNOPSIS
18
19 # use the helper to create View
20     myapp_create.pl view TT TT
21
22 # configure in lib/MyApp.pm
23
24     our $ROOT = '/home/dent/catalyst/MyApp';
25
26     MyApp->config({
27         name     => 'MyApp',
28         root     => $ROOT,
29         'V::TT' => {
30             # any TT configurations items go here
31             INCLUDE_PATH => [
32               "$ROOT/templates/src", 
33               "$ROOT/templates/lib"
34             ],
35             PRE_PROCESS => 'config/main',
36             WRAPPER     => 'site/wrapper',
37
38             # two optional config items
39             CATALYST_VAR => 'Catalyst',
40             TIMER        => 1,
41         },
42     });
43          
44 # render view from lib/MyApp.pm or lib/MyApp::C::SomeController.pm
45     
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');
51     }
52
53 # access variables from template
54
55     The message is: [% message %].
56     
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 %] 
61     
62     # example when CATALYST_VAR isn't set
63     Context is [% c %]
64     The base is [% base %]
65     The name is [% name %]
66
67 =head1 DESCRIPTION
68
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.
75
76     $ script/myapp_create.pl view TT TT
77
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
80 something like this:
81
82     package FooBar::V::TT;
83     
84     use strict;
85      use base 'Catalyst::View::TT';
86
87     __PACKAGE__->config->{DEBUG} = 'all';
88
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
92 to the TT view class.
93
94     # In MyApp or MyApp::Controller::SomeController
95     
96     sub end : Private {
97         my( $self, $c ) = @_;
98         $c->forward('MyApp::V::TT');
99     }
100
101 =head2 CONFIGURATION
102
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.
106
107     package MyApp::V::TT;
108     
109     use strict;
110     use base 'Catalyst::View::TT';
111
112     our $ROOT = '/home/dent/catalyst/MyApp';
113     
114     MyApp::V::TT->config({
115         INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
116         PRE_PROCESS  => 'config/main',
117         WRAPPER      => 'site/wrapper',
118     });
119
120 The second way is to define a C<new()> method in your view subclass.
121 This performs the configuration when the view object is created,
122 shortly after being loaded.  Remember to delegate to the base class
123 C<new()> method (via C<$self-E<gt>NEXT::new()> in the example below) after
124 performing any configuration.
125
126     sub new {
127         my $self = shift;
128         $self->config({
129             INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
130             PRE_PROCESS  => 'config/main',
131             WRAPPER      => 'site/wrapper',
132         });
133         return $self->NEXT::new(@_);
134     }
135  
136 The final, and perhaps most direct way, is to define a class
137 item in your main application configuration, again by calling the
138 uniquitous C<config()> method.  The items in the class hash are
139 added to those already defined by the above two methods.  This happens
140 in the base class new() method (which is one reason why you must
141 remember to call it via C<NEXT> if you redefine the C<new()> method in a
142 subclass).
143
144     package MyApp;
145     
146     use strict;
147     use Catalyst;
148     
149     our $ROOT = '/home/dent/catalyst/MyApp';
150     
151     MyApp->config({
152         name     => 'MyApp',
153         root     => $ROOT,
154         'V::TT' => {
155             INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"],
156             PRE_PROCESS  => 'config/main',
157             WRAPPER      => 'site/wrapper',
158         },
159     });
160
161 Note that any configuration items defined by one of the earlier
162 methods will be overwritten by items of the same name provided by the
163 latter methods.  
164
165 =head2 RENDERING VIEWS
166
167 The view plugin renders the template specified in the C<template>
168 item in the stash.  
169
170     sub message : Global {
171         my ( $self, $c ) = @_;
172         $c->stash->{template} = 'message.tt2';
173         $c->forward('MyApp::V::TT');
174     }
175
176 If a class item isn't defined, then it instead uses the
177 current match, as returned by C<$c-E<gt>match>.  In the above 
178 example, this would be C<message>.
179
180 The items defined in the stash are passed to the Template Toolkit for
181 use as template variables.
182
183 sub message : Global {
184     sub default : Private {
185         my ( $self, $c ) = @_;
186         $c->stash->{template} = 'message.tt2';
187         $c->stash->{message}  = 'Hello World!';
188         $c->forward('MyApp::V::TT');
189     }
190
191 A number of other template variables are also added:
192
193     c      A reference to the context object, $c
194     base   The URL base, from $c->req->base()
195     name   The application name, from $c->config->{ name }
196
197 These can be accessed from the template in the usual way:
198
199 <message.tt2>:
200
201     The message is: [% message %]
202     The base is [% base %]
203     The name is [% name %]
204
205
206 The output generated by the template is stored in
207 C<$c-E<gt>response-E<gt>output>.
208
209 =head2 TEMPLATE PROFILING
210
211 =head2 METHODS
212
213 =over 4
214
215 =item new
216
217 The constructor for the TT view. Sets up the template provider, 
218 and reads the application config.
219
220 =cut
221
222 sub new {
223     my ( $class, $c, $arguments ) = @_;
224
225     my $root = $c->config->{root};
226
227     my $config = {
228         EVAL_PERL    => 0,
229         TEMPLATE_EXTENSION => '',
230         INCLUDE_PATH => [ $root, "$root/base" ],
231         %{ $class->config },
232         %{$arguments}
233     };
234
235     # if we're debugging and/or the TIMER option is set, then we install
236     # Template::Timer as a custom CONTEXT object, but only if we haven't
237     # already got a custom CONTEXT defined
238
239     if ( $config->{TIMER} ) {
240         if ( $config->{CONTEXT} ) {
241             $c->log->error(
242                 'Cannot use Template::Timer - a TT CONFIG is already defined');
243         }
244         else {
245             $config->{CONTEXT} = Template::Timer->new(%$config);
246         }
247     }
248
249     if ( $c->debug && $config->{DUMP_CONFIG} ) {
250         use Data::Dumper;
251         $c->log->debug( "TT Config: ", Dumper($config) );
252     }
253
254     return $class->NEXT::new(
255         $c,
256         {
257             template => Template->new($config) || do {
258                 my $error = Template->error();
259                 $c->log->error($error);
260                 $c->error($error);
261                 return undef;
262               }
263         }
264     );
265 }
266
267 =item process
268
269 Renders the template specified in C<$c-E<gt>stash-E<gt>{template}> or
270 C<$c-E<gt>request-E<gt>match>. Template variables are set up from the
271 contents of C<$c-E<gt>stash>, augmented with C<base> set to
272 C<$c-E<gt>req-E<gt>base>, C<c> to C<$c> and C<name> to
273 C<$c-E<gt>config-E<gt>{name}>. Alternately, the C<CATALYST_VAR>
274 configuration item can be defined to specify the name of a template
275 variable through which the context reference (C<$c>) can be accessed.
276 In this case, the C<c>, C<base> and C<name> variables are omitted.
277 Output is stored in C<$c-E<gt>response-E<gt>output>.
278
279 =cut
280
281 sub process {
282     my ( $self, $c ) = @_;
283
284     my $template = $c->stash->{template} || $c->request->match . $self->config->{TEMPLATE_EXTENSION};
285
286     unless ($template) {
287         $c->log->debug('No template specified for rendering') if $c->debug;
288         return 0;
289     }
290
291     $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
292
293     my $output;
294     my $cvar = $self->config->{CATALYST_VAR};
295     my $vars = {
296         defined $cvar
297         ? ( $cvar => $c )
298         : (
299             c    => $c,
300             base => $c->req->base,
301             name => $c->config->{name}
302         ),
303         %{ $c->stash() }
304     };
305
306     unless ( $self->template->process( $template, $vars, \$output ) ) {
307         my $error = $self->template->error;
308         $error = qq/Couldn't render template "$error"/;
309         $c->log->error($error);
310         $c->error($error);
311         return 0;
312     }
313
314     unless ( $c->response->content_type ) {
315         $c->response->content_type('text/html; charset=utf-8');
316     }
317
318     $c->response->body($output);
319
320     return 1;
321 }
322
323 =item config
324
325 This method allows your view subclass to pass additional settings to
326 the TT configuration hash, or to set the options as below:
327
328 =over 2
329
330 =item C<CATALYST_VAR> 
331
332 Allows you to change the name of the Catalyst context object. If set, it will also
333 remove the base and name aliases, so you will have access them through <context>.
334
335 For example:
336
337     MyApp->config({
338         name     => 'MyApp',
339         root     => $ROOT,
340         'V::TT' => {
341             CATALYST_VAR => 'Catalyst',
342         },
343     });
344
345 F<message.tt2>:
346
347     The base is [% Catalyst.req.base %]
348     The name is [% Catalyst.config.name %]
349
350 =item C<TIMER>
351
352 If you have configured Catalyst for debug output, and turned on the TIMER setting,
353 C<Catalyst::View::TT> will enable profiling of template processing
354 (using L<Template::Timer>). This will embed HTML comments in the
355 output from your templates, such as:
356
357     <!-- TIMER START: process mainmenu/mainmenu.ttml -->
358     <!-- TIMER START: include mainmenu/cssindex.tt -->
359     <!-- TIMER START: process mainmenu/cssindex.tt -->
360     <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
361     <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
362
363     ....
364
365     <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
366
367
368 =item C<TEMPLATE_EXTENSION>
369
370 an extension to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
371
372 For example:
373
374   package MyApp::C::Test;
375   sub test : Local { .. } 
376
377 Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
378 <root>/test/test.tt.
379
380 =back
381
382 =back
383
384 =head2 HELPERS
385
386 The L<Catalyst::Helper::View::TT> and
387 L<Catalyst::Helper::View::TTSite> helper modules are provided to create
388 your view module.  There are invoked by the F<myapp_create.pl> script:
389
390     $ script/myapp_create.pl view TT TT
391
392     $ script/myapp_create.pl view TT TTSite
393
394 The L<Catalyst::Helper::View::TT> module creates a basic TT view
395 module.  The L<Catalyst::Helper::View::TTSite> module goes a little
396 further.  It also creates a default set of templates to get you
397 started.  It also configures the view module to locate the templates
398 automatically.
399
400 =head1 SEE ALSO
401
402 L<Catalyst>, L<Catalyst::Helper::View::TT>,
403 L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
404
405 =head1 AUTHORS
406
407 Sebastian Riedel, C<sri@cpan.org>
408
409 Marcus Ramberg, C<mramberg@cpan.org>
410
411 Jesse Sheidlower, C<jester@panix.com>
412
413 Andy Wardley, C<abw@cpan.org>
414
415 =head1 COPYRIGHT
416
417 This program is free software, you can redistribute it and/or modify it 
418 under the same terms as Perl itself.
419
420 =cut
421
422 1;