released 0.19
[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.19';
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_EXTENSION => '.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     my $self = $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         %{$config},
268         },
269     );
270     $self->config($config);
271
272     return $self;
273 }
274
275 =item process
276
277 Renders the template specified in C<$c-E<gt>stash-E<gt>{template}> or
278 C<$c-E<gt>request-E<gt>match>. Template variables are set up from the
279 contents of C<$c-E<gt>stash>, augmented with C<base> set to
280 C<$c-E<gt>req-E<gt>base>, C<c> to C<$c> and C<name> to
281 C<$c-E<gt>config-E<gt>{name}>. Alternately, the C<CATALYST_VAR>
282 configuration item can be defined to specify the name of a template
283 variable through which the context reference (C<$c>) can be accessed.
284 In this case, the C<c>, C<base> and C<name> variables are omitted.
285 Output is stored in C<$c-E<gt>response-E<gt>output>.
286
287 =cut
288
289 sub process {
290     my ( $self, $c ) = @_;
291
292     my $template = $c->stash->{template}
293       || $c->request->match . $self->config->{TEMPLATE_EXTENSION};
294
295     unless ($template) {
296         $c->log->debug('No template specified for rendering') if $c->debug;
297         return 0;
298     }
299
300     $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
301
302     my $output;
303     my $cvar = $self->config->{CATALYST_VAR};
304     my $vars = {
305         defined $cvar
306         ? ( $cvar => $c )
307         : (
308             c    => $c,
309             base => $c->req->base,
310             name => $c->config->{name}
311         ),
312         %{ $c->stash() }
313     };
314
315     unless ( $self->template->process( $template, $vars, \$output ) ) {
316         my $error = $self->template->error;
317         $error = qq/Couldn't render template "$error"/;
318         $c->log->error($error);
319         $c->error($error);
320         return 0;
321     }
322
323     unless ( $c->response->content_type ) {
324         $c->response->content_type('text/html; charset=utf-8');
325     }
326
327     $c->response->body($output);
328
329     return 1;
330 }
331
332 =item config
333
334 This method allows your view subclass to pass additional settings to
335 the TT configuration hash, or to set the options as below:
336
337 =over 2
338
339 =item C<CATALYST_VAR> 
340
341 Allows you to change the name of the Catalyst context object. If set, it will also
342 remove the base and name aliases, so you will have access them through <context>.
343
344 For example:
345
346     MyApp->config({
347         name     => 'MyApp',
348         root     => MyApp->path_to('root'),
349         'V::TT' => {
350             CATALYST_VAR => 'Catalyst',
351         },
352     });
353
354 F<message.tt2>:
355
356     The base is [% Catalyst.req.base %]
357     The name is [% Catalyst.config.name %]
358
359 =item C<TIMER>
360
361 If you have configured Catalyst for debug output, and turned on the TIMER setting,
362 C<Catalyst::View::TT> will enable profiling of template processing
363 (using L<Template::Timer>). This will embed HTML comments in the
364 output from your templates, such as:
365
366     <!-- TIMER START: process mainmenu/mainmenu.ttml -->
367     <!-- TIMER START: include mainmenu/cssindex.tt -->
368     <!-- TIMER START: process mainmenu/cssindex.tt -->
369     <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
370     <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
371
372     ....
373
374     <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
375
376
377 =item C<TEMPLATE_EXTENSION>
378
379 a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
380
381 For example:
382
383   package MyApp::C::Test;
384   sub test : Local { .. } 
385
386 Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
387 <root>/test/test.tt.
388
389 =back
390
391 =back
392
393 =head2 HELPERS
394
395 The L<Catalyst::Helper::View::TT> and
396 L<Catalyst::Helper::View::TTSite> helper modules are provided to create
397 your view module.  There are invoked by the F<myapp_create.pl> script:
398
399     $ script/myapp_create.pl view TT TT
400
401     $ script/myapp_create.pl view TT TTSite
402
403 The L<Catalyst::Helper::View::TT> module creates a basic TT view
404 module.  The L<Catalyst::Helper::View::TTSite> module goes a little
405 further.  It also creates a default set of templates to get you
406 started.  It also configures the view module to locate the templates
407 automatically.
408
409 =head1 SEE ALSO
410
411 L<Catalyst>, L<Catalyst::Helper::View::TT>,
412 L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
413
414 =head1 AUTHORS
415
416 Sebastian Riedel, C<sri@cpan.org>
417
418 Marcus Ramberg, C<mramberg@cpan.org>
419
420 Jesse Sheidlower, C<jester@panix.com>
421
422 Andy Wardley, C<abw@cpan.org>
423
424 =head1 COPYRIGHT
425
426 This program is free software, you can redistribute it and/or modify it 
427 under the same terms as Perl itself.
428
429 =cut
430
431 1;