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