View::TT, added tests from dwc
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
CommitLineData
8077080c 1package Catalyst::View::TT;
2
3use strict;
7d8aa5ec 4use base qw/Catalyst::View/;
8077080c 5use Template;
6use Template::Timer;
7use NEXT;
8
07571b2f 9our $VERSION = '0.20';
8077080c 10
11__PACKAGE__->mk_accessors('template');
8077080c 12
13=head1 NAME
14
15Catalyst::View::TT - Template View Class
16
17=head1 SYNOPSIS
18
8cd017a8 19# use the helper to create View
722fede4 20 myapp_create.pl view TT TT
8077080c 21
8cd017a8 22# configure in lib/MyApp.pm
23
8cd017a8 24 MyApp->config({
25 name => 'MyApp',
7d8aa5ec 26 root => MyApp->path_to('root');,
7d607671 27 'V::TT' => {
8cd017a8 28 # any TT configurations items go here
29 INCLUDE_PATH => [
93f25382 30 MyApp->path_to( 'root', 'src' ),
31 MyApp->path_to( 'root', 'lib' ),
8cd017a8 32 ],
07571b2f 33 PRE_PROCESS => 'config/main',
34 WRAPPER => 'site/wrapper',
35 TEMPLATE_EXTENSION => '.tt',
8cd017a8 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 {
94b3529a 46 my ( $self, $c ) = @_;
47 $c->stash->{template} = 'message.tt2';
48 $c->stash->{message} = 'Hello World!';
8cd017a8 49 $c->forward('MyApp::V::TT');
50 }
8077080c 51
8cd017a8 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
68This is the Catalyst view class for the L<Template Toolkit|Template>.
69Your application should defined a view class which is a subclass of
70this module. The easiest way to achieve this is using the
71F<myapp_create.pl> script (where F<myapp> should be replaced with
72whatever your application is called). This script is created as part
73of the Catalyst setup.
74
75 $ script/myapp_create.pl view TT TT
76
77This creates a MyApp::V::TT.pm module in the F<lib> directory (again,
78replacing C<MyApp> with the name of your application) which looks
79something like this:
80
81 package FooBar::V::TT;
82
83 use strict;
84 use base 'Catalyst::View::TT';
8077080c 85
86 __PACKAGE__->config->{DEBUG} = 'all';
87
8cd017a8 88Now you can modify your action handlers in the main application and/or
89controllers to forward to your view class. You might choose to do this
90in the end() method, for example, to automatically forward all actions
91to the TT view class.
722fede4 92
8cd017a8 93 # In MyApp or MyApp::Controller::SomeController
8077080c 94
8cd017a8 95 sub end : Private {
94b3529a 96 my( $self, $c ) = @_;
8cd017a8 97 $c->forward('MyApp::V::TT');
98 }
8077080c 99
8cd017a8 100=head2 CONFIGURATION
4687ac0d 101
8cd017a8 102There are a three different ways to configure your view class. The
103first way is to call the C<config()> method in the view subclass. This
104happens when the module is first loaded.
8077080c 105
8cd017a8 106 package MyApp::V::TT;
107
108 use strict;
109 use base 'Catalyst::View::TT';
722fede4 110
8cd017a8 111 MyApp::V::TT->config({
7d8aa5ec 112 INCLUDE_PATH => [
113 MyApp->path_to( 'root', 'templates', 'lib' ),
114 MyApp->path_to( 'root', 'templates', 'src' ),
115 ],
8cd017a8 116 PRE_PROCESS => 'config/main',
117 WRAPPER => 'site/wrapper',
118 });
119
120The second way is to define a C<new()> method in your view subclass.
121This performs the configuration when the view object is created,
122shortly after being loaded. Remember to delegate to the base class
123C<new()> method (via C<$self-E<gt>NEXT::new()> in the example below) after
124performing any configuration.
125
126 sub new {
127 my $self = shift;
128 $self->config({
7d8aa5ec 129 INCLUDE_PATH => [
130 MyApp->path_to( 'root', 'templates', 'lib' ),
131 MyApp->path_to( 'root', 'templates', 'src' ),
132 ],
8cd017a8 133 PRE_PROCESS => 'config/main',
134 WRAPPER => 'site/wrapper',
135 });
136 return $self->NEXT::new(@_);
137 }
138
94b3529a 139The final, and perhaps most direct way, is to define a class
8cd017a8 140item in your main application configuration, again by calling the
94b3529a 141uniquitous C<config()> method. The items in the class hash are
8cd017a8 142added to those already defined by the above two methods. This happens
143in the base class new() method (which is one reason why you must
144remember to call it via C<NEXT> if you redefine the C<new()> method in a
145subclass).
146
147 package MyApp;
148
149 use strict;
150 use Catalyst;
151
8cd017a8 152 MyApp->config({
153 name => 'MyApp',
7d8aa5ec 154 root => MyApp->path_to('root'),
7d607671 155 'V::TT' => {
7d8aa5ec 156 INCLUDE_PATH => [
157 MyApp->path_to( 'root', 'templates', 'lib' ),
158 MyApp->path_to( 'root', 'templates', 'src' ),
159 ],
8cd017a8 160 PRE_PROCESS => 'config/main',
161 WRAPPER => 'site/wrapper',
162 },
163 });
164
165Note that any configuration items defined by one of the earlier
166methods will be overwritten by items of the same name provided by the
167latter methods.
168
169=head2 RENDERING VIEWS
170
171The view plugin renders the template specified in the C<template>
172item in the stash.
173
174 sub message : Global {
94b3529a 175 my ( $self, $c ) = @_;
176 $c->stash->{template} = 'message.tt2';
8cd017a8 177 $c->forward('MyApp::V::TT');
178 }
722fede4 179
94b3529a 180If a class item isn't defined, then it instead uses the
8cd017a8 181current match, as returned by C<$c-E<gt>match>. In the above
182example, this would be C<message>.
183
184The items defined in the stash are passed to the Template Toolkit for
185use as template variables.
186
187sub message : Global {
188 sub default : Private {
94b3529a 189 my ( $self, $c ) = @_;
190 $c->stash->{template} = 'message.tt2';
191 $c->stash->{message} = 'Hello World!';
8cd017a8 192 $c->forward('MyApp::V::TT');
193 }
7b592fc7 194
8cd017a8 195A number of other template variables are also added:
8077080c 196
8cd017a8 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
201These 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
8cd017a8 209
210The output generated by the template is stored in
211C<$c-E<gt>response-E<gt>output>.
212
213=head2 TEMPLATE PROFILING
214
caa61517 215=head2 METHODS
8077080c 216
2774dc77 217=over 4
218
219=item new
220
221The constructor for the TT view. Sets up the template provider,
222and reads the application config.
223
8077080c 224=cut
225
226sub new {
9300af5b 227 my ( $class, $c, $arguments ) = @_;
228
229 my $root = $c->config->{root};
230
94b3529a 231 my $config = {
7d8aa5ec 232 EVAL_PERL => 0,
4729c102 233 TEMPLATE_EXTENSION => '',
7d8aa5ec 234 INCLUDE_PATH => [ $root, "$root/base" ],
9300af5b 235 %{ $class->config },
8cd017a8 236 %{$arguments}
94b3529a 237 };
62728755 238
8cd017a8 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
dccfa0ff 243 if ( $config->{TIMER} ) {
94b3529a 244 if ( $config->{CONTEXT} ) {
8cd017a8 245 $c->log->error(
246 'Cannot use Template::Timer - a TT CONFIG is already defined');
247 }
248 else {
94b3529a 249 $config->{CONTEXT} = Template::Timer->new(%$config);
8cd017a8 250 }
251 }
252
94b3529a 253 if ( $c->debug && $config->{DUMP_CONFIG} ) {
8cd017a8 254 use Data::Dumper;
94b3529a 255 $c->log->debug( "TT Config: ", Dumper($config) );
62728755 256 }
257
e3a53d5b 258 my $self = $class->NEXT::new(
8cd017a8 259 $c,
260 {
94b3529a 261 template => Template->new($config) || do {
8cd017a8 262 my $error = Template->error();
263 $c->log->error($error);
264 $c->error($error);
265 return undef;
48d69085 266 },
be7c1afa 267 %{$config},
48d69085 268 },
8cd017a8 269 );
e3a53d5b 270 $self->config($config);
271
272 return $self;
8077080c 273}
274
2774dc77 275=item process
8077080c 276
722fede4 277Renders the template specified in C<$c-E<gt>stash-E<gt>{template}> or
278C<$c-E<gt>request-E<gt>match>. Template variables are set up from the
279contents of C<$c-E<gt>stash>, augmented with C<base> set to
280C<$c-E<gt>req-E<gt>base>, C<c> to C<$c> and C<name> to
8cd017a8 281C<$c-E<gt>config-E<gt>{name}>. Alternately, the C<CATALYST_VAR>
282configuration item can be defined to specify the name of a template
283variable through which the context reference (C<$c>) can be accessed.
284In this case, the C<c>, C<base> and C<name> variables are omitted.
285Output is stored in C<$c-E<gt>response-E<gt>output>.
8077080c 286
287=cut
288
289sub process {
290 my ( $self, $c ) = @_;
23042c3c 291
7d8aa5ec 292 my $template = $c->stash->{template}
293 || $c->request->match . $self->config->{TEMPLATE_EXTENSION};
23042c3c 294
295 unless ($template) {
8077080c 296 $c->log->debug('No template specified for rendering') if $c->debug;
297 return 0;
298 }
23042c3c 299
300 $c->log->debug(qq/Rendering template "$template"/) if $c->debug;
23042c3c 301
8cd017a8 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 ) ) {
8077080c 316 my $error = $self->template->error;
317 $error = qq/Couldn't render template "$error"/;
318 $c->log->error($error);
becb7ac2 319 $c->error($error);
23042c3c 320 return 0;
321 }
8cd017a8 322
23042c3c 323 unless ( $c->response->content_type ) {
324 $c->response->content_type('text/html; charset=utf-8');
8077080c 325 }
23042c3c 326
327 $c->response->body($output);
328
8077080c 329 return 1;
330}
331
2774dc77 332=item config
8077080c 333
8cd017a8 334This method allows your view subclass to pass additional settings to
4729c102 335the TT configuration hash, or to set the options as below:
336
337=over 2
338
339=item C<CATALYST_VAR>
340
341Allows you to change the name of the Catalyst context object. If set, it will also
342remove the base and name aliases, so you will have access them through <context>.
343
344For example:
345
346 MyApp->config({
347 name => 'MyApp',
7d8aa5ec 348 root => MyApp->path_to('root'),
4729c102 349 'V::TT' => {
350 CATALYST_VAR => 'Catalyst',
351 },
352 });
353
354F<message.tt2>:
355
356 The base is [% Catalyst.req.base %]
357 The name is [% Catalyst.config.name %]
358
359=item C<TIMER>
360
361If you have configured Catalyst for debug output, and turned on the TIMER setting,
362C<Catalyst::View::TT> will enable profiling of template processing
363(using L<Template::Timer>). This will embed HTML comments in the
364output 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
be7c1afa 377=item C<TEMPLATE_EXTENSION>
4729c102 378
747f2b6d 379a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
4729c102 380
381For example:
382
383 package MyApp::C::Test;
384 sub test : Local { .. }
385
386Would 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
8077080c 390
2774dc77 391=back
8077080c 392
8cd017a8 393=head2 HELPERS
394
395The L<Catalyst::Helper::View::TT> and
396L<Catalyst::Helper::View::TTSite> helper modules are provided to create
397your 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
403The L<Catalyst::Helper::View::TT> module creates a basic TT view
404module. The L<Catalyst::Helper::View::TTSite> module goes a little
405further. It also creates a default set of templates to get you
406started. It also configures the view module to locate the templates
407automatically.
408
8077080c 409=head1 SEE ALSO
410
8cd017a8 411L<Catalyst>, L<Catalyst::Helper::View::TT>,
412L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
8077080c 413
c0eb0527 414=head1 AUTHORS
8077080c 415
416Sebastian Riedel, C<sri@cpan.org>
c0eb0527 417
d938377b 418Marcus Ramberg, C<mramberg@cpan.org>
c0eb0527 419
722fede4 420Jesse Sheidlower, C<jester@panix.com>
c0eb0527 421
8cd017a8 422Andy Wardley, C<abw@cpan.org>
8077080c 423
424=head1 COPYRIGHT
425
2774dc77 426This program is free software, you can redistribute it and/or modify it
427under the same terms as Perl itself.
8077080c 428
429=cut
430
4311;