r11755@t0mlaptop (orig r11720): theory | 2009-11-03 00:23:43 +0000
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
CommitLineData
8077080c 1package Catalyst::View::TT;
2
3use strict;
6229ce0d 4use warnings;
5
7d8aa5ec 6use base qw/Catalyst::View/;
9e739e1e 7use Data::Dump 'dump';
8077080c 8use Template;
9use Template::Timer;
e8693f1b 10use MRO::Compat;
8077080c 11
bd45975e 12our $VERSION = '0.33';
8077080c 13
14__PACKAGE__->mk_accessors('template');
e2bbd784 15__PACKAGE__->mk_accessors('include_path');
8077080c 16
9d574573 17*paths = \&include_path;
18
8077080c 19=head1 NAME
20
21Catalyst::View::TT - Template View Class
22
23=head1 SYNOPSIS
24
bd4ee63a 25# use the helper to create your View
ad50568f 26
722fede4 27 myapp_create.pl view TT TT
8077080c 28
6175bba7 29# configure in lib/MyApp.pm (Could be set from configfile instead)
8cd017a8 30
ae035767 31 MyApp->config(
8cd017a8 32 name => 'MyApp',
e1c15a53 33 root => MyApp->path_to('root'),
ae035767 34 'View::TT' => {
8cd017a8 35 # any TT configurations items go here
36 INCLUDE_PATH => [
f5b61ad7 37 MyApp->path_to( 'root', 'src' ),
38 MyApp->path_to( 'root', 'lib' ),
8cd017a8 39 ],
6175bba7 40 TEMPLATE_EXTENSION => '.tt',
41 CATALYST_VAR => 'c',
42 TIMER => 0,
43 # Not set by default
07571b2f 44 PRE_PROCESS => 'config/main',
45 WRAPPER => 'site/wrapper',
3715305f 46 render_die => 1, # Default for new apps, see render method docs
8cd017a8 47 },
ae035767 48 );
f5b61ad7 49
6229ce0d 50# render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm
f5b61ad7 51
8cd017a8 52 sub message : Global {
94b3529a 53 my ( $self, $c ) = @_;
54 $c->stash->{template} = 'message.tt2';
55 $c->stash->{message} = 'Hello World!';
c18eae32 56 $c->forward( $c->view('TT') );
8cd017a8 57 }
8077080c 58
8cd017a8 59# access variables from template
60
61 The message is: [% message %].
f5b61ad7 62
8cd017a8 63 # example when CATALYST_VAR is set to 'Catalyst'
f5b61ad7 64 Context is [% Catalyst %]
65 The base is [% Catalyst.req.base %]
66 The name is [% Catalyst.config.name %]
67
8cd017a8 68 # example when CATALYST_VAR isn't set
69 Context is [% c %]
70 The base is [% base %]
71 The name is [% name %]
72
bd4ee63a 73=cut
74
75sub _coerce_paths {
76 my ( $paths, $dlim ) = shift;
77 return () if ( !$paths );
78 return @{$paths} if ( ref $paths eq 'ARRAY' );
79
80 # tweak delim to ignore C:/
81 unless ( defined $dlim ) {
82 $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
83 }
84 return split( /$dlim/, $paths );
85}
86
87sub new {
88 my ( $class, $c, $arguments ) = @_;
89 my $config = {
90 EVAL_PERL => 0,
91 TEMPLATE_EXTENSION => '',
92 %{ $class->config },
93 %{$arguments},
94 };
95 if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
96 my $delim = $config->{DELIMITER};
97 my @include_path
98 = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
99 if ( !@include_path ) {
100 my $root = $c->config->{root};
101 my $base = Path::Class::dir( $root, 'base' );
102 @include_path = ( "$root", "$base" );
103 }
104 $config->{INCLUDE_PATH} = \@include_path;
105 }
106
107 # if we're debugging and/or the TIMER option is set, then we install
108 # Template::Timer as a custom CONTEXT object, but only if we haven't
109 # already got a custom CONTEXT defined
110
111 if ( $config->{TIMER} ) {
112 if ( $config->{CONTEXT} ) {
113 $c->log->error(
114 'Cannot use Template::Timer - a TT CONTEXT is already defined'
115 );
116 }
117 else {
118 $config->{CONTEXT} = Template::Timer->new(%$config);
119 }
120 }
121
122 if ( $c->debug && $config->{DUMP_CONFIG} ) {
9e739e1e 123 $c->log->debug( "TT Config: ", dump($config) );
bd4ee63a 124 }
6175bba7 125
e8693f1b 126 my $self = $class->next::method(
f5b61ad7 127 $c, { %$config },
6175bba7 128 );
129
130 # Set base include paths. Local'd in render if needed
131 $self->include_path($config->{INCLUDE_PATH});
f5b61ad7 132
6175bba7 133 $self->config($config);
134
135 # Creation of template outside of call to new so that we can pass [ $self ]
136 # as INCLUDE_PATH config item, which then gets ->paths() called to get list
137 # of include paths to search for templates.
f5b61ad7 138
6175bba7 139 # Use a weakend copy of self so we dont have loops preventing GC from working
140 my $copy = $self;
141 Scalar::Util::weaken($copy);
142 $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
143
bd4ee63a 144 if ( $config->{PROVIDERS} ) {
145 my @providers = ();
146 if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
147 foreach my $p (@{$config->{PROVIDERS}}) {
148 my $pname = $p->{name};
149 my $prov = 'Template::Provider';
150 if($pname eq '_file_')
151 {
152 $p->{args} = { %$config };
153 }
154 else
155 {
51199593 156 if($pname =~ s/^\+//) {
157 $prov = $pname;
158 }
159 else
160 {
161 $prov .= "::$pname";
162 }
6175bba7 163 # We copy the args people want from the config
164 # to the args
165 $p->{args} ||= {};
166 if ($p->{copy_config}) {
167 map { $p->{args}->{$_} = $config->{$_} }
168 grep { exists $config->{$_} }
169 @{ $p->{copy_config} };
170 }
bd4ee63a 171 }
fc0ffed0 172 local $@;
bd4ee63a 173 eval "require $prov";
174 if(!$@) {
175 push @providers, "$prov"->new($p->{args});
176 }
177 else
178 {
179 $c->log->warn("Can't load $prov, ($@)");
180 }
181 }
182 }
183 delete $config->{PROVIDERS};
184 if(@providers) {
185 $config->{LOAD_TEMPLATES} = \@providers;
186 }
187 }
f5b61ad7 188
189 $self->{template} =
bd4ee63a 190 Template->new($config) || do {
191 my $error = Template->error();
192 $c->log->error($error);
193 $c->error($error);
194 return undef;
195 };
196
197
198 return $self;
199}
200
201sub process {
202 my ( $self, $c ) = @_;
203
204 my $template = $c->stash->{template}
205 || $c->action . $self->config->{TEMPLATE_EXTENSION};
206
207 unless (defined $template) {
208 $c->log->debug('No template specified for rendering') if $c->debug;
209 return 0;
210 }
211
fc0ffed0 212 local $@;
cad820fe 213 my $output = eval { $self->render($c, $template) };
214 if (my $err = $@) {
215 my $error = qq/Couldn't render template "$template"/;
bd4ee63a 216 $c->log->error($error);
217 $c->error($error);
218 return 0;
219 }
220
221 unless ( $c->response->content_type ) {
222 $c->response->content_type('text/html; charset=utf-8');
223 }
224
225 $c->response->body($output);
226
227 return 1;
228}
229
230sub render {
231 my ($self, $c, $template, $args) = @_;
232
cbb149dc 233 $c->log->debug(qq/Rendering template "$template"/) if $c && $c->debug;
bd4ee63a 234
235 my $output;
f5b61ad7 236 my $vars = {
bd4ee63a 237 (ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
238 $self->template_vars($c)
239 };
240
f5b61ad7 241 local $self->{include_path} =
bd4ee63a 242 [ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ]
243 if ref $vars->{additional_template_paths};
244
596ff245 245 unless ( $self->template->process( $template, $vars, \$output ) ) {
246 if (exists $self->{render_die}) {
247 die $self->template->error if $self->{render_die};
248 return $self->template->error;
249 }
250 require Carp;
251 Carp::carp('The Catalyst::View::TT render() method of will die on error in a future release. If you want it to continue to return the exception instead, pass render_die => 0 to the constructor');
252 return $self->template->error;
253 }
cad820fe 254 return $output;
bd4ee63a 255}
256
257sub template_vars {
258 my ( $self, $c ) = @_;
259
cbb149dc 260 return () unless $c;
bd4ee63a 261 my $cvar = $self->config->{CATALYST_VAR};
262
263 defined $cvar
264 ? ( $cvar => $c )
265 : (
266 c => $c,
267 base => $c->req->base,
268 name => $c->config->{name}
269 )
270}
271
272
2731;
274
275__END__
276
8cd017a8 277=head1 DESCRIPTION
278
279This is the Catalyst view class for the L<Template Toolkit|Template>.
280Your application should defined a view class which is a subclass of
281this module. The easiest way to achieve this is using the
282F<myapp_create.pl> script (where F<myapp> should be replaced with
283whatever your application is called). This script is created as part
284of the Catalyst setup.
285
286 $ script/myapp_create.pl view TT TT
287
6229ce0d 288This creates a MyApp::View::TT.pm module in the F<lib> directory (again,
8cd017a8 289replacing C<MyApp> with the name of your application) which looks
290something like this:
291
6229ce0d 292 package FooBar::View::TT;
f5b61ad7 293
8cd017a8 294 use strict;
c18eae32 295 use warnings;
f5b61ad7 296
c18eae32 297 use base 'Catalyst::View::TT';
8077080c 298
a1b7968f 299 __PACKAGE__->config(DEBUG => 'all');
8077080c 300
8cd017a8 301Now you can modify your action handlers in the main application and/or
302controllers to forward to your view class. You might choose to do this
303in the end() method, for example, to automatically forward all actions
304to the TT view class.
722fede4 305
8cd017a8 306 # In MyApp or MyApp::Controller::SomeController
f5b61ad7 307
8cd017a8 308 sub end : Private {
94b3529a 309 my( $self, $c ) = @_;
c18eae32 310 $c->forward( $c->view('TT') );
8cd017a8 311 }
8077080c 312
2844488f 313But if you are using the standard auto-generated end action, you don't even need
314to do this!
315
316 # in MyApp::Controller::Root
317 sub end : ActionClass('RenderView') {} # no need to change this line
318
319 # in MyApp.pm
320 __PACKAGE__->config(
321 ...
322 default_view => 'TT',
323 );
324
325This will Just Work. And it has the advantages that:
326
327=over 4
328
329=item *
330
331If you want to use a different view for a given request, just set
332<< $c->stash->{current_view} >>. (See L<Catalyst>'s C<< $c->view >> method
333for details.
334
335=item *
336
337<< $c->res->redirect >> is handled by default. If you just forward to
338C<View::TT> in your C<end> routine, you could break this by sending additional
339content.
340
341=back
342
343See L<Catalyst::Action::RenderView> for more details.
344
8cd017a8 345=head2 CONFIGURATION
4687ac0d 346
8cd017a8 347There are a three different ways to configure your view class. The
348first way is to call the C<config()> method in the view subclass. This
349happens when the module is first loaded.
8077080c 350
6229ce0d 351 package MyApp::View::TT;
f5b61ad7 352
8cd017a8 353 use strict;
354 use base 'Catalyst::View::TT';
722fede4 355
6229ce0d 356 MyApp::View::TT->config({
7d8aa5ec 357 INCLUDE_PATH => [
358 MyApp->path_to( 'root', 'templates', 'lib' ),
359 MyApp->path_to( 'root', 'templates', 'src' ),
360 ],
8cd017a8 361 PRE_PROCESS => 'config/main',
362 WRAPPER => 'site/wrapper',
363 });
364
365The second way is to define a C<new()> method in your view subclass.
366This performs the configuration when the view object is created,
367shortly after being loaded. Remember to delegate to the base class
e8693f1b 368C<new()> method (via C<$self-E<gt>next::method()> in the example below) after
8cd017a8 369performing any configuration.
370
371 sub new {
372 my $self = shift;
373 $self->config({
7d8aa5ec 374 INCLUDE_PATH => [
375 MyApp->path_to( 'root', 'templates', 'lib' ),
376 MyApp->path_to( 'root', 'templates', 'src' ),
377 ],
8cd017a8 378 PRE_PROCESS => 'config/main',
379 WRAPPER => 'site/wrapper',
380 });
e8693f1b 381 return $self->next::method(@_);
8cd017a8 382 }
f5b61ad7 383
94b3529a 384The final, and perhaps most direct way, is to define a class
8cd017a8 385item in your main application configuration, again by calling the
ad50568f 386ubiquitous C<config()> method. The items in the class hash are
8cd017a8 387added to those already defined by the above two methods. This happens
388in the base class new() method (which is one reason why you must
f5b61ad7 389remember to call it via C<MRO::Compat> if you redefine the C<new()>
e8693f1b 390method in a subclass).
8cd017a8 391
392 package MyApp;
f5b61ad7 393
8cd017a8 394 use strict;
395 use Catalyst;
f5b61ad7 396
8cd017a8 397 MyApp->config({
398 name => 'MyApp',
7d8aa5ec 399 root => MyApp->path_to('root'),
6229ce0d 400 'View::TT' => {
7d8aa5ec 401 INCLUDE_PATH => [
402 MyApp->path_to( 'root', 'templates', 'lib' ),
403 MyApp->path_to( 'root', 'templates', 'src' ),
404 ],
8cd017a8 405 PRE_PROCESS => 'config/main',
406 WRAPPER => 'site/wrapper',
407 },
408 });
409
410Note that any configuration items defined by one of the earlier
411methods will be overwritten by items of the same name provided by the
f5b61ad7 412latter methods.
8cd017a8 413
e2bbd784 414=head2 DYNAMIC INCLUDE_PATH
415
f7dfca06 416Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
f5b61ad7 417
f7dfca06 418Additional paths can be added to the start of INCLUDE_PATH via the stash as
419follows:
420
421 $c->stash->{additional_template_paths} =
422 [$c->config->{root} . '/test_include_path'];
423
424If you need to add paths to the end of INCLUDE_PATH, there is also an
425include_path() accessor available:
426
427 push( @{ $c->view('TT')->include_path }, qw/path/ );
428
429Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
430MUST check for duplicate paths. Without such checking, the above code will add
431"path" to INCLUDE_PATH at every request, causing a memory leak.
432
433A safer approach is to use include_path() to overwrite the array of paths
434rather than adding to it. This eliminates both the need to perform duplicate
435checking and the chance of a memory leak:
e2bbd784 436
f7dfca06 437 @{ $c->view('TT')->include_path } = qw/path another_path/;
e2bbd784 438
f5b61ad7 439If you are calling C<render> directly then you can specify dynamic paths by
9d574573 440having a C<additional_template_paths> key with a value of additonal directories
1bc9fc55 441to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this.
442
8cd017a8 443=head2 RENDERING VIEWS
444
445The view plugin renders the template specified in the C<template>
f5b61ad7 446item in the stash.
8cd017a8 447
448 sub message : Global {
94b3529a 449 my ( $self, $c ) = @_;
450 $c->stash->{template} = 'message.tt2';
6229ce0d 451 $c->forward( $c->view('TT') );
8cd017a8 452 }
722fede4 453
c969f23a 454If a stash item isn't defined, then it instead uses the
455stringification of the action dispatched to (as defined by $c->action)
456in the above example, this would be C<message>, but because the default
457is to append '.tt', it would load C<root/message.tt>.
8cd017a8 458
459The items defined in the stash are passed to the Template Toolkit for
460use as template variables.
461
8cd017a8 462 sub default : Private {
94b3529a 463 my ( $self, $c ) = @_;
464 $c->stash->{template} = 'message.tt2';
465 $c->stash->{message} = 'Hello World!';
6229ce0d 466 $c->forward( $c->view('TT') );
8cd017a8 467 }
7b592fc7 468
8cd017a8 469A number of other template variables are also added:
8077080c 470
8cd017a8 471 c A reference to the context object, $c
472 base The URL base, from $c->req->base()
473 name The application name, from $c->config->{ name }
474
475These can be accessed from the template in the usual way:
476
477<message.tt2>:
478
479 The message is: [% message %]
480 The base is [% base %]
481 The name is [% name %]
482
8cd017a8 483
1bc9fc55 484The output generated by the template is stored in C<< $c->response->body >>.
485
486=head2 CAPTURING TEMPLATE OUTPUT
487
488If you wish to use the output of a template for some other purpose than
489displaying in the response, e.g. for sending an email, this is possible using
490L<Catalyst::Plugin::Email> and the L<render> method:
491
492 sub send_email : Local {
493 my ($self, $c) = @_;
f5b61ad7 494
1bc9fc55 495 $c->email(
496 header => [
497 To => 'me@localhost',
498 Subject => 'A TT Email',
499 ],
500 body => $c->view('TT')->render($c, 'email.tt', {
9d574573 501 additional_template_paths => [ $c->config->{root} . '/email_templates'],
1bc9fc55 502 email_tmpl_param1 => 'foo'
503 }
504 ),
505 );
506 # Redirect or display a message
507 }
8cd017a8 508
509=head2 TEMPLATE PROFILING
510
1bc9fc55 511See L<C<TIMER>> property of the L<config> method.
512
caa61517 513=head2 METHODS
8077080c 514
b63ddd04 515=head2 new
2774dc77 516
f5b61ad7 517The constructor for the TT view. Sets up the template provider,
2774dc77 518and reads the application config.
519
81b7f2a2 520=head2 process($c)
8077080c 521
1bc9fc55 522Renders the template specified in C<< $c->stash->{template} >> or
ad50568f 523C<< $c->action >> (the private name of the matched action). Calls L<render> to
1bc9fc55 524perform actual rendering. Output is stored in C<< $c->response->body >>.
8077080c 525
81b7f2a2 526It is possible to forward to the process method of a TT view from inside
527Catalyst like this:
528
529 $c->forward('View::TT');
530
531N.B. This is usually done automatically by L<Catalyst::Action::RenderView>.
f2ee4d6c 532
b63ddd04 533=head2 render($c, $template, \%args)
1bc9fc55 534
cad820fe 535Renders the given template and returns output. Throws a L<Template::Exception>
f5b61ad7 536object upon error.
1bc9fc55 537
f5b61ad7 538The template variables are set to C<%$args> if $args is a hashref, or
539$C<< $c->stash >> otherwise. In either case the variables are augmented with
1bc9fc55 540C<base> set to C< << $c->req->base >>, C<c> to C<$c> and C<name> to
541C<< $c->config->{name} >>. Alternately, the C<CATALYST_VAR> configuration item
542can be defined to specify the name of a template variable through which the
543context reference (C<$c>) can be accessed. In this case, the C<c>, C<base> and
544C<name> variables are omitted.
545
f5b61ad7 546C<$template> can be anything that Template::process understands how to
1bc9fc55 547process, including the name of a template file or a reference to a test string.
548See L<Template::process|Template/process> for a full list of supported formats.
549
f59953e1 550To use the render method outside of your Catalyst app, just pass a undef context.
cbb149dc 551This can be useful for tests, for instance.
552
81b7f2a2 553It is possible to forward to the render method of a TT view from inside Catalyst
554to render page fragments like this:
555
556 my $fragment = $c->forward("View::TT", "render", $template_name, $c->stash->{fragment_data});
f2ee4d6c 557
3715305f 558=head3 Backwards compatibility note
559
560The render method used to just return the Template::Exception object, rather
561than just throwing it. This is now deprecated and instead the render method
562will throw an exception for new applications.
563
564This behaviour can be activated (and is activated in the default skeleton
565configuration) by using C<< render_die => 1 >>. If you rely on the legacy
566behaviour then a warning will be issued.
567
568To silence this warning, set C<< render_die => 0 >>, but it is recommended
569you adjust your code so that it works with C<< render_die => 1 >>.
570
571In a future release, C<< render_die => 1 >> will become the default if
572unspecified.
573
b63ddd04 574=head2 template_vars
850ee226 575
1bc9fc55 576Returns a list of keys/values to be used as the catalyst variables in the
850ee226 577template.
578
b63ddd04 579=head2 config
8077080c 580
8cd017a8 581This method allows your view subclass to pass additional settings to
4729c102 582the TT configuration hash, or to set the options as below:
583
b63ddd04 584=head2 paths
585
586The list of paths TT will look for templates in.
4729c102 587
f5b61ad7 588=head2 C<CATALYST_VAR>
4729c102 589
590Allows you to change the name of the Catalyst context object. If set, it will also
591remove the base and name aliases, so you will have access them through <context>.
592
593For example:
594
595 MyApp->config({
596 name => 'MyApp',
7d8aa5ec 597 root => MyApp->path_to('root'),
6229ce0d 598 'View::TT' => {
4729c102 599 CATALYST_VAR => 'Catalyst',
600 },
601 });
602
603F<message.tt2>:
604
605 The base is [% Catalyst.req.base %]
606 The name is [% Catalyst.config.name %]
607
b63ddd04 608=head2 C<TIMER>
4729c102 609
610If you have configured Catalyst for debug output, and turned on the TIMER setting,
611C<Catalyst::View::TT> will enable profiling of template processing
612(using L<Template::Timer>). This will embed HTML comments in the
613output from your templates, such as:
614
615 <!-- TIMER START: process mainmenu/mainmenu.ttml -->
616 <!-- TIMER START: include mainmenu/cssindex.tt -->
617 <!-- TIMER START: process mainmenu/cssindex.tt -->
618 <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
619 <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
620
621 ....
622
623 <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
624
625
b63ddd04 626=head2 C<TEMPLATE_EXTENSION>
4729c102 627
747f2b6d 628a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
4729c102 629
630For example:
631
6229ce0d 632 package MyApp::Controller::Test;
f5b61ad7 633 sub test : Local { .. }
4729c102 634
635Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
636<root>/test/test.tt.
637
51199593 638=head2 C<PROVIDERS>
639
640Allows you to specify the template providers that TT will use.
641
642 MyApp->config({
643 name => 'MyApp',
644 root => MyApp->path_to('root'),
6229ce0d 645 'View::TT' => {
51199593 646 PROVIDERS => [
647 {
648 name => 'DBI',
649 args => {
650 DBI_DSN => 'dbi:DB2:books',
651 DBI_USER=> 'foo'
652 }
653 }, {
654 name => '_file_',
655 args => {}
656 }
657 ]
658 },
659 });
660
661The 'name' key should correspond to the class name of the provider you
662want to use. The _file_ name is a special case that represents the default
663TT file-based provider. By default the name is will be prefixed with
664'Template::Provider::'. You can fully qualify the name by using a unary
665plus:
666
667 name => '+MyApp::Provider::Foo'
668
6175bba7 669You can also specify the 'copy_config' key as an arrayref, to copy those keys
670from the general config, into the config for the provider:
f5b61ad7 671
6175bba7 672 DEFAULT_ENCODING => 'utf-8',
673 PROVIDERS => [
674 {
675 name => 'Encoding',
676 copy_config => [qw(DEFAULT_ENCODING INCLUDE_PATH)]
677 }
678 ]
f5b61ad7 679
6175bba7 680This can prove useful when you want to use the additional_template_paths hack
681in your own provider, or if you need to use Template::Provider::Encoding
682
8cd017a8 683=head2 HELPERS
684
685The L<Catalyst::Helper::View::TT> and
686L<Catalyst::Helper::View::TTSite> helper modules are provided to create
687your view module. There are invoked by the F<myapp_create.pl> script:
688
689 $ script/myapp_create.pl view TT TT
690
691 $ script/myapp_create.pl view TT TTSite
692
693The L<Catalyst::Helper::View::TT> module creates a basic TT view
694module. The L<Catalyst::Helper::View::TTSite> module goes a little
695further. It also creates a default set of templates to get you
696started. It also configures the view module to locate the templates
697automatically.
698
02c64502 699=head1 NOTES
700
701If you are using the L<CGI> module inside your templates, you will
702experience that the Catalyst server appears to hang while rendering
703the web page. This is due to the debug mode of L<CGI> (which is
704waiting for input in the terminal window). Turning off the
705debug mode using the "-no_debug" option solves the
706problem, eg.:
707
708 [% USE CGI('-no_debug') %]
709
8077080c 710=head1 SEE ALSO
711
8cd017a8 712L<Catalyst>, L<Catalyst::Helper::View::TT>,
713L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
8077080c 714
c0eb0527 715=head1 AUTHORS
8077080c 716
717Sebastian Riedel, C<sri@cpan.org>
c0eb0527 718
d938377b 719Marcus Ramberg, C<mramberg@cpan.org>
c0eb0527 720
722fede4 721Jesse Sheidlower, C<jester@panix.com>
c0eb0527 722
8cd017a8 723Andy Wardley, C<abw@cpan.org>
8077080c 724
725=head1 COPYRIGHT
726
f5b61ad7 727This program is free software. You can redistribute it and/or modify it
2774dc77 728under the same terms as Perl itself.
8077080c 729
730=cut