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