| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Maypole; |
|
2
|
1
|
|
|
1
|
|
1261
|
use base qw(Class::Accessor::Fast Class::Data::Inheritable); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
798
|
|
|
3
|
|
|
|
|
|
|
use UNIVERSAL::require; |
|
4
|
|
|
|
|
|
|
use strict; |
|
5
|
|
|
|
|
|
|
use warnings; |
|
6
|
|
|
|
|
|
|
use Data::Dumper; |
|
7
|
|
|
|
|
|
|
use Maypole::Config; |
|
8
|
|
|
|
|
|
|
use Maypole::Constants; |
|
9
|
|
|
|
|
|
|
use Maypole::Headers; |
|
10
|
|
|
|
|
|
|
use URI(); |
|
11
|
|
|
|
|
|
|
use URI::QueryParam; |
|
12
|
|
|
|
|
|
|
use NEXT; |
|
13
|
|
|
|
|
|
|
use File::MMagic::XS qw(:compat); |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '2.13'; |
|
16
|
|
|
|
|
|
|
our $mmagic = File::MMagic::XS->new(); |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# proposed privacy conventions: |
|
19
|
|
|
|
|
|
|
# - no leading underscore - public to custom application code and plugins |
|
20
|
|
|
|
|
|
|
# - single leading underscore - private to the main Maypole stack - *not* |
|
21
|
|
|
|
|
|
|
# including plugins |
|
22
|
|
|
|
|
|
|
# - double leading underscore - private to the current package |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 NAME |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
Maypole - MVC web application framework |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
The canonical example used in the Maypole documentation is the beer database: |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
package BeerDB; |
|
33
|
|
|
|
|
|
|
use strict; |
|
34
|
|
|
|
|
|
|
use warnings; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# choose a frontend, initialise the config object, and load a plugin |
|
37
|
|
|
|
|
|
|
use Maypole::Application qw/Relationship/; |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# set everything up |
|
40
|
|
|
|
|
|
|
__PACKAGE__->setup("dbi:SQLite:t/beerdb.db"); |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# get the empty config object created by Maypole::Application |
|
43
|
|
|
|
|
|
|
my $config = __PACKAGE__->config; |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# basic settings |
|
46
|
|
|
|
|
|
|
$config->uri_base("http://localhost/beerdb"); |
|
47
|
|
|
|
|
|
|
$config->template_root("/path/to/templates"); |
|
48
|
|
|
|
|
|
|
$config->rows_per_page(10); |
|
49
|
|
|
|
|
|
|
$config->display_tables([qw/beer brewery pub style/]); |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# table relationships |
|
52
|
|
|
|
|
|
|
$config->relationships([ |
|
53
|
|
|
|
|
|
|
"a brewery produces beers", |
|
54
|
|
|
|
|
|
|
"a style defines beers", |
|
55
|
|
|
|
|
|
|
"a pub has beers on handpumps", |
|
56
|
|
|
|
|
|
|
]); |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# validation |
|
59
|
|
|
|
|
|
|
BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] ); |
|
60
|
|
|
|
|
|
|
BeerDB::Pub->untaint_columns( printable => [qw/name notes url/] ); |
|
61
|
|
|
|
|
|
|
BeerDB::Style->untaint_columns( printable => [qw/name notes/] ); |
|
62
|
|
|
|
|
|
|
BeerDB::Beer->untaint_columns( |
|
63
|
|
|
|
|
|
|
printable => [qw/abv name price notes/], |
|
64
|
|
|
|
|
|
|
integer => [qw/style brewery score/], |
|
65
|
|
|
|
|
|
|
date => [ qw/date/], |
|
66
|
|
|
|
|
|
|
); |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# note : set up model before calling this method |
|
69
|
|
|
|
|
|
|
BeerDB::Beer->required_columns([qw/name/]); |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
1; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
This documents the Maypole request object. See the L, for a |
|
76
|
|
|
|
|
|
|
detailed guide to using Maypole. |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Maypole is a Perl web application framework similar to Java's struts. It is |
|
79
|
|
|
|
|
|
|
essentially completely abstracted, and so doesn't know anything about |
|
80
|
|
|
|
|
|
|
how to talk to the outside world. |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
To use it, you need to create a driver package which represents your entire |
|
83
|
|
|
|
|
|
|
application. This is the C package used as an example in the manual. |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
This needs to first use L which will make your package |
|
86
|
|
|
|
|
|
|
inherit from the appropriate platform driver such as C or |
|
87
|
|
|
|
|
|
|
C. Then, the driver calls C. This sets up the model classes |
|
88
|
|
|
|
|
|
|
and configures your application. The default model class for Maypole uses |
|
89
|
|
|
|
|
|
|
L to map a database to classes, but this can be changed by altering |
|
90
|
|
|
|
|
|
|
configuration (B calling setup.) |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 DOCUMENTATION AND SUPPORT |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Note that some details in some of these resources may be out of date. |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=over 4 |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item The Maypole Manual |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
The primary documentation is the Maypole manual. This lives in the |
|
102
|
|
|
|
|
|
|
C pod documents included with the distribution. |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=item Embedded POD |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Individual packages within the distribution contain (more or less) detailed |
|
107
|
|
|
|
|
|
|
reference documentation for their API. |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=item Mailing lists |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
There are two mailing lists - maypole-devel and maypole-users - see |
|
112
|
|
|
|
|
|
|
http://maypole.perl.org/?MailingList |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=item The Maypole Wiki |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
The Maypole wiki provides a useful store of extra documentation - |
|
117
|
|
|
|
|
|
|
http://maypole.perl.org |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
In particular, there's a FAQ (http://maypole.perl.org/?FAQ) and a cookbook |
|
120
|
|
|
|
|
|
|
(http://maypole.perl.org/?Cookbook). Again, certain information on these pages |
|
121
|
|
|
|
|
|
|
may be out of date. |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item Web applications with Maypole |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
A tutorial written by Simon Cozens for YAPC::EU 2005 - |
|
126
|
|
|
|
|
|
|
http://www.aarontrevena.co.uk/opensource/maypole/maypole-tutorial.pdf [228KB]. |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item A Database-Driven Web Application in 18 Lines of Code |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
By Paul Barry, published in Linux Journal, March 2005. |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
http://www.linuxjournal.com/article/7937 |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
"From zero to Web-based database application in eight easy steps". |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Maypole won a 2005 Linux Journal Editor's Choice Award |
|
137
|
|
|
|
|
|
|
(http://www.linuxjournal.com/article/8293) after featuring in this article. |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item Build Web apps with Maypole |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
By Simon Cozens, on IBM's DeveloperWorks website, May 2004. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
http://www-128.ibm.com/developerworks/linux/library/l-maypole/ |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item Rapid Web Application Deployment with Maypole |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
By Simon Cozens, on O'Reilly's Perl website, April 2004. |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
http://www.perl.com/pub/a/2004/04/15/maypole.html |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item Authentication |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Some notes written by Simon Cozens. A little bit out of date, but still |
|
154
|
|
|
|
|
|
|
very useful: http://www.aarontrevena.co.uk/opensource/maypole/authentication.html |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=item CheatSheet |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
There's a refcard for the Maypole (and Class::DBI) APIs on the wiki - |
|
159
|
|
|
|
|
|
|
http://maypole.perl.org/?CheatSheet. Probably a little out of date now - it's a |
|
160
|
|
|
|
|
|
|
wiki, so feel free to fix any errors! |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item Plugins and add-ons |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
There are a large and growing number of plugins and other add-on modules |
|
165
|
|
|
|
|
|
|
available on CPAN - http://search.cpan.org/search?query=maypole&mode=module |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item del.icio.us |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
You can find a range of useful Maypole links, particularly to several thoughtful |
|
170
|
|
|
|
|
|
|
blog entries, starting here: http://del.icio.us/search/?all=maypole |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=item CPAN ratings |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
There are a couple of short reviews here: |
|
175
|
|
|
|
|
|
|
http://cpanratings.perl.org/dist/Maypole |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=back |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=cut |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
__PACKAGE__->mk_classdata($_) for qw( config init_done view_object model_classes_loaded); |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors( |
|
184
|
|
|
|
|
|
|
qw( params query objects model_class template_args output path |
|
185
|
|
|
|
|
|
|
args action template error document_encoding content_type table |
|
186
|
|
|
|
|
|
|
headers_in headers_out stash status parent build_form_elements |
|
187
|
|
|
|
|
|
|
user session) |
|
188
|
|
|
|
|
|
|
); |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
__PACKAGE__->config( Maypole::Config->new({additional => { }, request_options => { }, view_options => { },}) ); |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
__PACKAGE__->init_done(0); |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
__PACKAGE__->model_classes_loaded(0); |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head1 HOOKABLE METHODS |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
As a framework, Maypole provides a number of B - methods that are |
|
199
|
|
|
|
|
|
|
intended to be overridden. Some of these methods come with useful default |
|
200
|
|
|
|
|
|
|
behaviour, others do nothing by default. Hooks include: |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Class methods |
|
203
|
|
|
|
|
|
|
------------- |
|
204
|
|
|
|
|
|
|
debug |
|
205
|
|
|
|
|
|
|
setup |
|
206
|
|
|
|
|
|
|
setup_model |
|
207
|
|
|
|
|
|
|
load_model_subclass |
|
208
|
|
|
|
|
|
|
init |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Instance methods |
|
211
|
|
|
|
|
|
|
---------------- |
|
212
|
|
|
|
|
|
|
start_request_hook |
|
213
|
|
|
|
|
|
|
is_model_applicable |
|
214
|
|
|
|
|
|
|
get_session |
|
215
|
|
|
|
|
|
|
authenticate |
|
216
|
|
|
|
|
|
|
exception |
|
217
|
|
|
|
|
|
|
additional_data |
|
218
|
|
|
|
|
|
|
preprocess_path |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head1 CLASS METHODS |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=over 4 |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=item debug |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub My::App::debug {1} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Returns the debugging flag. Override this in your application class to |
|
229
|
|
|
|
|
|
|
enable/disable debugging. |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
You can also set the C flag via L. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
Some packages respond to higher debug levels, try increasing it to 2 or 3. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=cut |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub debug { 0 } |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=item config |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Returns the L object |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item setup |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
My::App->setup($data_source, $user, $password, \%attr); |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Initialise the Maypole application and plugins and model classes. |
|
249
|
|
|
|
|
|
|
Your application should call this B setting up configuration data via |
|
250
|
|
|
|
|
|
|
L<"config">. |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
It calls the hook C to setup the model. The %attr hash contains |
|
253
|
|
|
|
|
|
|
options and arguments used to set up the model. See the particular model's |
|
254
|
|
|
|
|
|
|
documentation. However here is the most usage of setup where |
|
255
|
|
|
|
|
|
|
Maypole::Model::CDBI is the base class. |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
My::App->setup($data_source, $user, $password, |
|
258
|
|
|
|
|
|
|
{ options => { # These are DB connection options |
|
259
|
|
|
|
|
|
|
AutoCommit => 0, |
|
260
|
|
|
|
|
|
|
RaiseError => 1, |
|
261
|
|
|
|
|
|
|
... |
|
262
|
|
|
|
|
|
|
}, |
|
263
|
|
|
|
|
|
|
# These are Class::DBI::Loader arguments. |
|
264
|
|
|
|
|
|
|
relationships => 1, |
|
265
|
|
|
|
|
|
|
... |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
); |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Also, see L. |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub setup |
|
275
|
|
|
|
|
|
|
{ |
|
276
|
|
|
|
|
|
|
my $class = shift; |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
$class->setup_model(@_); |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=item setup_model |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
Called by C. This method builds the Maypole model hierarchy. |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
A likely target for over-riding, if you need to build a customised model. |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
This method also ensures any code in custom model classes is loaded, so you |
|
288
|
|
|
|
|
|
|
don't need to load them in the driver. |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=cut |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub setup_model { |
|
293
|
|
|
|
|
|
|
my $class = shift; |
|
294
|
|
|
|
|
|
|
$class = ref $class if ref $class; |
|
295
|
|
|
|
|
|
|
my $config = $class->config; |
|
296
|
|
|
|
|
|
|
$config->model || $config->model('Maypole::Model::CDBI'); |
|
297
|
|
|
|
|
|
|
$config->model->require or die sprintf |
|
298
|
|
|
|
|
|
|
"Couldn't load the model class %s: %s", $config->model, $@; |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# among other things, this populates $config->classes |
|
301
|
|
|
|
|
|
|
$config->model->setup_database($config, $class, @_); |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
$config->model->add_model_superclass($config); |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# Load custom model code, if it exists - nb this must happen after the |
|
306
|
|
|
|
|
|
|
# adding the model superclass, to allow code attributes to work, but before adopt(), |
|
307
|
|
|
|
|
|
|
# in case adopt() calls overridden methods on $subclass |
|
308
|
|
|
|
|
|
|
foreach my $subclass ( @{ $config->classes } ) { |
|
309
|
|
|
|
|
|
|
$class->load_model_subclass($subclass) unless ($class->model_classes_loaded()); |
|
310
|
|
|
|
|
|
|
$config->model->adopt($subclass) if $config->model->can("adopt"); |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=item load_model_subclass($subclass) |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
This method is called from C. It attempts to load the |
|
318
|
|
|
|
|
|
|
C<$subclass> package, if one exists. So if you make a customized C |
|
319
|
|
|
|
|
|
|
package, you don't need to explicitly load it. |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
If automatic loading causes problems, Override load_model_subclass in your driver. |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub load_model_subclass {}; |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Or perhaps during development, if you don't want to load up custom classes, you |
|
326
|
|
|
|
|
|
|
can override this method and load them manually. |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=cut |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub load_model_subclass { |
|
331
|
|
|
|
|
|
|
my ($class, $subclass) = @_; |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
my $config = $class->config; |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Load any external files for the model base class or subclasses |
|
336
|
|
|
|
|
|
|
# (e.g. BeerDB/DBI.pm or BeerDB/Beer.pm) based on code borrowed from |
|
337
|
|
|
|
|
|
|
# Maypole::Plugin::Loader and Class::DBI. |
|
338
|
|
|
|
|
|
|
if ( $subclass->require ) { |
|
339
|
|
|
|
|
|
|
warn "Loaded external module for '$subclass'\n" if $class->debug > 1; |
|
340
|
|
|
|
|
|
|
} else { |
|
341
|
|
|
|
|
|
|
(my $filename = $subclass) =~ s!::!/!g; |
|
342
|
|
|
|
|
|
|
die "Loading '$subclass' failed: $@\n" |
|
343
|
|
|
|
|
|
|
unless $@ =~ /Can\'t locate \Q$filename\E\.pm/; |
|
344
|
|
|
|
|
|
|
warn "No external module for '$subclass'" |
|
345
|
|
|
|
|
|
|
if $class->debug > 1; |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=item init |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
Loads the view class and instantiates the view object. |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
You should not call this directly, but you may wish to override this to add |
|
354
|
|
|
|
|
|
|
application-specific initialisation - see L. |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=cut |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub init |
|
359
|
|
|
|
|
|
|
{ |
|
360
|
|
|
|
|
|
|
my $class = shift; |
|
361
|
|
|
|
|
|
|
my $config = $class->config; |
|
362
|
|
|
|
|
|
|
$config->view || $config->view("Maypole::View::TT"); |
|
363
|
|
|
|
|
|
|
$config->view->require; |
|
364
|
|
|
|
|
|
|
die "Couldn't load the view class " . $config->view . ": $@" if $@; |
|
365
|
|
|
|
|
|
|
$config->display_tables |
|
366
|
|
|
|
|
|
|
|| $config->display_tables( $class->config->tables ); |
|
367
|
|
|
|
|
|
|
$class->view_object( $class->config->view->new ); |
|
368
|
|
|
|
|
|
|
$class->init_done(1); |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=item new |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
Constructs a very minimal new Maypole request object. |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=cut |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub new |
|
378
|
|
|
|
|
|
|
{ |
|
379
|
|
|
|
|
|
|
my ($class) = @_; |
|
380
|
|
|
|
|
|
|
my $self = bless { |
|
381
|
|
|
|
|
|
|
config => $class->config, |
|
382
|
|
|
|
|
|
|
}, $class; |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
$self->stash({}); |
|
385
|
|
|
|
|
|
|
$self->params({}); |
|
386
|
|
|
|
|
|
|
$self->query({}); |
|
387
|
|
|
|
|
|
|
$self->template_args({}); |
|
388
|
|
|
|
|
|
|
$self->args([]); |
|
389
|
|
|
|
|
|
|
$self->objects([]); |
|
390
|
|
|
|
|
|
|
return $self; |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=item view_object |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Get/set the Maypole::View object |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=back |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head1 INSTANCE METHODS |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=head2 Workflow |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=over 4 |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=item handler |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
This method sets up the class if it's not done yet, sets some defaults and |
|
408
|
|
|
|
|
|
|
leaves the dirty work to C. |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=cut |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# handler() has a method attribute so that mod_perl will invoke |
|
413
|
|
|
|
|
|
|
# BeerDB->handler() as a method rather than a plain function |
|
414
|
|
|
|
|
|
|
# BeerDB::handler() and so this inherited implementation will be |
|
415
|
|
|
|
|
|
|
# found. See e.g. "Practical mod_perl" by Bekman & Cholet for |
|
416
|
|
|
|
|
|
|
# more information |
|
417
|
|
|
|
|
|
|
sub handler : method { |
|
418
|
|
|
|
|
|
|
# See Maypole::Workflow before trying to understand this. |
|
419
|
|
|
|
|
|
|
my ($class, $req) = @_; |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
$class->init unless $class->init_done; |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
my $self = $class->new; |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# initialise the request |
|
426
|
|
|
|
|
|
|
$self->headers_out(Maypole::Headers->new); |
|
427
|
|
|
|
|
|
|
$self->get_request($req); |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
$self->parse_location; |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# hook useful for declining static requests e.g. images, or perhaps for |
|
432
|
|
|
|
|
|
|
# sanitizing request parameters |
|
433
|
|
|
|
|
|
|
$self->status(Maypole::Constants::OK()); # set the default |
|
434
|
|
|
|
|
|
|
$self->__call_hook('start_request_hook'); |
|
435
|
|
|
|
|
|
|
return $self->status unless $self->status == Maypole::Constants::OK(); |
|
436
|
|
|
|
|
|
|
die "status undefined after start_request_hook()" unless defined |
|
437
|
|
|
|
|
|
|
$self->status; |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
my $session = $self->get_session; |
|
440
|
|
|
|
|
|
|
$self->session($self->{session} || $session); |
|
441
|
|
|
|
|
|
|
my $user = $self->get_user; |
|
442
|
|
|
|
|
|
|
$self->user($self->{user} || $user); |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
my $status = $self->handler_guts; |
|
445
|
|
|
|
|
|
|
return $status unless $status == OK; |
|
446
|
|
|
|
|
|
|
# TODO: require send_output to return a status code |
|
447
|
|
|
|
|
|
|
$self->send_output; |
|
448
|
|
|
|
|
|
|
return $status; |
|
449
|
|
|
|
|
|
|
} |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=item component |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Run Maypole sub-requests as a component of the request |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
[% request.component("/beer/view_as_component/20") %] |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Allows you to integrate the results of a Maypole request into an existing |
|
458
|
|
|
|
|
|
|
request. You'll need to set up actions and templates |
|
459
|
|
|
|
|
|
|
which return fragments of HTML rather than entire pages, but once you've |
|
460
|
|
|
|
|
|
|
done that, you can use the C method of the Maypole request object |
|
461
|
|
|
|
|
|
|
to call those actions. You may pass a query string in the usual URL style. |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
You should not fully qualify the Maypole URLs. |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
Note: any HTTP POST or URL parameters passed to the parent are not passed to the |
|
466
|
|
|
|
|
|
|
component sub-request, only what is included in the url passed as an argument |
|
467
|
|
|
|
|
|
|
to the method |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=cut |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
sub component { |
|
472
|
|
|
|
|
|
|
my ( $r, $path ) = @_; |
|
473
|
|
|
|
|
|
|
my $self = bless { parent => $r, config => $r->{config}, } , ref $r; |
|
474
|
|
|
|
|
|
|
$self->stash({}); |
|
475
|
|
|
|
|
|
|
$self->params({}); |
|
476
|
|
|
|
|
|
|
$self->query({}); |
|
477
|
|
|
|
|
|
|
$self->template_args({}); |
|
478
|
|
|
|
|
|
|
$self->args([]); |
|
479
|
|
|
|
|
|
|
$self->objects([]); |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
$self->session($self->get_session); |
|
482
|
|
|
|
|
|
|
$self->user($self->get_user); |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
my $url = URI->new($path); |
|
485
|
|
|
|
|
|
|
$self->{path} = $url->path; |
|
486
|
|
|
|
|
|
|
$self->parse_path; |
|
487
|
|
|
|
|
|
|
$self->params( $url->query_form_hash ); |
|
488
|
|
|
|
|
|
|
$self->handler_guts; |
|
489
|
|
|
|
|
|
|
return $self->output; |
|
490
|
|
|
|
|
|
|
} |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub get_template_root { |
|
493
|
|
|
|
|
|
|
my $self = shift; |
|
494
|
|
|
|
|
|
|
my $r = shift; |
|
495
|
|
|
|
|
|
|
return $r->parent->get_template_root if $r->{parent}; |
|
496
|
|
|
|
|
|
|
return $self->NEXT::DISTINCT::get_template_root( $r, @_ ); |
|
497
|
|
|
|
|
|
|
} |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub view_object { |
|
500
|
|
|
|
|
|
|
my $self = shift; |
|
501
|
|
|
|
|
|
|
my $r = shift; |
|
502
|
|
|
|
|
|
|
return $r->parent->view_object if $r->{parent}; |
|
503
|
|
|
|
|
|
|
return $self->NEXT::DISTINCT::view_object( $r, @_ ); |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
# Instead of making plugin authors use the NEXT::DISTINCT hoopla to ensure other |
|
507
|
|
|
|
|
|
|
# plugins also get to call the hook, we can cycle through the application's |
|
508
|
|
|
|
|
|
|
# @ISA and call them all here. Doesn't work for setup() though, because it's |
|
509
|
|
|
|
|
|
|
# too ingrained in the stack. We could add a run_setup() method, but we'd break |
|
510
|
|
|
|
|
|
|
# lots of existing code. |
|
511
|
|
|
|
|
|
|
sub __call_hook |
|
512
|
|
|
|
|
|
|
{ |
|
513
|
|
|
|
|
|
|
my ($self, $hook) = @_; |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
my @plugins; |
|
516
|
|
|
|
|
|
|
{ |
|
517
|
|
|
|
|
|
|
my $class = ref($self); |
|
518
|
|
|
|
|
|
|
no strict 'refs'; |
|
519
|
|
|
|
|
|
|
@plugins = @{"$class\::ISA"}; |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# this is either a custom method in the driver, or the method in the 1st |
|
523
|
|
|
|
|
|
|
# plugin, or the 'null' method in the frontend (i.e. inherited from |
|
524
|
|
|
|
|
|
|
# Maypole.pm) - we need to be careful to only call it once |
|
525
|
|
|
|
|
|
|
my $first_hook = $self->can($hook); |
|
526
|
|
|
|
|
|
|
$self->$first_hook; |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
my %seen = ( $first_hook => 1 ); |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
# @plugins includes the frontend |
|
531
|
|
|
|
|
|
|
foreach my $plugin (@plugins) |
|
532
|
|
|
|
|
|
|
{ |
|
533
|
|
|
|
|
|
|
next unless my $plugin_hook = $plugin->can($hook); |
|
534
|
|
|
|
|
|
|
next if $seen{$plugin_hook}++; |
|
535
|
|
|
|
|
|
|
$self->$plugin_hook; |
|
536
|
|
|
|
|
|
|
} |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=item handler_guts |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
This is the main request handling method and calls various methods to handle the |
|
542
|
|
|
|
|
|
|
request/response and defines the workflow within Maypole. |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=cut |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# The root of all evil |
|
547
|
|
|
|
|
|
|
sub handler_guts { |
|
548
|
|
|
|
|
|
|
my ($self) = @_; |
|
549
|
|
|
|
|
|
|
$self->build_form_elements(1) unless (defined ($self->config->build_form_elements) && $self->config->build_form_elements == 0); |
|
550
|
|
|
|
|
|
|
$self->__load_request_model; |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
my $applicable = $self->is_model_applicable == OK; |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
my $status; |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# handle authentication |
|
557
|
|
|
|
|
|
|
eval { $status = $self->call_authenticate }; |
|
558
|
|
|
|
|
|
|
if ( my $error = $@ ) { |
|
559
|
|
|
|
|
|
|
$status = $self->call_exception($error, "authentication"); |
|
560
|
|
|
|
|
|
|
if ( $status != OK ) { |
|
561
|
|
|
|
|
|
|
$self->warn("caught authenticate error: $error"); |
|
562
|
|
|
|
|
|
|
return $self->debug ? |
|
563
|
|
|
|
|
|
|
$self->view_object->error($self, $error) : ERROR; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
} |
|
566
|
|
|
|
|
|
|
if ( $self->debug and $status != OK and $status != DECLINED ) { |
|
567
|
|
|
|
|
|
|
$self->view_object->error( $self, |
|
568
|
|
|
|
|
|
|
"Got unexpected status $status from calling authentication" ); |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
return $status unless $status == OK; |
|
572
|
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
# We run additional_data for every request |
|
574
|
|
|
|
|
|
|
$self->additional_data; |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# process request with model if applicable and template not set. |
|
577
|
|
|
|
|
|
|
if ($applicable) { |
|
578
|
|
|
|
|
|
|
unless ($self->{template}) { |
|
579
|
|
|
|
|
|
|
eval { $self->model_class->process($self) }; |
|
580
|
|
|
|
|
|
|
if ( my $error = $@ ) { |
|
581
|
|
|
|
|
|
|
$status = $self->call_exception($error, "model"); |
|
582
|
|
|
|
|
|
|
if ( $status != OK ) { |
|
583
|
|
|
|
|
|
|
$self->warn("caught model error: $error"); |
|
584
|
|
|
|
|
|
|
return $self->debug ? |
|
585
|
|
|
|
|
|
|
$self->view_object->error($self, $error) : ERROR; |
|
586
|
|
|
|
|
|
|
} |
|
587
|
|
|
|
|
|
|
} |
|
588
|
|
|
|
|
|
|
} |
|
589
|
|
|
|
|
|
|
} else { |
|
590
|
|
|
|
|
|
|
$self->__setup_plain_template; |
|
591
|
|
|
|
|
|
|
} |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# less frequent path - perhaps output has been set to an error message |
|
594
|
|
|
|
|
|
|
if ($self->output) { |
|
595
|
|
|
|
|
|
|
$self->{content_type} ||= $self->__get_mime_type(); |
|
596
|
|
|
|
|
|
|
$self->{document_encoding} ||= "utf-8"; |
|
597
|
|
|
|
|
|
|
return OK; |
|
598
|
|
|
|
|
|
|
} |
|
599
|
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
# normal path - no output has been generated yet |
|
601
|
|
|
|
|
|
|
my $processed_view_ok = $self->__call_process_view; |
|
602
|
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
$self->{content_type} ||= $self->__get_mime_type(); |
|
604
|
|
|
|
|
|
|
$self->{document_encoding} ||= "utf-8"; |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
return $processed_view_ok; |
|
607
|
|
|
|
|
|
|
} |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
my %filetypes = ( |
|
610
|
|
|
|
|
|
|
'js' => 'text/javascript', |
|
611
|
|
|
|
|
|
|
'css' => 'text/css', |
|
612
|
|
|
|
|
|
|
'htm' => 'text/html', |
|
613
|
|
|
|
|
|
|
'html' => 'text/html', |
|
614
|
|
|
|
|
|
|
); |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
sub __get_mime_type { |
|
617
|
|
|
|
|
|
|
my $self = shift; |
|
618
|
|
|
|
|
|
|
my $type = 'text/html'; |
|
619
|
|
|
|
|
|
|
if ($self->path =~ m/.*\.(\w{2,4})$/) { |
|
620
|
|
|
|
|
|
|
$type = $filetypes{$1}; |
|
621
|
|
|
|
|
|
|
} else { |
|
622
|
|
|
|
|
|
|
my $output = $self->output; |
|
623
|
|
|
|
|
|
|
if (defined $output) { |
|
624
|
|
|
|
|
|
|
$type = $mmagic->checktype_contents($output); |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
return $type; |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
sub __load_request_model |
|
631
|
|
|
|
|
|
|
{ |
|
632
|
|
|
|
|
|
|
my ($self) = @_; |
|
633
|
|
|
|
|
|
|
# We may get a made up class from class_of |
|
634
|
|
|
|
|
|
|
my $mclass = $self->config->model->class_of($self, $self->table); |
|
635
|
|
|
|
|
|
|
if ( eval {$mclass->isa('Maypole::Model::Base')} ) { |
|
636
|
|
|
|
|
|
|
$self->model_class( $mclass ); |
|
637
|
|
|
|
|
|
|
} |
|
638
|
|
|
|
|
|
|
elsif ($self->debug > 1) { |
|
639
|
|
|
|
|
|
|
$self->warn("***Warning: No $mclass class appropriate for model. @_"); |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
# is_applicable() returned false, so set up a plain template. Model processing |
|
645
|
|
|
|
|
|
|
# will be skipped, but need to remove the model anyway so the template can't |
|
646
|
|
|
|
|
|
|
# access it. |
|
647
|
|
|
|
|
|
|
sub __setup_plain_template |
|
648
|
|
|
|
|
|
|
{ |
|
649
|
|
|
|
|
|
|
my ($self) = @_; |
|
650
|
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# It's just a plain template |
|
652
|
|
|
|
|
|
|
$self->build_form_elements(0); |
|
653
|
|
|
|
|
|
|
$self->model_class(undef); |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
unless ($self->template) { |
|
656
|
|
|
|
|
|
|
# FIXME: this is likely to be redundant and is definately causing problems. |
|
657
|
|
|
|
|
|
|
my $path = $self->path; |
|
658
|
|
|
|
|
|
|
$path =~ s{/$}{}; # De-absolutify |
|
659
|
|
|
|
|
|
|
$self->path($path); |
|
660
|
|
|
|
|
|
|
$self->template($self->path); |
|
661
|
|
|
|
|
|
|
} |
|
662
|
|
|
|
|
|
|
} |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
# The model has been processed or skipped (if is_applicable returned false), |
|
665
|
|
|
|
|
|
|
# any exceptions have been handled, and there's no content in $self->output |
|
666
|
|
|
|
|
|
|
sub __call_process_view { |
|
667
|
|
|
|
|
|
|
my ($self) = @_; |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
my $status = eval { $self->view_object->process($self) }; |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
my $error = $@ || $self->{error}; |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
if ( $error ) { |
|
674
|
|
|
|
|
|
|
$status = $self->call_exception($error, "view"); |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
if ( $status != OK ) { |
|
677
|
|
|
|
|
|
|
warn "caught view error: $error" if $self->debug; |
|
678
|
|
|
|
|
|
|
return $self->debug ? |
|
679
|
|
|
|
|
|
|
$self->view_object->error($self, $error) : ERROR; |
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
return $status; |
|
684
|
|
|
|
|
|
|
} |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=item warn |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
$r->warn('its all gone pete tong'); |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
Warn must be implemented by the backend, i.e. Apache::MVC |
|
691
|
|
|
|
|
|
|
and warn to stderr or appropriate logfile. |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
You can also over-ride this in your Maypole driver, should you |
|
694
|
|
|
|
|
|
|
want to use something like Log::Log4perl instead. |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=cut |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
sub warn { } |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=item build_form_elements |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
$r->build_form_elements(0); |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
Specify (in an action) whether to build HTML form elements and populate |
|
705
|
|
|
|
|
|
|
the cgi element of classmetadata in the view. |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
You can set this globally using the accessor of the same name in Maypole::Config, |
|
708
|
|
|
|
|
|
|
this method allows you to over-ride that setting per action. |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=cut |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=item get_request |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
You should only need to define this method if you are writing a new |
|
715
|
|
|
|
|
|
|
Maypole backend. It should return something that looks like an Apache |
|
716
|
|
|
|
|
|
|
or CGI request object, it defaults to blank. |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=cut |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub get_request { } |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=item parse_location |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
Turns the backend request (e.g. Apache::MVC, Maypole, CGI) into a Maypole |
|
725
|
|
|
|
|
|
|
request. It does this by setting the C, and invoking C and |
|
726
|
|
|
|
|
|
|
C. |
|
727
|
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
You should only need to define this method if you are writing a new Maypole |
|
729
|
|
|
|
|
|
|
backend. |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=cut |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
sub parse_location |
|
734
|
|
|
|
|
|
|
{ |
|
735
|
|
|
|
|
|
|
die "parse_location is a virtual method. Do not use Maypole directly; " . |
|
736
|
|
|
|
|
|
|
"use Apache::MVC or similar"; |
|
737
|
|
|
|
|
|
|
} |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=item start_request_hook |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
This is called immediately after setting up the basic request. The default |
|
742
|
|
|
|
|
|
|
method does nothing. |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
The value of C<< $r->status >> is set to C before this hook is run. Your |
|
745
|
|
|
|
|
|
|
implementation can change the status code, or leave it alone. |
|
746
|
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
After this hook has run, Maypole will check the value of C. For any |
|
748
|
|
|
|
|
|
|
value other than C, Maypole returns the C immediately. |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
This is useful for filtering out requests for static files, e.g. images, which |
|
751
|
|
|
|
|
|
|
should not be processed by Maypole or by the templating engine: |
|
752
|
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
sub start_request_hook |
|
754
|
|
|
|
|
|
|
{ |
|
755
|
|
|
|
|
|
|
my ($r) = @_; |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
$r->status(DECLINED) if $r->path =~ /\.jpg$/; |
|
758
|
|
|
|
|
|
|
} |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
Multiple plugins, and the driver, can define this hook - Maypole will call all |
|
761
|
|
|
|
|
|
|
of them. You should check for and probably not change any non-OK C |
|
762
|
|
|
|
|
|
|
value: |
|
763
|
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
package Maypole::Plugin::MyApp::SkipFavicon; |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
sub start_request_hook |
|
767
|
|
|
|
|
|
|
{ |
|
768
|
|
|
|
|
|
|
my ($r) = @_; |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
# check if a previous plugin has already DECLINED this request |
|
771
|
|
|
|
|
|
|
# - probably unnecessary in this example, but you get the idea |
|
772
|
|
|
|
|
|
|
return unless $r->status == OK; |
|
773
|
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
# then do our stuff |
|
775
|
|
|
|
|
|
|
$r->status(DECLINED) if $r->path =~ /favicon\.ico/; |
|
776
|
|
|
|
|
|
|
} |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
=cut |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
sub start_request_hook { } |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=item is_applicable |
|
783
|
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
B as of version 2.11. If you have overridden it, |
|
785
|
|
|
|
|
|
|
please override C instead, and change the return type |
|
786
|
|
|
|
|
|
|
from a Maypole:Constant to a true/false value. |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
Returns a Maypole::Constant to indicate whether the request is valid. |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=cut |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
sub is_applicable { return shift->is_model_applicable(@_); } |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
=item is_model_applicable |
|
795
|
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
Returns true or false to indicate whether the request is valid. |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
The default implementation checks that C<< $r->table >> is publicly |
|
799
|
|
|
|
|
|
|
accessible and that the model class is configured to handle the |
|
800
|
|
|
|
|
|
|
C<< $r->action >>. |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
=cut |
|
803
|
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
sub is_model_applicable { |
|
805
|
|
|
|
|
|
|
my ($self) = @_; |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
# Establish which tables should be processed by the model |
|
808
|
|
|
|
|
|
|
my $config = $self->config; |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
$config->ok_tables || $config->ok_tables( $config->display_tables ); |
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
$config->ok_tables( { map { $_ => 1 } @{ $config->ok_tables } } ) |
|
813
|
|
|
|
|
|
|
if ref $config->ok_tables eq "ARRAY"; |
|
814
|
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
my $ok_tables = $config->ok_tables; |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
# Does this request concern a table to be processed by the model? |
|
818
|
|
|
|
|
|
|
my $table = $self->table; |
|
819
|
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
my $ok = 0; |
|
821
|
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
if (exists $ok_tables->{$table}) |
|
823
|
|
|
|
|
|
|
{ |
|
824
|
|
|
|
|
|
|
$ok = 1; |
|
825
|
|
|
|
|
|
|
} |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
if (not $ok) |
|
828
|
|
|
|
|
|
|
{ |
|
829
|
|
|
|
|
|
|
$self->warn ("We don't have that table ($table).\n" |
|
830
|
|
|
|
|
|
|
. "Available tables are: " |
|
831
|
|
|
|
|
|
|
. join( ",", keys %$ok_tables )) |
|
832
|
|
|
|
|
|
|
if $self->debug and not $ok_tables->{$table}; |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
return DECLINED; |
|
835
|
|
|
|
|
|
|
} |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# Is the action public? |
|
838
|
|
|
|
|
|
|
my $action = $self->action; |
|
839
|
|
|
|
|
|
|
return OK if $self->model_class->is_public($action); |
|
840
|
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
$self->warn("The action '$action' is not applicable to the table '$table'") |
|
842
|
|
|
|
|
|
|
if $self->debug; |
|
843
|
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
return DECLINED; |
|
845
|
|
|
|
|
|
|
} |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=item get_session |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
Called immediately after C. |
|
850
|
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
This method should return a session, which will be stored in the request's |
|
852
|
|
|
|
|
|
|
C attribute. |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
The default method is empty. |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
=cut |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
sub get_session { } |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=item get_user |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
Called immediately after C. |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
This method should return a user, which will be stored in the request's C |
|
865
|
|
|
|
|
|
|
attribute. |
|
866
|
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
The default method is empty. |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
=cut |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
sub get_user {} |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
=item call_authenticate |
|
874
|
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
This method first checks if the relevant model class |
|
876
|
|
|
|
|
|
|
can authenticate the user, or falls back to the default |
|
877
|
|
|
|
|
|
|
authenticate method of your Maypole application. |
|
878
|
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
=cut |
|
880
|
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
sub call_authenticate |
|
882
|
|
|
|
|
|
|
{ |
|
883
|
|
|
|
|
|
|
my ($self) = @_; |
|
884
|
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
# Check if we have a model class with an authenticate() to delegate to |
|
886
|
|
|
|
|
|
|
return $self->model_class->authenticate($self) |
|
887
|
|
|
|
|
|
|
if $self->model_class and $self->model_class->can('authenticate'); |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
# Interface consistency is a Good Thing - |
|
890
|
|
|
|
|
|
|
# the invocant and the argument may one day be different things |
|
891
|
|
|
|
|
|
|
# (i.e. controller and request), like they are when authenticate() |
|
892
|
|
|
|
|
|
|
# is called on a model class (i.e. model and request) |
|
893
|
|
|
|
|
|
|
return $self->authenticate($self); |
|
894
|
|
|
|
|
|
|
} |
|
895
|
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
=item authenticate |
|
897
|
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
Returns a Maypole::Constant to indicate whether the user is authenticated for |
|
899
|
|
|
|
|
|
|
the Maypole request. |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
The default implementation returns C |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
=cut |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
sub authenticate { return OK } |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
=item call_exception |
|
909
|
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
This model is called to catch exceptions, first after authenticate, then after |
|
911
|
|
|
|
|
|
|
processing the model class, and finally to check for exceptions from the view |
|
912
|
|
|
|
|
|
|
class. |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
This method first checks if the relevant model class |
|
915
|
|
|
|
|
|
|
can handle exceptions the user, or falls back to the default |
|
916
|
|
|
|
|
|
|
exception method of your Maypole application. |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
=cut |
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
sub call_exception |
|
921
|
|
|
|
|
|
|
{ |
|
922
|
|
|
|
|
|
|
my ($self, $error, $when) = @_; |
|
923
|
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
# Check if we have a model class with an exception() to delegate to |
|
925
|
|
|
|
|
|
|
if ( $self->model_class && $self->model_class->can('exception') ) |
|
926
|
|
|
|
|
|
|
{ |
|
927
|
|
|
|
|
|
|
my $status = $self->model_class->exception( $self, $error, $when ); |
|
928
|
|
|
|
|
|
|
return $status if $status == OK; |
|
929
|
|
|
|
|
|
|
} |
|
930
|
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
return $self->exception($error, $when); |
|
932
|
|
|
|
|
|
|
} |
|
933
|
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
=item exception |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
This method is called if any exceptions are raised during the authentication or |
|
938
|
|
|
|
|
|
|
model/view processing. It should accept the exception as a parameter and return |
|
939
|
|
|
|
|
|
|
a Maypole::Constant to indicate whether the request should continue to be |
|
940
|
|
|
|
|
|
|
processed. |
|
941
|
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
=cut |
|
943
|
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
sub exception { |
|
945
|
|
|
|
|
|
|
my ($self, $error, $when) = @_; |
|
946
|
|
|
|
|
|
|
if (ref $self->view_object && $self->view_object->can("report_error") and $self->debug) { |
|
947
|
|
|
|
|
|
|
$self->view_object->report_error($self, $error, $when); |
|
948
|
|
|
|
|
|
|
return OK; |
|
949
|
|
|
|
|
|
|
} |
|
950
|
|
|
|
|
|
|
return ERROR; |
|
951
|
|
|
|
|
|
|
} |
|
952
|
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
=item additional_data |
|
954
|
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
Called before the model processes the request, this method gives you a chance to |
|
956
|
|
|
|
|
|
|
do some processing for each request, for example, manipulating C. |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=cut |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
sub additional_data { } |
|
961
|
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
=item send_output |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
Sends the output and additional headers to the user. |
|
965
|
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=cut |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
sub send_output { |
|
969
|
|
|
|
|
|
|
die "send_output is a virtual method. Do not use Maypole directly; use Apache::MVC or similar"; |
|
970
|
|
|
|
|
|
|
} |
|
971
|
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=back |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=head2 Path processing and manipulation |
|
976
|
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
=over 4 |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=item path |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
Returns the request path |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=item parse_path |
|
984
|
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
Parses the request path and sets the C, C and C
|
986
|
|
|
|
|
|
|
properties. Calls C before parsing path and setting properties. |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
=cut |
|
989
|
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
sub parse_path { |
|
991
|
|
|
|
|
|
|
my ($self) = @_; |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
# Previous versions unconditionally set table, action and args to whatever |
|
994
|
|
|
|
|
|
|
# was in @pi (or else to defaults, if @pi is empty). |
|
995
|
|
|
|
|
|
|
# Adding preprocess_path(), and then setting table, action and args |
|
996
|
|
|
|
|
|
|
# conditionally, broke lots of tests, hence this: |
|
997
|
|
|
|
|
|
|
$self->$_(undef) for qw/action table args/; |
|
998
|
|
|
|
|
|
|
$self->preprocess_path; |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
# use frontpage template for frontpage |
|
1001
|
|
|
|
|
|
|
unless ($self->path && $self->path ne '/') { |
|
1002
|
|
|
|
|
|
|
$self->path('frontpage'); |
|
1003
|
|
|
|
|
|
|
} |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
my @pi = grep {length} split '/', $self->path; |
|
1006
|
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
$self->table || $self->table(shift @pi); |
|
1008
|
|
|
|
|
|
|
$self->action || $self->action( shift @pi or 'index' ); |
|
1009
|
|
|
|
|
|
|
$self->args || $self->args(\@pi); |
|
1010
|
|
|
|
|
|
|
} |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
=item preprocess_path |
|
1013
|
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
Sometimes when you don't want to rewrite or over-ride parse_path but |
|
1015
|
|
|
|
|
|
|
want to rewrite urls or extract data from them before it is parsed, |
|
1016
|
|
|
|
|
|
|
the preprocess_path/location methods allow you to munge paths and urls |
|
1017
|
|
|
|
|
|
|
before maypole maps them to actions, classes, etc. |
|
1018
|
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
This method is called after parse_location has populated the request |
|
1020
|
|
|
|
|
|
|
information and before parse_path has populated the model and action |
|
1021
|
|
|
|
|
|
|
information, and is passed the request object. |
|
1022
|
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
You can set action, args or table in this method and parse_path will |
|
1024
|
|
|
|
|
|
|
then leave those values in place or populate them based on the current |
|
1025
|
|
|
|
|
|
|
value of the path attribute if they are not present. |
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
=cut |
|
1028
|
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
sub preprocess_path { }; |
|
1030
|
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
=item preprocess_location |
|
1032
|
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
This method is called at the start of parse_location, after the headers in, and allows you |
|
1034
|
|
|
|
|
|
|
to rewrite the url used by maypole, or dynamically set configuration |
|
1035
|
|
|
|
|
|
|
like the base_uri based on the hostname or path. |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
=cut |
|
1038
|
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
sub preprocess_location { }; |
|
1040
|
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
=item make_path( %args or \%args or @args ) |
|
1042
|
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
This is the counterpart to C. It generates a path to use |
|
1044
|
|
|
|
|
|
|
in links, form actions etc. To implement your own path scheme, just override |
|
1045
|
|
|
|
|
|
|
this method and C. |
|
1046
|
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
%args = ( table => $table, |
|
1048
|
|
|
|
|
|
|
action => $action, |
|
1049
|
|
|
|
|
|
|
additional => $additional, # optional - generally an object ID |
|
1050
|
|
|
|
|
|
|
); |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
\%args = as above, but a ref |
|
1053
|
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
@args = ( $table, $action, $additional ); # $additional is optional |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
C can be used as an alternative key to C. |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
C<$additional> can be a string, an arrayref, or a hashref. An arrayref is |
|
1059
|
|
|
|
|
|
|
expanded into extra path elements, whereas a hashref is translated into a query |
|
1060
|
|
|
|
|
|
|
string. |
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
=cut |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
sub make_path |
|
1066
|
|
|
|
|
|
|
{ |
|
1067
|
|
|
|
|
|
|
my $r = shift; |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
my %args; |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
if (@_ == 1 and ref $_[0] and ref $_[0] eq 'HASH') |
|
1072
|
|
|
|
|
|
|
{ |
|
1073
|
|
|
|
|
|
|
%args = %{$_[0]}; |
|
1074
|
|
|
|
|
|
|
} |
|
1075
|
|
|
|
|
|
|
elsif ( @_ > 1 and @_ < 4 ) |
|
1076
|
|
|
|
|
|
|
{ |
|
1077
|
|
|
|
|
|
|
$args{table} = shift; |
|
1078
|
|
|
|
|
|
|
$args{action} = shift; |
|
1079
|
|
|
|
|
|
|
$args{additional} = shift; |
|
1080
|
|
|
|
|
|
|
} |
|
1081
|
|
|
|
|
|
|
else |
|
1082
|
|
|
|
|
|
|
{ |
|
1083
|
|
|
|
|
|
|
%args = @_; |
|
1084
|
|
|
|
|
|
|
} |
|
1085
|
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
do { die "no $_" unless $args{$_} } for qw( table action ); |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
|
|
|
|
|
|
my $additional = $args{additional} || $args{id}; |
|
1089
|
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
my @add = (); |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
if ($additional) |
|
1093
|
|
|
|
|
|
|
{ |
|
1094
|
|
|
|
|
|
|
# if $additional is a href, make_uri() will transform it into a query |
|
1095
|
|
|
|
|
|
|
@add = (ref $additional eq 'ARRAY') ? @$additional : ($additional); |
|
1096
|
|
|
|
|
|
|
} |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
my $uri = $r->make_uri($args{table}, $args{action}, @add); |
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
return $uri->as_string; |
|
1101
|
|
|
|
|
|
|
} |
|
1102
|
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
=item make_uri( @segments ) |
|
1106
|
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
Make a L object given table, action etc. Automatically adds |
|
1108
|
|
|
|
|
|
|
the C. |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
If the final element in C<@segments> is a hash ref, C will render it |
|
1111
|
|
|
|
|
|
|
as a query string. |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
=cut |
|
1114
|
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
sub make_uri |
|
1116
|
|
|
|
|
|
|
{ |
|
1117
|
|
|
|
|
|
|
my ($r, @segments) = @_; |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
my $query = (ref $segments[-1] eq 'HASH') ? pop(@segments) : undef; |
|
1120
|
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
my $base = $r->config->uri_base; |
|
1122
|
|
|
|
|
|
|
$base =~ s|/$||; |
|
1123
|
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
my $uri = URI->new($base); |
|
1125
|
|
|
|
|
|
|
$uri->path_segments($uri->path_segments, grep {length} @segments); |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
my $abs_uri = $uri->abs('/'); |
|
1128
|
|
|
|
|
|
|
$abs_uri->query_form($query) if $query; |
|
1129
|
|
|
|
|
|
|
return $abs_uri; |
|
1130
|
|
|
|
|
|
|
} |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
=item parse_args |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
Turns post data and query string paramaters into a hash of C. |
|
1135
|
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
You should only need to define this method if you are writing a new Maypole |
|
1137
|
|
|
|
|
|
|
backend. |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
=cut |
|
1140
|
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
sub parse_args |
|
1142
|
|
|
|
|
|
|
{ |
|
1143
|
|
|
|
|
|
|
die "parse_args() is a virtual method. Do not use Maypole directly; ". |
|
1144
|
|
|
|
|
|
|
"use Apache::MVC or similar"; |
|
1145
|
|
|
|
|
|
|
} |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
=item get_template_root |
|
1148
|
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
Implementation-specific path to template root. |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
You should only need to define this method if you are writing a new Maypole |
|
1152
|
|
|
|
|
|
|
backend. Otherwise, see L |
|
1153
|
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
=cut |
|
1155
|
|
|
|
|
|
|
|
|
1156
|
|
|
|
|
|
|
=back |
|
1157
|
|
|
|
|
|
|
|
|
1158
|
|
|
|
|
|
|
=head2 Request properties |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
=over 4 |
|
1161
|
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
=item model_class |
|
1163
|
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
Returns the perl package name that will serve as the model for the |
|
1165
|
|
|
|
|
|
|
request. It corresponds to the request C attribute.
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
=item objects |
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
Get/set a list of model objects. The objects will be accessible in the view |
|
1171
|
|
|
|
|
|
|
templates. |
|
1172
|
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
If the first item in C<$self-Eargs> can be Cd by the model |
|
1174
|
|
|
|
|
|
|
class, it will be removed from C and the retrieved object will be added to |
|
1175
|
|
|
|
|
|
|
the C list. See L for more information. |
|
1176
|
|
|
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
=item object |
|
1179
|
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
Alias to get/set the first/only model object. The object will be accessible |
|
1181
|
|
|
|
|
|
|
in the view templates. |
|
1182
|
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
When used to set the object, will overwrite the request objects |
|
1184
|
|
|
|
|
|
|
with a single object. |
|
1185
|
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
=cut |
|
1187
|
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
sub object { |
|
1189
|
|
|
|
|
|
|
my ($r,$object) = @_; |
|
1190
|
|
|
|
|
|
|
$r->objects([$object]) if ($object); |
|
1191
|
|
|
|
|
|
|
return undef unless $r->objects(); |
|
1192
|
|
|
|
|
|
|
return $r->objects->[0]; |
|
1193
|
|
|
|
|
|
|
} |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
=item template_args |
|
1196
|
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
$self->template_args->{foo} = 'bar'; |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
Get/set a hash of template variables. |
|
1200
|
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
Maypole reserved words for template variables will over-ride values in template_variables. |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
Reserved words are : r, request, object, objects, base, config and errors, as well as the |
|
1204
|
|
|
|
|
|
|
current class or object name. |
|
1205
|
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
=item stash |
|
1207
|
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
A place to put custom application data. Not used by Maypole itself. |
|
1209
|
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=item template |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
Get/set the template to be used by the view. By default, it returns |
|
1213
|
|
|
|
|
|
|
C<$self-Eaction> |
|
1214
|
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
=item error |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
Get/set a request error |
|
1219
|
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
=item output |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
Get/set the response output. This is usually populated by the view class. You |
|
1223
|
|
|
|
|
|
|
can skip view processing by setting the C |
|
1224
|
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
=item table |
|
1226
|
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
The table part of the Maypole request path |
|
1228
|
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
=item action |
|
1230
|
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
The action part of the Maypole request path |
|
1232
|
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
=item args |
|
1234
|
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
A list of remaining parts of the request path after table and action |
|
1236
|
|
|
|
|
|
|
have been |
|
1237
|
|
|
|
|
|
|
removed |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
=item headers_in |
|
1240
|
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
A L object containing HTTP headers for the request |
|
1242
|
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
=item headers_out |
|
1244
|
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
A L object that contains HTTP headers for the output |
|
1246
|
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
=item document_encoding |
|
1248
|
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
Get/set the output encoding. Default: utf-8. |
|
1250
|
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
=item content_type |
|
1252
|
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
Get/set the output content type. Default: text/html |
|
1254
|
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
=item get_protocol |
|
1256
|
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
Returns the protocol the request was made with, i.e. https |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
=cut |
|
1260
|
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
sub get_protocol { |
|
1262
|
|
|
|
|
|
|
die "get_protocol is a virtual method. Do not use Maypole directly; use Apache::MVC or similar"; |
|
1263
|
|
|
|
|
|
|
} |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
=back |
|
1266
|
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
=head2 Request parameters |
|
1268
|
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
The source of the parameters may vary depending on the Maypole backend, but they |
|
1270
|
|
|
|
|
|
|
are usually populated from request query string and POST data. |
|
1271
|
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
Maypole supplies several approaches for accessing the request parameters. Note |
|
1273
|
|
|
|
|
|
|
that the current implementation (via a hashref) of C and C is |
|
1274
|
|
|
|
|
|
|
likely to change in a future version of Maypole. So avoid direct access to these |
|
1275
|
|
|
|
|
|
|
hashrefs: |
|
1276
|
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
$r->{params}->{foo} # bad |
|
1278
|
|
|
|
|
|
|
$r->params->{foo} # better |
|
1279
|
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
$r->{query}->{foo} # bad |
|
1281
|
|
|
|
|
|
|
$r->query->{foo} # better |
|
1282
|
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
$r->param('foo') # best |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
=over 4 |
|
1286
|
|
|
|
|
|
|
|
|
1287
|
|
|
|
|
|
|
=item param |
|
1288
|
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
An accessor (get or set) for request parameters. It behaves similarly to |
|
1290
|
|
|
|
|
|
|
CGI::param() for accessing CGI parameters, i.e. |
|
1291
|
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
$r->param # returns list of keys |
|
1293
|
|
|
|
|
|
|
$r->param($key) # returns value for $key |
|
1294
|
|
|
|
|
|
|
$r->param($key => $value) # returns old value, sets to new value |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
=cut |
|
1297
|
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
sub param |
|
1299
|
|
|
|
|
|
|
{ |
|
1300
|
|
|
|
|
|
|
my ($self, $key) = (shift, shift); |
|
1301
|
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
return keys %{$self->params} unless defined $key; |
|
1303
|
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
return unless exists $self->params->{$key}; |
|
1305
|
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
my $val = $self->params->{$key}; |
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
if (@_) |
|
1309
|
|
|
|
|
|
|
{ |
|
1310
|
|
|
|
|
|
|
my $new_val = shift; |
|
1311
|
|
|
|
|
|
|
$self->params->{$key} = $new_val; |
|
1312
|
|
|
|
|
|
|
} |
|
1313
|
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
return (ref $val eq 'ARRAY') ? @$val : ($val) if wantarray; |
|
1315
|
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
return (ref $val eq 'ARRAY') ? $val->[0] : $val; |
|
1317
|
|
|
|
|
|
|
} |
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
=item params |
|
1321
|
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
Returns a hashref of request parameters. |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
B Where muliple values of a parameter were supplied, the C value |
|
1325
|
|
|
|
|
|
|
will be an array reference. |
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
=item query |
|
1328
|
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
Alias for C. |
|
1330
|
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
=back |
|
1332
|
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
=head3 Utility methods |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
=over 4 |
|
1336
|
|
|
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
=item redirect_request |
|
1338
|
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
Sets output headers to redirect based on the arguments provided |
|
1340
|
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
Accepts either a single argument of the full url to redirect to, or a hash of |
|
1342
|
|
|
|
|
|
|
named parameters : |
|
1343
|
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
$r->redirect_request('http://www.example.com/path'); |
|
1345
|
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
or |
|
1347
|
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
$r->redirect_request(protocol=>'https', domain=>'www.example.com', path=>'/path/file?arguments', status=>'302', url=>'..'); |
|
1349
|
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
The named parameters are protocol, domain, path, status and url |
|
1351
|
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
Only 1 named parameter is required but other than url, they can be combined as |
|
1353
|
|
|
|
|
|
|
required and current values (from the request) will be used in place of any |
|
1354
|
|
|
|
|
|
|
missing arguments. The url argument must be a full url including protocol and |
|
1355
|
|
|
|
|
|
|
can only be combined with status. |
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=cut |
|
1358
|
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
sub redirect_request { |
|
1360
|
|
|
|
|
|
|
die "redirect_request is a virtual method. Do not use Maypole directly; use Apache::MVC or similar"; |
|
1361
|
|
|
|
|
|
|
} |
|
1362
|
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
# =item redirect_internal_request |
|
1364
|
|
|
|
|
|
|
# |
|
1365
|
|
|
|
|
|
|
# =cut |
|
1366
|
|
|
|
|
|
|
# |
|
1367
|
|
|
|
|
|
|
# sub redirect_internal_request { |
|
1368
|
|
|
|
|
|
|
# |
|
1369
|
|
|
|
|
|
|
# } |
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
=item make_random_id |
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
returns a unique id for this request can be used to prevent or detect repeat |
|
1375
|
|
|
|
|
|
|
submissions. |
|
1376
|
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
=cut |
|
1378
|
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
# Session and Repeat Submission Handling |
|
1380
|
|
|
|
|
|
|
sub make_random_id { |
|
1381
|
|
|
|
|
|
|
use Maypole::Session; |
|
1382
|
|
|
|
|
|
|
return Maypole::Session::generate_unique_id(); |
|
1383
|
|
|
|
|
|
|
} |
|
1384
|
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
=back |
|
1386
|
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
=head1 SEQUENCE DIAGRAMS |
|
1388
|
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
See L for a detailed discussion of the sequence of |
|
1390
|
|
|
|
|
|
|
calls during processing of a request. This is a brief summary: |
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
INITIALIZATION |
|
1393
|
|
|
|
|
|
|
Model e.g. |
|
1394
|
|
|
|
|
|
|
BeerDB Maypole::Model::CDBI |
|
1395
|
|
|
|
|
|
|
| | |
|
1396
|
|
|
|
|
|
|
setup | | |
|
1397
|
|
|
|
|
|
|
o-------->|| | |
|
1398
|
|
|
|
|
|
|
|| setup_model | setup_database() creates |
|
1399
|
|
|
|
|
|
|
||------+ | a subclass of the Model |
|
1400
|
|
|
|
|
|
|
|||<----+ | for each table |
|
1401
|
|
|
|
|
|
|
||| | | |
|
1402
|
|
|
|
|
|
|
||| setup_database | | |
|
1403
|
|
|
|
|
|
|
|||--------------------->|| 'create' * |
|
1404
|
|
|
|
|
|
|
||| ||----------> $subclass |
|
1405
|
|
|
|
|
|
|
||| | | |
|
1406
|
|
|
|
|
|
|
||| load_model_subclass | | |
|
1407
|
|
|
|
|
|
|
foreach |||------+ ($subclass) | | |
|
1408
|
|
|
|
|
|
|
$subclass ||||<----+ | require | |
|
1409
|
|
|
|
|
|
|
||||--------------------------------------->| |
|
1410
|
|
|
|
|
|
|
||| | | |
|
1411
|
|
|
|
|
|
|
||| adopt($subclass) | | |
|
1412
|
|
|
|
|
|
|
|||--------------------->|| | |
|
1413
|
|
|
|
|
|
|
| | | |
|
1414
|
|
|
|
|
|
|
| | | |
|
1415
|
|
|
|
|
|
|
|-----+ init | | |
|
1416
|
|
|
|
|
|
|
||<---+ | | |
|
1417
|
|
|
|
|
|
|
|| | new | view_object: e.g. |
|
1418
|
|
|
|
|
|
|
||---------------------------------------------> Maypole::View::TT |
|
1419
|
|
|
|
|
|
|
| | | | |
|
1420
|
|
|
|
|
|
|
| | | | |
|
1421
|
|
|
|
|
|
|
| | | | |
|
1422
|
|
|
|
|
|
|
| | | | |
|
1423
|
|
|
|
|
|
|
| | | | |
|
1424
|
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
|
|
1427
|
|
|
|
|
|
|
HANDLING A REQUEST |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
BeerDB Model $subclass view_object |
|
1431
|
|
|
|
|
|
|
| | | | |
|
1432
|
|
|
|
|
|
|
handler | | | | |
|
1433
|
|
|
|
|
|
|
o-------->| new | | | |
|
1434
|
|
|
|
|
|
|
|-----> r:BeerDB | | | |
|
1435
|
|
|
|
|
|
|
| | | | | |
|
1436
|
|
|
|
|
|
|
| | | | | |
|
1437
|
|
|
|
|
|
|
| || | | | |
|
1438
|
|
|
|
|
|
|
| ||-----+ parse_location | | | |
|
1439
|
|
|
|
|
|
|
| |||<---+ | | | |
|
1440
|
|
|
|
|
|
|
| || | | | |
|
1441
|
|
|
|
|
|
|
| ||-----+ start_request_hook | | | |
|
1442
|
|
|
|
|
|
|
| |||<---+ | | | |
|
1443
|
|
|
|
|
|
|
| || | | | |
|
1444
|
|
|
|
|
|
|
| ||-----+ get_session | | | |
|
1445
|
|
|
|
|
|
|
| |||<---+ | | | |
|
1446
|
|
|
|
|
|
|
| || | | | |
|
1447
|
|
|
|
|
|
|
| ||-----+ get_user | | | |
|
1448
|
|
|
|
|
|
|
| |||<---+ | | | |
|
1449
|
|
|
|
|
|
|
| || | | | |
|
1450
|
|
|
|
|
|
|
| ||-----+ handler_guts | | | |
|
1451
|
|
|
|
|
|
|
| |||<---+ | | | |
|
1452
|
|
|
|
|
|
|
| ||| class_of($table) | | | |
|
1453
|
|
|
|
|
|
|
| |||------------------------->|| | | |
|
1454
|
|
|
|
|
|
|
| ||| $subclass || | | |
|
1455
|
|
|
|
|
|
|
| |||<-------------------------|| | | |
|
1456
|
|
|
|
|
|
|
| ||| | | | |
|
1457
|
|
|
|
|
|
|
| |||-----+ is_model_applicable| | | |
|
1458
|
|
|
|
|
|
|
| ||||<---+ | | | |
|
1459
|
|
|
|
|
|
|
| ||| | | | |
|
1460
|
|
|
|
|
|
|
| |||-----+ call_authenticate | | | |
|
1461
|
|
|
|
|
|
|
| ||||<---+ | | | |
|
1462
|
|
|
|
|
|
|
| ||| | | | |
|
1463
|
|
|
|
|
|
|
| |||-----+ additional_data | | | |
|
1464
|
|
|
|
|
|
|
| ||||<---+ | | | |
|
1465
|
|
|
|
|
|
|
| ||| process | | | |
|
1466
|
|
|
|
|
|
|
| |||--------------------------------->|| fetch_objects |
|
1467
|
|
|
|
|
|
|
| ||| | ||-----+ | |
|
1468
|
|
|
|
|
|
|
| ||| | |||<---+ | |
|
1469
|
|
|
|
|
|
|
| ||| | || | |
|
1470
|
|
|
|
|
|
|
| ||| | || $action |
|
1471
|
|
|
|
|
|
|
| ||| | ||-----+ | |
|
1472
|
|
|
|
|
|
|
| ||| | |||<---+ | |
|
1473
|
|
|
|
|
|
|
| ||| process | | | |
|
1474
|
|
|
|
|
|
|
| |||------------------------------------------->|| template |
|
1475
|
|
|
|
|
|
|
| ||| | | ||-----+ |
|
1476
|
|
|
|
|
|
|
| ||| | | |||<---+ |
|
1477
|
|
|
|
|
|
|
| ||| | | | |
|
1478
|
|
|
|
|
|
|
| || send_output | | | |
|
1479
|
|
|
|
|
|
|
| ||-----+ | | | |
|
1480
|
|
|
|
|
|
|
| |||<---+ | | | |
|
1481
|
|
|
|
|
|
|
$status | || | | | |
|
1482
|
|
|
|
|
|
|
<------------------|| | | | |
|
1483
|
|
|
|
|
|
|
| | | | | |
|
1484
|
|
|
|
|
|
|
| X | | | |
|
1485
|
|
|
|
|
|
|
| | | | |
|
1486
|
|
|
|
|
|
|
| | | | |
|
1487
|
|
|
|
|
|
|
| | | | |
|
1488
|
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
There's more documentation, examples, and information on our mailing lists |
|
1494
|
|
|
|
|
|
|
at the Maypole web site: |
|
1495
|
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
L |
|
1497
|
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
L, L, L. |
|
1499
|
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1501
|
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
Maypole is currently maintained by Aaron Trevena. |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
=head1 AUTHOR EMERITUS |
|
1505
|
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
Simon Cozens, C |
|
1507
|
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
Simon Flack maintained Maypole from 2.05 to 2.09 |
|
1509
|
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
Sebastian Riedel, C maintained Maypole from 1.99_01 to 2.04 |
|
1511
|
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
=head1 THANKS TO |
|
1513
|
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
Sebastian Riedel, Danijel Milicevic, Dave Slack, Jesse Sheidlower, Jody Belka, |
|
1515
|
|
|
|
|
|
|
Marcus Ramberg, Mickael Joanne, Randal Schwartz, Simon Flack, Steve Simms, |
|
1516
|
|
|
|
|
|
|
Veljko Vidovic and all the others who've helped. |
|
1517
|
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
=head1 LICENSE |
|
1519
|
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
You may distribute this code under the same terms as Perl itself. |
|
1521
|
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
=cut |
|
1523
|
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
1; |
|
1525
|
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
__END__ |
| |