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