]> git.decadent.org.uk Git - maypole.git/blobdiff - lib/Maypole/View/TT.pm
added sensible defaults to template so less whitespace waste
[maypole.git] / lib / Maypole / View / TT.pm
index 6f9fbc6bbc7115278c717983066e403670c7c9aa..8759e0cba9206754a24783b7b82de80cb0e1d8f9 100644 (file)
@@ -3,40 +3,90 @@ use base 'Maypole::View::Base';
 use Maypole::Constants;
 use Template;
 use File::Spec::Functions qw(catdir tmpdir);
 use Maypole::Constants;
 use Template;
 use File::Spec::Functions qw(catdir tmpdir);
+use Template::Constants qw( :all );
+
+our $error_template;
+{ local $/; $error_template = <DATA>; }
+
+our $VERSION = '2.13';
+
+my $debug_flags = DEBUG_ON;
 
 use strict;
 
 use strict;
-our $VERSION = 2.11;
 
 sub template {
 
 sub template {
-    my ( $self, $r ) = @_;
-
-    unless ($self->{tt}) {
-        my $view_options = $r->config->view_options || {};
-        $self->{provider} = Template::Provider->new($view_options);
-        $self->{tt}       = Template->new({
-            %$view_options,
-            LOAD_TEMPLATES => [ $self->{provider} ],
-        });
+  my ( $self, $r ) = @_;
+  unless ($self->{tt}) {
+    my $view_options = $r->config->view_options || { POST_CHOMP=>1, PRE_CHOMP=>1, TRIM=>1 };
+    if ($r->debug) {
+      $view_options->{DEBUG} = $debug_flags;
     }
 
     }
 
-    $self->{provider}->include_path([ $self->paths($r) ]);
+    $view_options->{POST_CHOMP} = 1 unless (exists $view_options->{POST_CHOMP});
+    $self->{provider} = Template::Provider->new($view_options);
+    $self->{tt}       = Template->new({
+                                      %$view_options,
+                                      LOAD_TEMPLATES => [ $self->{provider} ],
+                                     });
+  }
+
+  $self->{provider}->include_path([ $self->paths($r) ]);
+
+  my $template_file = $r->template;
+
+  my $ext = $r->config->template_extension;
+  $template_file .= $ext if defined $ext;
+
+  my $output;
+  my $processed_ok = eval{$self->{tt}->process($template_file, { $self->vars($r) }, \$output );};
+  if ($processed_ok) {
+    $r->{output} = $output;
+    return OK;
+  } else {
+    if ($@) {
+      my $error = "fatal error in template '$template_file' : $@\nTT paths : " . join(', ',$self->paths($r)) . "\n";
+      $r->warn($error);
+      $r->{error} = $error;
+    } else {
+      my $error = "TT error for template '$template_file'\n" . $self->{tt}->error . "\nTT paths : " . join(', ',$self->paths($r)) . "\n";
+      $r->warn($error);
+      $r->{error} = $error;
+    }
+    return ERROR;
+  }
+}
 
 
-    my $template_file = $r->template;
-    my $ext = $r->config->template_extension;
-    $template_file .= $ext if defined $ext;
 
 
+sub report_error {
+    my ($self, $r, $error, $type) = @_;
     my $output;
     my $output;
-    if ($self->{tt}->process($template_file, { $self->vars($r) }, \$output )) {
+
+    # Need to be very careful here.
+    my $tt = Template->new;
+    unless (ref $r->{config}) {
+      $r->warn("no config for this request");
+      $error .= '<br> There was a problem finding configuration for this request';
+      $r->{config} ||= {};
+    }
+
+    $r->warn("report_error - reporting error to user : $error\n");
+
+    if ($tt->process(\$error_template,
+                    { err_type => $type, error => $error,
+                      config => $r->{config},
+                      request => $r,
+                      paths => [ $self->paths($r) ],
+                      eval{$self->vars($r)} }, \$output )) {
         $r->{output} = $output;
         $r->{output} = $output;
+        if ($tt->error) { $r->{output} = "<html><body>Even the error template
+        errored - ".$tt->error."</body></html>"; }
+        $r->{content_type}      ||= "text/html";
+        $r->{document_encoding} ||= "utf-8";
         return OK;
     }
         return OK;
     }
-    else {
-       $r->{error} = "TT error for template '$template_file'\n" . $self->{tt}->error;
-        return ERROR;
-    }
+    return ERROR;
 }
 
 }
 
-1;
 
 =head1 NAME
 
 
 =head1 NAME
 
@@ -54,7 +104,13 @@ Maypole::View::TT - A Template Toolkit view class for Maypole
 
     .....
 
 
     .....
 
-    [%# Template Toolkit directives and maypole macros go here %]
+    [% PROCESS macros %]
+
+    [% pager %]
+
+    [% link %]
+
+    [% maybe_link_view %]
 
 =head1 DESCRIPTION
 
 
 =head1 DESCRIPTION
 
@@ -74,6 +130,10 @@ options.
 
 Processes the template and sets the output. See L<Maypole::View::Base>
 
 
 Processes the template and sets the output. See L<Maypole::View::Base>
 
+=item report_error
+
+Reports the details of an error, current state and parameters
+
 =back
 
 =head1 TEMPLATE TOOLKIT INTRODUCTION
 =back
 
 =head1 TEMPLATE TOOLKIT INTRODUCTION
@@ -112,6 +172,9 @@ or CALL a method or operation which will also not return anything.
 You can specify expressions using the logical (and, or, not, ?:) and mathematic
 operators (+ - * / % mod div).
 
 You can specify expressions using the logical (and, or, not, ?:) and mathematic
 operators (+ - * / % mod div).
 
+Results of TT commands are interpolated in the place of the template tags, unless
+using SET or CALL, i.e. [% SET foo = 1 %], [% GET foo.bar('quz'); %]
+
 =over 4
 
 [% template.title or default.title %]
 =over 4
 
 [% template.title or default.title %]
@@ -236,6 +299,18 @@ truncate, format, escape or encode trivially. A useful selection is included
 with Template Toolkit and they can also be found on CPAN or can be written
 easily. See L<Template::Manual::Filters>.
 
 with Template Toolkit and they can also be found on CPAN or can be written
 easily. See L<Template::Manual::Filters>.
 
+TT provides stderr and stdout filters, which allow you to write handy macros
+like this one to output debug information to your web server log, etc :
+
+=over 4
+
+[% MACRO debug_msg(text)
+    FILTER stderr; "[TT debug_msg] $text\n"; END;
+%]
+
+=back
+
+
 TT Macros allow you to reuse small blocks of content, directives, etc. The MACRO
 directive allows you to define a directive or directive block which is then
 evaluated each time the macro is called. Macros can be passed named parameters
 TT Macros allow you to reuse small blocks of content, directives, etc. The MACRO
 directive allows you to define a directive or directive block which is then
 evaluated each time the macro is called. Macros can be passed named parameters
@@ -247,15 +322,72 @@ and useful macros in the templates/ directory of the package and these are used
 in the beerdb and default templates. See the MACRO section of the
 L<Template::Manual::Directives> documentation.
 
 in the beerdb and default templates. See the MACRO section of the
 L<Template::Manual::Directives> documentation.
 
+=head1 ACCESSING MAYPOLE VALUES
+
+=head2 request
+
+You can access the request in your templates in order to see the action, table, etc as well
+as parameters passed through forms :
+
+for example
+
+Hello [% request.params.forename %] [% request.params.surname %] !
+
+or 
+
+Are you want to [% request.action %] in the [% request.table %] ?
+
+=head2 config
+
+You can access your maypole application configuration through the config variable :
+
+<link base="[% config.uri_base %]"/>
+
+=head2 object and objects
+
+Objects are passed to the request using r->objects($arrayref) and are accessed in the templates
+as an array called objects.
+
+[% FOR objects %] <a href="[% config.uri_base %]/[% request.table %]/view/[% object.id %]"> [% object %] </a> [% END %]
+
 =head1 MAYPOLE MACROS AND FILTERS
 
 =head1 MAYPOLE MACROS AND FILTERS
 
-Maypole provides a collection of useful and powerful macros...TO DO
+Maypole provides a collection of useful and powerful macros in the templates/factory/macros
+ and other templates. These can be used in any template with [% PROCESS templatename %].
 
 =head2 link
 
 
 =head2 link
 
-=head2 other macros
+This creates an <A HREF="..."> to a command in the Apache::MVC system by
+catenating the base URL, table, command, and any arguments.
 
 
-=head2 finish this documentation
+=head2 maybe_link_view
+
+C<maybe_link_view> takes something returned from the database - either
+some ordinary data, or an object in a related class expanded by a
+has-a relationship. If it is an object, it constructs a link to the view
+command for that object. Otherwise, it just displays the data.
+
+=head2 pager
+
+This is an include template rather than a macro, and it controls the pager
+display at the bottom (by default) of the factory list and search views/template.
+It expects a C<pager> template argument which responds to the L<Data::Page> interface.
+
+This macro is in the pager template and used as :
+
+[% PROCESS pager %]
+
+Maypole provides a pager for list and search actions, otherwise you can
+provide a pager in the template using Template::Plugin::Pagination.
+
+[% USE pager = Pagination(objects, page.current, page.rows) %]
+...
+[% PROCESS pager %]
+
+The pager will use a the request action  as the action in the url unless the
+pager_action variable is set, which it will use instead if available.
+
+=head2 other macros
 
 =head1 AUTHOR
 
 
 =head1 AUTHOR
 
@@ -263,3 +395,64 @@ Simon Cozens
 
 =cut
 
 
 =cut
 
+1;
+
+__DATA__
+<html><head><title>Maypole error page</title>
+<style type="text/css">
+body { background-color:#7d95b5; font-family: sans-serif}
+p { background-color: #fff; padding: 5px; }
+pre { background-color: #fff; padding: 5px; border: 1px dotted black }
+h1 { color: #fff }
+h2 { color: #fff }
+.lhs {background-color: #ffd; }
+.rhs {background-color: #dff; }
+</style>
+</head> <body>
+<h1> Maypole application error </h1>
+
+<p> This application living at <code>[%request.config.uri_base%]</code>, 
+[%request.config.application_name || "which is unnamed" %], has
+produced an error. The adminstrator should be able to understand
+this error message and fix the problem.</p>
+
+<h2> Some basic facts </h2>
+
+<p> The error was found in the [% err_type %] stage of processing
+the path "[% request.path %]". The error text returned was:
+</p>
+<pre>
+    [% error %]
+</pre>
+
+<h2> Request details </h2>
+
+<table width="85%" cellspacing="2" cellpadding="1">
+    [% FOR attribute = ["model_class", "table", "template", "path",
+    "content_type", "document_encoding", "action", "args", "objects"] %]
+    <tr> <td class="lhs" width="35%"> <b>[% attribute %]</b> </td> <td class="rhs" width="65%"> [%
+    request.$attribute.list.join(" , ") %] </td></tr>
+    [% END %]
+    <tr><td colspan="2"></tr>
+    <tr><td class="lhs" colspan="2"><b>CGI Parameters</b> </td></tr>
+    [% FOREACH param IN request.params %]
+    <tr> <td class="lhs" width="35%">[% param.key %]</td> <td class="rhs" width="65%"> [% param.value %] </td></tr>
+    [% END %]
+</table>
+
+<h2> Website / Template Paths </h2>
+<table width="85%" cellspacing="2" cellpadding="1">
+<tr><td class="lhs" width="35%"> <b>Base URI</b> </td><td class="rhs" width="65%">[% request.config.uri_base %]</td></tr>
+<tr><td class="lhs" width="35%"> <b>Paths</b> </td><td class="rhs" width="65%"> [% paths %] </td></tr>
+</table>
+
+<h2> Application configuration </h2>
+<table width="85%" cellspacing="2" cellpadding="1">
+    <tr><td class="lhs"  width="35%"> <b>Model </b> </td><td class="rhs" width="65%"> [% request.config.model %] </td></tr>
+    <tr><td class="lhs"  width="35%"> <b>View </b> </td><td class="rhs" width="65%"> [% request.config.view %] </td></tr>
+    <tr><td class="lhs" width="35%"> <b>Classes</b> </td><td class="rhs" width="65%"> [% request.config.classes.list.join(" , ") %] </td></tr>
+    <tr><td class="lhs" width="35%"> <b>Tables</b> </td><td class="rhs" width="65%"> [% request.config.display_tables.list.join(" , ") %] </td></tr>
+</table>
+
+</body>
+</html>