]> git.decadent.org.uk Git - maypole.git/blob - lib/Maypole/View/Base.pm
Fixed mime type setting, fixed errors in revision 445, folded in Maypole::Component...
[maypole.git] / lib / Maypole / View / Base.pm
1 package Maypole::View::Base;
2 use File::Spec;
3 use UNIVERSAL::moniker;
4 use strict;
5 use Maypole::Constants;
6 use Carp;
7
8 sub new { bless {}, shift }    # By default, do nothing.
9
10 sub paths {
11     my ( $self, $r ) = @_;
12     my $root = $r->config->template_root || $r->get_template_root;
13     if(ref($root) ne 'ARRAY') {
14         $root = [ $root ];
15     }
16     my @output = ();
17     foreach my $path (@$root) {
18         push(@output, $path);
19         push(@output,
20              (
21               $r->model_class
22               && File::Spec->catdir( $path, $r->model_class->moniker )
23               )
24              );
25         push(@output, File::Spec->catdir( $path, "custom" ));
26         push(@output, File::Spec->catdir( $path, "factory" ));
27     }
28
29     return @output;
30 }
31
32
33
34
35 sub vars {
36     my ( $self, $r ) = @_;
37     my $class = $r->model_class;
38     my $base  = $r->config->uri_base;
39     $base =~ s/\/+$//;
40     my %args = (
41         request => $r,
42         objects => $r->objects,
43         base    => $base,
44         config  => $r->config
45
46           # ...
47     );
48     if ($class) {
49         my $classmeta = $r->template_args->{classmetadata} ||= {};
50         $classmeta->{name}              ||= $class;
51         $classmeta->{table}             ||= $class->table;
52         $classmeta->{columns}           ||= [ $class->display_columns ];
53         $classmeta->{list_columns}      ||= [ $class->list_columns ];
54         $classmeta->{colnames}          ||= { $class->column_names };
55         $classmeta->{related_accessors} ||= [ $class->related($r) ];
56         $classmeta->{moniker}           ||= $class->moniker;
57         $classmeta->{plural}            ||= $class->plural_moniker;
58         $classmeta->{cgi}               ||= { $class->to_cgi };
59         $classmeta->{stringify_column}  ||= $class->stringify_column;
60
61         # User-friendliness facility for custom template writers.
62         if ( @{ $r->objects || [] } > 1 ) {
63             $args{ $r->model_class->plural_moniker } = $r->objects;
64         }
65         else {
66             ( $args{ $r->model_class->moniker } ) = @{ $r->objects || [] };
67         }
68     }
69
70     # Overrides
71     %args = ( %args, %{ $r->template_args || {} } );
72     %args;
73 }
74
75 sub process {
76     my ( $self, $r ) = @_;
77     my $status = $self->template($r);
78     return $self->error($r) if $status != OK;
79     return OK;
80 }
81
82 sub error {
83     my ( $self, $r, $desc ) = @_;
84     $desc = $desc ? "$desc: " : "";
85     carp $desc . $r->{error};
86     if ( $r->{error} =~ /not found$/ ) {
87
88         # This is a rough test to see whether or not we're a template or
89         # a static page
90         return -1 unless @{ $r->{objects} || [] };
91
92         my $template_error = $r->{error};
93         $r->{error} = <<EOF;
94
95 <h1> Template not found </h1>
96
97 A template was not found while processing the following request:
98
99 <strong>@{[$r->{action}]}</strong> on table
100 <strong>@{[ $r->{table} ]}</strong> with objects:
101
102 <pre>
103 @{[join "\n", @{$r->{objects}}]}
104 </pre>
105
106
107 The main template is <strong>@{[$r->{template}]}</strong>.
108 The template subsystem's error message was
109 <pre>
110 $template_error
111 </pre>
112 We looked in paths:
113
114 <pre>
115 @{[ join "\n", $self->paths($r) ]}
116 </pre>
117 EOF
118         $r->{content_type} = "text/html";
119         $r->{output}       = $r->{error};
120         return OK;
121     }
122     $r->{content_type} = "text/plain";
123     $r->{output}       = $r->{error};
124     $r->send_output;
125     return ERROR;
126 }
127
128 sub template { die shift() . " didn't define a decent template method!" }
129
130 1;
131
132
133 =head1 NAME
134
135 Maypole::View::Base - Base class for view classes
136
137 =head1 DESCRIPTION
138
139 This is the base class for Maypole view classes. This is an abstract class
140 that defines the interface, and can't be used directly.
141
142 =head2 process
143
144 This is the entry point for the view. It templates the request and returns a
145 C<Maypole::Constant> indicate success or failure for the view phase.
146
147 Anyone subclassing this for a different rendering mechanism needs to provide
148 the following methods:
149
150 =head2 template
151
152 In this method you do the actual processing of your template. it should use
153 L<paths> to search for components, and provide the templates with easy access
154 to the contents of L<vars>. It should put the result in C<$r-E<gt>output> and
155 return C<OK> if processing was sucessfull, or populate C<$r-E<gt>error> and
156 return C<ERROR> if it fails.
157
158 =head1 Other overrides
159
160 Additionally, individual derived model classes may want to override the
161
162 =head2 new
163
164 The default constructor does nothing. You can override this to perform actions
165 during view initialization.
166
167 =head2 paths
168
169 Returns search paths for templates. the default method returns folders for the
170 model class's C<moniker>, factory, custom under the configured template root.
171
172 =head2 vars
173
174 returns a hash of data the template should have access to. The default one
175 populates classmetadata if there is a table class, as well as setting the data
176 objects by name if there is one or more objects available.
177
178 =head2 error
179
180
181 =cut