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