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