blib/lib/CGI/Application.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 356 | 380 | 93.6 |
branch | 158 | 186 | 84.9 |
condition | 17 | 27 | 62.9 |
subroutine | 41 | 44 | 93.1 |
pod | 29 | 31 | 93.5 |
total | 601 | 668 | 89.9 |
line | stmt | bran | cond | sub | pod | time | code | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | package CGI::Application; | ||||||||||||||||||||||||||||||||
2 | 17 | 17 | 281041 | use Carp; | |||||||||||||||||||||||||||||
17 | 33 | ||||||||||||||||||||||||||||||||
17 | 1326 | ||||||||||||||||||||||||||||||||
3 | 17 | 17 | 109 | use strict; | |||||||||||||||||||||||||||||
17 | 25 | ||||||||||||||||||||||||||||||||
17 | 475 | ||||||||||||||||||||||||||||||||
4 | 17 | 17 | 7979 | use Class::ISA; | |||||||||||||||||||||||||||||
17 | 27319 | ||||||||||||||||||||||||||||||||
17 | 454 | ||||||||||||||||||||||||||||||||
5 | 17 | 17 | 98 | use Scalar::Util; | |||||||||||||||||||||||||||||
17 | 27 | ||||||||||||||||||||||||||||||||
17 | 65463 | ||||||||||||||||||||||||||||||||
6 | |||||||||||||||||||||||||||||||||
7 | $CGI::Application::VERSION = '4.50_50'; | ||||||||||||||||||||||||||||||||
8 | |||||||||||||||||||||||||||||||||
9 | my %INSTALLED_CALLBACKS = ( | ||||||||||||||||||||||||||||||||
10 | # hook name package sub | ||||||||||||||||||||||||||||||||
11 | init => { 'CGI::Application' => [ 'cgiapp_init' ] }, | ||||||||||||||||||||||||||||||||
12 | prerun => { 'CGI::Application' => [ 'cgiapp_prerun' ] }, | ||||||||||||||||||||||||||||||||
13 | postrun => { 'CGI::Application' => [ 'cgiapp_postrun' ] }, | ||||||||||||||||||||||||||||||||
14 | teardown => { 'CGI::Application' => [ 'teardown' ] }, | ||||||||||||||||||||||||||||||||
15 | load_tmpl => { }, | ||||||||||||||||||||||||||||||||
16 | error => { }, | ||||||||||||||||||||||||||||||||
17 | ); | ||||||||||||||||||||||||||||||||
18 | |||||||||||||||||||||||||||||||||
19 | ################################### | ||||||||||||||||||||||||||||||||
20 | #### INSTANCE SCRIPT METHODS #### | ||||||||||||||||||||||||||||||||
21 | ################################### | ||||||||||||||||||||||||||||||||
22 | |||||||||||||||||||||||||||||||||
23 | sub new { | ||||||||||||||||||||||||||||||||
24 | 69 | 69 | 1 | 83825 | my $class = shift; | ||||||||||||||||||||||||||||
25 | |||||||||||||||||||||||||||||||||
26 | 69 | 134 | my @args = @_; | ||||||||||||||||||||||||||||||
27 | |||||||||||||||||||||||||||||||||
28 | 69 | 50 | 189 | if (ref($class)) { | |||||||||||||||||||||||||||||
29 | # No copy constructor yet! | ||||||||||||||||||||||||||||||||
30 | 0 | 0 | $class = ref($class); | ||||||||||||||||||||||||||||||
31 | } | ||||||||||||||||||||||||||||||||
32 | |||||||||||||||||||||||||||||||||
33 | # Create our object! | ||||||||||||||||||||||||||||||||
34 | 69 | 104 | my $self = {}; | ||||||||||||||||||||||||||||||
35 | 69 | 140 | bless($self, $class); | ||||||||||||||||||||||||||||||
36 | |||||||||||||||||||||||||||||||||
37 | ### SET UP DEFAULT VALUES ### | ||||||||||||||||||||||||||||||||
38 | # | ||||||||||||||||||||||||||||||||
39 | # We set them up here and not in the setup() because a subclass | ||||||||||||||||||||||||||||||||
40 | # which implements setup() still needs default values! | ||||||||||||||||||||||||||||||||
41 | |||||||||||||||||||||||||||||||||
42 | 69 | 280 | $self->header_type('header'); | ||||||||||||||||||||||||||||||
43 | 69 | 213 | $self->mode_param('rm'); | ||||||||||||||||||||||||||||||
44 | 69 | 203 | $self->start_mode('start'); | ||||||||||||||||||||||||||||||
45 | |||||||||||||||||||||||||||||||||
46 | # Process optional new() parameters | ||||||||||||||||||||||||||||||||
47 | 69 | 56 | my $rprops; | ||||||||||||||||||||||||||||||
48 | 69 | 100 | 162 | if (ref($args[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
49 | 1 | 4 | $rprops = $self->_cap_hash($args[0]); | ||||||||||||||||||||||||||||||
50 | } else { | ||||||||||||||||||||||||||||||||
51 | 68 | 258 | $rprops = $self->_cap_hash({ @args }); | ||||||||||||||||||||||||||||||
52 | } | ||||||||||||||||||||||||||||||||
53 | |||||||||||||||||||||||||||||||||
54 | # Set tmpl_path() | ||||||||||||||||||||||||||||||||
55 | 69 | 100 | 192 | if (exists($rprops->{TMPL_PATH})) { | |||||||||||||||||||||||||||||
56 | 4 | 25 | $self->tmpl_path($rprops->{TMPL_PATH}); | ||||||||||||||||||||||||||||||
57 | } | ||||||||||||||||||||||||||||||||
58 | |||||||||||||||||||||||||||||||||
59 | # Set CGI query object | ||||||||||||||||||||||||||||||||
60 | 69 | 100 | 148 | if (exists($rprops->{QUERY})) { | |||||||||||||||||||||||||||||
61 | 20 | 72 | $self->query($rprops->{QUERY}); | ||||||||||||||||||||||||||||||
62 | } | ||||||||||||||||||||||||||||||||
63 | |||||||||||||||||||||||||||||||||
64 | # Set up init param() values | ||||||||||||||||||||||||||||||||
65 | 69 | 100 | 275 | if (exists($rprops->{PARAMS})) { | |||||||||||||||||||||||||||||
66 | 2 | 100 | 202 | croak("PARAMS is not a hash ref") unless (ref($rprops->{PARAMS}) eq 'HASH'); | |||||||||||||||||||||||||||||
67 | 1 | 2 | my $rparams = $rprops->{PARAMS}; | ||||||||||||||||||||||||||||||
68 | 1 | 4 | while (my ($k, $v) = each(%$rparams)) { | ||||||||||||||||||||||||||||||
69 | 2 | 8 | $self->param($k, $v); | ||||||||||||||||||||||||||||||
70 | } | ||||||||||||||||||||||||||||||||
71 | } | ||||||||||||||||||||||||||||||||
72 | |||||||||||||||||||||||||||||||||
73 | # Lock prerun_mode from being changed until cgiapp_prerun() | ||||||||||||||||||||||||||||||||
74 | 68 | 117 | $self->{__PRERUN_MODE_LOCKED} = 1; | ||||||||||||||||||||||||||||||
75 | |||||||||||||||||||||||||||||||||
76 | # Call cgiapp_init() method, which may be implemented in the sub-class. | ||||||||||||||||||||||||||||||||
77 | # Pass all constructor args forward. This will allow flexible usage | ||||||||||||||||||||||||||||||||
78 | # down the line. | ||||||||||||||||||||||||||||||||
79 | 68 | 199 | $self->call_hook('init', @args); | ||||||||||||||||||||||||||||||
80 | |||||||||||||||||||||||||||||||||
81 | # Call setup() method, which should be implemented in the sub-class! | ||||||||||||||||||||||||||||||||
82 | 68 | 195 | $self->setup(); | ||||||||||||||||||||||||||||||
83 | |||||||||||||||||||||||||||||||||
84 | 67 | 349 | return $self; | ||||||||||||||||||||||||||||||
85 | } | ||||||||||||||||||||||||||||||||
86 | |||||||||||||||||||||||||||||||||
87 | sub __get_runmode { | ||||||||||||||||||||||||||||||||
88 | 61 | 61 | 64 | my $self = shift; | |||||||||||||||||||||||||||||
89 | 61 | 66 | my $rm_param = shift; | ||||||||||||||||||||||||||||||
90 | |||||||||||||||||||||||||||||||||
91 | 61 | 65 | my $rm; | ||||||||||||||||||||||||||||||
92 | # Support call-back instead of CGI mode param | ||||||||||||||||||||||||||||||||
93 | 61 | 100 | 217 | if (ref($rm_param) eq 'CODE') { | |||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
94 | # Get run mode from subref | ||||||||||||||||||||||||||||||||
95 | 4 | 7 | $rm = $rm_param->($self); | ||||||||||||||||||||||||||||||
96 | } | ||||||||||||||||||||||||||||||||
97 | # support setting run mode from PATH_INFO | ||||||||||||||||||||||||||||||||
98 | elsif (ref($rm_param) eq 'HASH') { | ||||||||||||||||||||||||||||||||
99 | 4 | 4 | $rm = $rm_param->{run_mode}; | ||||||||||||||||||||||||||||||
100 | } | ||||||||||||||||||||||||||||||||
101 | # Get run mode from CGI param | ||||||||||||||||||||||||||||||||
102 | else { | ||||||||||||||||||||||||||||||||
103 | 53 | 113 | $rm = $self->query->param($rm_param); | ||||||||||||||||||||||||||||||
104 | } | ||||||||||||||||||||||||||||||||
105 | |||||||||||||||||||||||||||||||||
106 | # If $rm undefined, use default (start) mode | ||||||||||||||||||||||||||||||||
107 | 61 | 100 | 100 | 1052 | $rm = $self->start_mode unless defined($rm) && length($rm); | ||||||||||||||||||||||||||||
108 | |||||||||||||||||||||||||||||||||
109 | 61 | 96 | return $rm; | ||||||||||||||||||||||||||||||
110 | } | ||||||||||||||||||||||||||||||||
111 | |||||||||||||||||||||||||||||||||
112 | sub __get_runmeth { | ||||||||||||||||||||||||||||||||
113 | 61 | 61 | 76 | my $self = shift; | |||||||||||||||||||||||||||||
114 | 61 | 65 | my $rm = shift; | ||||||||||||||||||||||||||||||
115 | |||||||||||||||||||||||||||||||||
116 | 61 | 55 | my $rmeth; | ||||||||||||||||||||||||||||||
117 | |||||||||||||||||||||||||||||||||
118 | 61 | 71 | my $is_autoload = 0; | ||||||||||||||||||||||||||||||
119 | |||||||||||||||||||||||||||||||||
120 | 61 | 116 | my %rmodes = ($self->run_modes()); | ||||||||||||||||||||||||||||||
121 | 61 | 100 | 160 | if (exists($rmodes{$rm})) { | |||||||||||||||||||||||||||||
122 | 58 | 92 | $rmeth = $rmodes{$rm}; | ||||||||||||||||||||||||||||||
123 | } | ||||||||||||||||||||||||||||||||
124 | else { | ||||||||||||||||||||||||||||||||
125 | # Look for run mode "AUTOLOAD" before dieing | ||||||||||||||||||||||||||||||||
126 | 3 | 100 | 9 | unless (exists($rmodes{'AUTOLOAD'})) { | |||||||||||||||||||||||||||||
127 | 1 | 155 | croak("No such run mode '$rm'"); | ||||||||||||||||||||||||||||||
128 | } | ||||||||||||||||||||||||||||||||
129 | 2 | 3 | $rmeth = $rmodes{'AUTOLOAD'}; | ||||||||||||||||||||||||||||||
130 | 2 | 4 | $is_autoload = 1; | ||||||||||||||||||||||||||||||
131 | } | ||||||||||||||||||||||||||||||||
132 | |||||||||||||||||||||||||||||||||
133 | 60 | 146 | return ($rmeth, $is_autoload); | ||||||||||||||||||||||||||||||
134 | } | ||||||||||||||||||||||||||||||||
135 | |||||||||||||||||||||||||||||||||
136 | sub __get_body { | ||||||||||||||||||||||||||||||||
137 | 61 | 61 | 68 | my $self = shift; | |||||||||||||||||||||||||||||
138 | 61 | 66 | my $rm = shift; | ||||||||||||||||||||||||||||||
139 | |||||||||||||||||||||||||||||||||
140 | 61 | 165 | my ($rmeth, $is_autoload) = $self->__get_runmeth($rm); | ||||||||||||||||||||||||||||||
141 | |||||||||||||||||||||||||||||||||
142 | 60 | 62 | my $body; | ||||||||||||||||||||||||||||||
143 | 60 | 65 | eval { | ||||||||||||||||||||||||||||||
144 | 60 | 100 | 247 | $body = $is_autoload ? $self->$rmeth($rm) : $self->$rmeth(); | |||||||||||||||||||||||||||||
145 | }; | ||||||||||||||||||||||||||||||||
146 | 60 | 100 | 877 | if ($@) { | |||||||||||||||||||||||||||||
147 | 3 | 5 | my $error = $@; | ||||||||||||||||||||||||||||||
148 | 3 | 9 | $self->call_hook('error', $error); | ||||||||||||||||||||||||||||||
149 | 3 | 100 | 14 | if (my $em = $self->error_mode) { | |||||||||||||||||||||||||||||
150 | 2 | 14 | $body = $self->$em( $error ); | ||||||||||||||||||||||||||||||
151 | } else { | ||||||||||||||||||||||||||||||||
152 | 1 | 70 | croak("Error executing run mode '$rm': $error"); | ||||||||||||||||||||||||||||||
153 | } | ||||||||||||||||||||||||||||||||
154 | } | ||||||||||||||||||||||||||||||||
155 | |||||||||||||||||||||||||||||||||
156 | # Make sure that $body is not undefined (suppress 'uninitialized value' | ||||||||||||||||||||||||||||||||
157 | # warnings) | ||||||||||||||||||||||||||||||||
158 | 58 | 100 | 172 | return defined $body ? $body : ''; | |||||||||||||||||||||||||||||
159 | } | ||||||||||||||||||||||||||||||||
160 | |||||||||||||||||||||||||||||||||
161 | |||||||||||||||||||||||||||||||||
162 | sub run { | ||||||||||||||||||||||||||||||||
163 | 61 | 61 | 1 | 800 | my $self = shift; | ||||||||||||||||||||||||||||
164 | 61 | 149 | my $q = $self->query(); | ||||||||||||||||||||||||||||||
165 | |||||||||||||||||||||||||||||||||
166 | 61 | 138 | my $rm_param = $self->mode_param(); | ||||||||||||||||||||||||||||||
167 | |||||||||||||||||||||||||||||||||
168 | 61 | 226 | my $rm = $self->__get_runmode($rm_param); | ||||||||||||||||||||||||||||||
169 | |||||||||||||||||||||||||||||||||
170 | # Set get_current_runmode() for access by user later | ||||||||||||||||||||||||||||||||
171 | 61 | 99 | $self->{__CURRENT_RUNMODE} = $rm; | ||||||||||||||||||||||||||||||
172 | |||||||||||||||||||||||||||||||||
173 | # Allow prerun_mode to be changed | ||||||||||||||||||||||||||||||||
174 | 61 | 108 | delete($self->{__PRERUN_MODE_LOCKED}); | ||||||||||||||||||||||||||||||
175 | |||||||||||||||||||||||||||||||||
176 | # Call PRE-RUN hook, now that we know the run mode | ||||||||||||||||||||||||||||||||
177 | # This hook can be used to provide run mode specific behaviors | ||||||||||||||||||||||||||||||||
178 | # before the run mode actually runs. | ||||||||||||||||||||||||||||||||
179 | 61 | 139 | $self->call_hook('prerun', $rm); | ||||||||||||||||||||||||||||||
180 | |||||||||||||||||||||||||||||||||
181 | # Lock prerun_mode from being changed after cgiapp_prerun() | ||||||||||||||||||||||||||||||||
182 | 61 | 108 | $self->{__PRERUN_MODE_LOCKED} = 1; | ||||||||||||||||||||||||||||||
183 | |||||||||||||||||||||||||||||||||
184 | # If prerun_mode has been set, use it! | ||||||||||||||||||||||||||||||||
185 | 61 | 200 | my $prerun_mode = $self->prerun_mode(); | ||||||||||||||||||||||||||||||
186 | 61 | 100 | 137 | if (length($prerun_mode)) { | |||||||||||||||||||||||||||||
187 | 1 | 2 | $rm = $prerun_mode; | ||||||||||||||||||||||||||||||
188 | 1 | 1 | $self->{__CURRENT_RUNMODE} = $rm; | ||||||||||||||||||||||||||||||
189 | } | ||||||||||||||||||||||||||||||||
190 | |||||||||||||||||||||||||||||||||
191 | # Process run mode! | ||||||||||||||||||||||||||||||||
192 | 61 | 180 | my $body = $self->__get_body($rm); | ||||||||||||||||||||||||||||||
193 | |||||||||||||||||||||||||||||||||
194 | # Support scalar-ref for body return | ||||||||||||||||||||||||||||||||
195 | 58 | 100 | 138 | $body = $$body if ref $body eq 'SCALAR'; | |||||||||||||||||||||||||||||
196 | |||||||||||||||||||||||||||||||||
197 | # Call cgiapp_postrun() hook | ||||||||||||||||||||||||||||||||
198 | 58 | 145 | $self->call_hook('postrun', \$body); | ||||||||||||||||||||||||||||||
199 | |||||||||||||||||||||||||||||||||
200 | 58 | 111 | my $return_value; | ||||||||||||||||||||||||||||||
201 | 58 | 100 | 138 | if ($self->{__IS_PSGI}) { | |||||||||||||||||||||||||||||
202 | 1 | 5 | my ($status, $headers) = $self->_send_psgi_headers(); | ||||||||||||||||||||||||||||||
203 | |||||||||||||||||||||||||||||||||
204 | 1 | 50 | 33 | 249 | if (ref($body) eq 'GLOB' || (Scalar::Util::blessed($body) && $body->can('getline'))) { | ||||||||||||||||||||||||||||
50 | 33 | ||||||||||||||||||||||||||||||||
205 | # body a file handle - return it | ||||||||||||||||||||||||||||||||
206 | 0 | 0 | $return_value = [ $status, $headers, $body]; | ||||||||||||||||||||||||||||||
207 | } | ||||||||||||||||||||||||||||||||
208 | elsif (ref($body) eq 'CODE') { | ||||||||||||||||||||||||||||||||
209 | |||||||||||||||||||||||||||||||||
210 | # body is a subref, or an explicit callback method is set | ||||||||||||||||||||||||||||||||
211 | $return_value = sub { | ||||||||||||||||||||||||||||||||
212 | 0 | 0 | 0 | my $respond = shift; | |||||||||||||||||||||||||||||
213 | |||||||||||||||||||||||||||||||||
214 | 0 | 0 | my $writer = $respond->([ $status, $headers ]); | ||||||||||||||||||||||||||||||
215 | |||||||||||||||||||||||||||||||||
216 | 0 | 0 | &$body($writer); | ||||||||||||||||||||||||||||||
217 | 0 | 0 | }; | ||||||||||||||||||||||||||||||
218 | } | ||||||||||||||||||||||||||||||||
219 | else { | ||||||||||||||||||||||||||||||||
220 | |||||||||||||||||||||||||||||||||
221 | 1 | 3 | $return_value = [ $status, $headers, [ $body ]]; | ||||||||||||||||||||||||||||||
222 | } | ||||||||||||||||||||||||||||||||
223 | } | ||||||||||||||||||||||||||||||||
224 | else { | ||||||||||||||||||||||||||||||||
225 | # Set up HTTP headers non-PSGI responses | ||||||||||||||||||||||||||||||||
226 | 57 | 167 | my $headers = $self->_send_headers(); | ||||||||||||||||||||||||||||||
227 | |||||||||||||||||||||||||||||||||
228 | # Build up total output | ||||||||||||||||||||||||||||||||
229 | 57 | 23330 | $return_value = $headers.$body; | ||||||||||||||||||||||||||||||
230 | 57 | 100 | 197 | print $return_value unless $ENV{CGI_APP_RETURN_ONLY}; | |||||||||||||||||||||||||||||
231 | } | ||||||||||||||||||||||||||||||||
232 | |||||||||||||||||||||||||||||||||
233 | # clean up operations | ||||||||||||||||||||||||||||||||
234 | 58 | 123 | $self->call_hook('teardown'); | ||||||||||||||||||||||||||||||
235 | |||||||||||||||||||||||||||||||||
236 | 58 | 182 | return $return_value; | ||||||||||||||||||||||||||||||
237 | } | ||||||||||||||||||||||||||||||||
238 | |||||||||||||||||||||||||||||||||
239 | |||||||||||||||||||||||||||||||||
240 | sub psgi_app { | ||||||||||||||||||||||||||||||||
241 | 0 | 0 | 1 | 0 | my $class = shift; | ||||||||||||||||||||||||||||
242 | 0 | 0 | my $args_to_new = shift; | ||||||||||||||||||||||||||||||
243 | |||||||||||||||||||||||||||||||||
244 | return sub { | ||||||||||||||||||||||||||||||||
245 | 0 | 0 | 0 | my $env = shift; | |||||||||||||||||||||||||||||
246 | |||||||||||||||||||||||||||||||||
247 | 0 | 0 | 0 | if (not defined $args_to_new->{QUERY}) { | |||||||||||||||||||||||||||||
248 | 0 | 0 | require CGI::PSGI; | ||||||||||||||||||||||||||||||
249 | 0 | 0 | $args_to_new->{QUERY} = CGI::PSGI->new($env); | ||||||||||||||||||||||||||||||
250 | } | ||||||||||||||||||||||||||||||||
251 | |||||||||||||||||||||||||||||||||
252 | 0 | 0 | my $webapp = $class->new($args_to_new); | ||||||||||||||||||||||||||||||
253 | 0 | 0 | return $webapp->run_as_psgi; | ||||||||||||||||||||||||||||||
254 | } | ||||||||||||||||||||||||||||||||
255 | 0 | 0 | } | ||||||||||||||||||||||||||||||
256 | |||||||||||||||||||||||||||||||||
257 | sub run_as_psgi { | ||||||||||||||||||||||||||||||||
258 | 1 | 1 | 1 | 6 | my $self = shift; | ||||||||||||||||||||||||||||
259 | 1 | 2 | $self->{__IS_PSGI} = 1; | ||||||||||||||||||||||||||||||
260 | |||||||||||||||||||||||||||||||||
261 | # Run doesn't officially support any args, but pass them through in case some sub-class uses them. | ||||||||||||||||||||||||||||||||
262 | 1 | 5 | return $self->run(@_); | ||||||||||||||||||||||||||||||
263 | } | ||||||||||||||||||||||||||||||||
264 | |||||||||||||||||||||||||||||||||
265 | |||||||||||||||||||||||||||||||||
266 | ############################ | ||||||||||||||||||||||||||||||||
267 | #### OVERRIDE METHODS #### | ||||||||||||||||||||||||||||||||
268 | ############################ | ||||||||||||||||||||||||||||||||
269 | |||||||||||||||||||||||||||||||||
270 | sub cgiapp_get_query { | ||||||||||||||||||||||||||||||||
271 | 14 | 14 | 1 | 22 | my $self = shift; | ||||||||||||||||||||||||||||
272 | |||||||||||||||||||||||||||||||||
273 | # Include CGI.pm and related modules | ||||||||||||||||||||||||||||||||
274 | 14 | 8528 | require CGI; | ||||||||||||||||||||||||||||||
275 | |||||||||||||||||||||||||||||||||
276 | # Get the query object | ||||||||||||||||||||||||||||||||
277 | 14 | 62802 | my $q = CGI->new(); | ||||||||||||||||||||||||||||||
278 | |||||||||||||||||||||||||||||||||
279 | 14 | 33158 | return $q; | ||||||||||||||||||||||||||||||
280 | } | ||||||||||||||||||||||||||||||||
281 | |||||||||||||||||||||||||||||||||
282 | |||||||||||||||||||||||||||||||||
283 | sub cgiapp_init { | ||||||||||||||||||||||||||||||||
284 | 45 | 45 | 1 | 51 | my $self = shift; | ||||||||||||||||||||||||||||
285 | 45 | 101 | my @args = (@_); | ||||||||||||||||||||||||||||||
286 | |||||||||||||||||||||||||||||||||
287 | # Nothing to init, yet! | ||||||||||||||||||||||||||||||||
288 | } | ||||||||||||||||||||||||||||||||
289 | |||||||||||||||||||||||||||||||||
290 | |||||||||||||||||||||||||||||||||
291 | sub cgiapp_prerun { | ||||||||||||||||||||||||||||||||
292 | 53 | 53 | 1 | 63 | my $self = shift; | ||||||||||||||||||||||||||||
293 | 53 | 92 | my $rm = shift; | ||||||||||||||||||||||||||||||
294 | |||||||||||||||||||||||||||||||||
295 | # Nothing to prerun, yet! | ||||||||||||||||||||||||||||||||
296 | } | ||||||||||||||||||||||||||||||||
297 | |||||||||||||||||||||||||||||||||
298 | |||||||||||||||||||||||||||||||||
299 | sub cgiapp_postrun { | ||||||||||||||||||||||||||||||||
300 | 51 | 51 | 1 | 63 | my $self = shift; | ||||||||||||||||||||||||||||
301 | 51 | 98 | my $bodyref = shift; | ||||||||||||||||||||||||||||||
302 | |||||||||||||||||||||||||||||||||
303 | # Nothing to postrun, yet! | ||||||||||||||||||||||||||||||||
304 | } | ||||||||||||||||||||||||||||||||
305 | |||||||||||||||||||||||||||||||||
306 | |||||||||||||||||||||||||||||||||
307 | sub setup { | ||||||||||||||||||||||||||||||||
308 | 11 | 11 | 1 | 16 | my $self = shift; | ||||||||||||||||||||||||||||
309 | } | ||||||||||||||||||||||||||||||||
310 | |||||||||||||||||||||||||||||||||
311 | |||||||||||||||||||||||||||||||||
312 | sub teardown { | ||||||||||||||||||||||||||||||||
313 | 39 | 39 | 1 | 68 | my $self = shift; | ||||||||||||||||||||||||||||
314 | |||||||||||||||||||||||||||||||||
315 | # Nothing to shut down, yet! | ||||||||||||||||||||||||||||||||
316 | } | ||||||||||||||||||||||||||||||||
317 | |||||||||||||||||||||||||||||||||
318 | |||||||||||||||||||||||||||||||||
319 | |||||||||||||||||||||||||||||||||
320 | |||||||||||||||||||||||||||||||||
321 | ###################################### | ||||||||||||||||||||||||||||||||
322 | #### APPLICATION MODULE METHODS #### | ||||||||||||||||||||||||||||||||
323 | ###################################### | ||||||||||||||||||||||||||||||||
324 | |||||||||||||||||||||||||||||||||
325 | sub dump { | ||||||||||||||||||||||||||||||||
326 | 2 | 2 | 1 | 3 | my $self = shift; | ||||||||||||||||||||||||||||
327 | 2 | 4 | my $output = ''; | ||||||||||||||||||||||||||||||
328 | |||||||||||||||||||||||||||||||||
329 | # Dump run mode | ||||||||||||||||||||||||||||||||
330 | 2 | 6 | my $current_runmode = $self->get_current_runmode(); | ||||||||||||||||||||||||||||||
331 | 2 | 100 | 7 | $current_runmode = "" unless (defined($current_runmode)); | |||||||||||||||||||||||||||||
332 | 2 | 6 | $output .= "Current Run mode: '$current_runmode'\n"; | ||||||||||||||||||||||||||||||
333 | |||||||||||||||||||||||||||||||||
334 | # Dump Params | ||||||||||||||||||||||||||||||||
335 | 2 | 4 | $output .= "\nQuery Parameters:\n"; | ||||||||||||||||||||||||||||||
336 | 2 | 5 | my @params = $self->query->param(); | ||||||||||||||||||||||||||||||
337 | 2 | 30 | foreach my $p (sort(@params)) { | ||||||||||||||||||||||||||||||
338 | 1 | 2 | my @data = $self->query->param($p); | ||||||||||||||||||||||||||||||
339 | 1 | 15 | my $data_str = "'".join("', '", @data)."'"; | ||||||||||||||||||||||||||||||
340 | 1 | 5 | $output .= "\t$p => $data_str\n"; | ||||||||||||||||||||||||||||||
341 | } | ||||||||||||||||||||||||||||||||
342 | |||||||||||||||||||||||||||||||||
343 | # Dump ENV | ||||||||||||||||||||||||||||||||
344 | 2 | 5 | $output .= "\nQuery Environment:\n"; | ||||||||||||||||||||||||||||||
345 | 2 | 28 | foreach my $ek (sort(keys(%ENV))) { | ||||||||||||||||||||||||||||||
346 | 34 | 62 | $output .= "\t$ek => '".$ENV{$ek}."'\n"; | ||||||||||||||||||||||||||||||
347 | } | ||||||||||||||||||||||||||||||||
348 | |||||||||||||||||||||||||||||||||
349 | 2 | 8 | return $output; | ||||||||||||||||||||||||||||||
350 | } | ||||||||||||||||||||||||||||||||
351 | |||||||||||||||||||||||||||||||||
352 | |||||||||||||||||||||||||||||||||
353 | sub dump_html { | ||||||||||||||||||||||||||||||||
354 | 1 | 1 | 1 | 1 | my $self = shift; | ||||||||||||||||||||||||||||
355 | 1 | 3 | my $query = $self->query(); | ||||||||||||||||||||||||||||||
356 | 1 | 2 | my $output = ''; | ||||||||||||||||||||||||||||||
357 | |||||||||||||||||||||||||||||||||
358 | # Dump run-mode | ||||||||||||||||||||||||||||||||
359 | 1 | 4 | my $current_runmode = $self->get_current_runmode(); | ||||||||||||||||||||||||||||||
360 | 1 | 3 | $output .= " Current Run-mode: |
||||||||||||||||||||||||||||||
361 | '$current_runmode'\n"; | ||||||||||||||||||||||||||||||||
362 | |||||||||||||||||||||||||||||||||
363 | # Dump Params | ||||||||||||||||||||||||||||||||
364 | 1 | 2 | $output .= " Query Parameters: \n"; |
||||||||||||||||||||||||||||||
365 | 1 | 47 | $output .= $query->Dump; | ||||||||||||||||||||||||||||||
366 | |||||||||||||||||||||||||||||||||
367 | # Dump ENV | ||||||||||||||||||||||||||||||||
368 | 1 | 266 | $output .= " Query Environment: \n
|
||||||||||||||||||||||||||||||
369 | 1 | 12 | foreach my $ek ( sort( keys( %ENV ) ) ) { | ||||||||||||||||||||||||||||||
370 | 17 | 1149 | $output .= sprintf( | ||||||||||||||||||||||||||||||
371 | " |
||||||||||||||||||||||||||||||||
372 | $query->escapeHTML( $ek ), | ||||||||||||||||||||||||||||||||
373 | $query->escapeHTML( $ENV{$ek} ) | ||||||||||||||||||||||||||||||||
374 | ); | ||||||||||||||||||||||||||||||||
375 | } | ||||||||||||||||||||||||||||||||
376 | 1 | 51 | $output .= "\n"; | ||||||||||||||||||||||||||||||
377 | |||||||||||||||||||||||||||||||||
378 | 1 | 3 | return $output; | ||||||||||||||||||||||||||||||
379 | } | ||||||||||||||||||||||||||||||||
380 | |||||||||||||||||||||||||||||||||
381 | |||||||||||||||||||||||||||||||||
382 | sub no_runmodes { | ||||||||||||||||||||||||||||||||
383 | |||||||||||||||||||||||||||||||||
384 | 9 | 9 | 0 | 13 | my $self = shift; | ||||||||||||||||||||||||||||
385 | 9 | 18 | my $query = $self->query(); | ||||||||||||||||||||||||||||||
386 | 9 | 186 | my $output = $query->start_html; | ||||||||||||||||||||||||||||||
387 | |||||||||||||||||||||||||||||||||
388 | # If no runmodes specified by app return error message | ||||||||||||||||||||||||||||||||
389 | 9 | 7387 | my $current_runmode = $self->get_current_runmode(); | ||||||||||||||||||||||||||||||
390 | 9 | 160 | my $query_params = $query->Dump; | ||||||||||||||||||||||||||||||
391 | |||||||||||||||||||||||||||||||||
392 | 9 | 1708 | $output .= qq{ | ||||||||||||||||||||||||||||||
393 | Error - No runmodes specified. |
||||||||||||||||||||||||||||||||
394 | Runmode called: $current_runmode" |
||||||||||||||||||||||||||||||||
395 | Query paramaters: $query_params |
||||||||||||||||||||||||||||||||
396 | Your application has not specified any runmodes. |
||||||||||||||||||||||||||||||||
397 | |||||||||||||||||||||||||||||||||
398 | CGI::Application documentation. | ||||||||||||||||||||||||||||||||
399 | }; | ||||||||||||||||||||||||||||||||
400 | |||||||||||||||||||||||||||||||||
401 | 9 | 124 | $output .= $query->end_html(); | ||||||||||||||||||||||||||||||
402 | 9 | 318 | return $output; | ||||||||||||||||||||||||||||||
403 | } | ||||||||||||||||||||||||||||||||
404 | |||||||||||||||||||||||||||||||||
405 | |||||||||||||||||||||||||||||||||
406 | sub header_add { | ||||||||||||||||||||||||||||||||
407 | 5 | 5 | 1 | 610 | my $self = shift; | ||||||||||||||||||||||||||||
408 | 5 | 14 | return $self->_header_props_update(\@_,add=>1); | ||||||||||||||||||||||||||||||
409 | } | ||||||||||||||||||||||||||||||||
410 | |||||||||||||||||||||||||||||||||
411 | sub header_props { | ||||||||||||||||||||||||||||||||
412 | 67 | 67 | 1 | 3114 | my $self = shift; | ||||||||||||||||||||||||||||
413 | 67 | 196 | return $self->_header_props_update(\@_,add=>0); | ||||||||||||||||||||||||||||||
414 | } | ||||||||||||||||||||||||||||||||
415 | |||||||||||||||||||||||||||||||||
416 | # used by header_props and header_add to update the headers | ||||||||||||||||||||||||||||||||
417 | sub _header_props_update { | ||||||||||||||||||||||||||||||||
418 | 72 | 72 | 67 | my $self = shift; | |||||||||||||||||||||||||||||
419 | 72 | 70 | my $data_ref = shift; | ||||||||||||||||||||||||||||||
420 | 72 | 129 | my %in = @_; | ||||||||||||||||||||||||||||||
421 | |||||||||||||||||||||||||||||||||
422 | 72 | 100 | my @data = @$data_ref; | ||||||||||||||||||||||||||||||
423 | |||||||||||||||||||||||||||||||||
424 | # First use? Create new __HEADER_PROPS! | ||||||||||||||||||||||||||||||||
425 | 72 | 100 | 209 | $self->{__HEADER_PROPS} = {} unless (exists($self->{__HEADER_PROPS})); | |||||||||||||||||||||||||||||
426 | |||||||||||||||||||||||||||||||||
427 | 72 | 63 | my $props; | ||||||||||||||||||||||||||||||
428 | |||||||||||||||||||||||||||||||||
429 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
430 | 72 | 100 | 134 | if (scalar(@data)) { | |||||||||||||||||||||||||||||
431 | 19 | 100 | 33 | if ($self->header_type eq 'none') { | |||||||||||||||||||||||||||||
432 | 1 | 12 | warn "header_props called while header_type set to 'none', headers will NOT be sent!" | ||||||||||||||||||||||||||||||
433 | } | ||||||||||||||||||||||||||||||||
434 | # Is it a hash, or hash-ref? | ||||||||||||||||||||||||||||||||
435 | 19 | 100 | 69 | if (ref($data[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
436 | # Make a copy | ||||||||||||||||||||||||||||||||
437 | 4 | 4 | %$props = %{$data[0]}; | ||||||||||||||||||||||||||||||
4 | 12 | ||||||||||||||||||||||||||||||||
438 | } elsif ((scalar(@data) % 2) == 0) { | ||||||||||||||||||||||||||||||||
439 | # It appears to be a possible hash (even # of elements) | ||||||||||||||||||||||||||||||||
440 | 13 | 33 | %$props = @data; | ||||||||||||||||||||||||||||||
441 | } else { | ||||||||||||||||||||||||||||||||
442 | 2 | 100 | 7 | my $meth = $in{add} ? 'add' : 'props'; | |||||||||||||||||||||||||||||
443 | 2 | 301 | croak("Odd number of elements passed to header_$meth(). Not a valid hash") | ||||||||||||||||||||||||||||||
444 | } | ||||||||||||||||||||||||||||||||
445 | |||||||||||||||||||||||||||||||||
446 | # merge in new headers, appending new values passed as array refs | ||||||||||||||||||||||||||||||||
447 | 17 | 100 | 38 | if ($in{add}) { | |||||||||||||||||||||||||||||
448 | 4 | 10 | for my $key_set_to_aref (grep { ref $props->{$_} eq 'ARRAY'} keys %$props) { | ||||||||||||||||||||||||||||||
4 | 15 | ||||||||||||||||||||||||||||||||
449 | 2 | 4 | my $existing_val = $self->{__HEADER_PROPS}->{$key_set_to_aref}; | ||||||||||||||||||||||||||||||
450 | 2 | 100 | 5 | next unless defined $existing_val; | |||||||||||||||||||||||||||||
451 | 1 | 50 | 4 | my @existing_val_array = (ref $existing_val eq 'ARRAY') ? @$existing_val : ($existing_val); | |||||||||||||||||||||||||||||
452 | 1 | 1 | $props->{$key_set_to_aref} = [ @existing_val_array, @{ $props->{$key_set_to_aref} } ]; | ||||||||||||||||||||||||||||||
1 | 4 | ||||||||||||||||||||||||||||||||
453 | } | ||||||||||||||||||||||||||||||||
454 | 4 | 9 | $self->{__HEADER_PROPS} = { %{ $self->{__HEADER_PROPS} }, %$props }; | ||||||||||||||||||||||||||||||
4 | 12 | ||||||||||||||||||||||||||||||||
455 | } | ||||||||||||||||||||||||||||||||
456 | # Set new headers, clobbering existing values | ||||||||||||||||||||||||||||||||
457 | else { | ||||||||||||||||||||||||||||||||
458 | 13 | 23 | $self->{__HEADER_PROPS} = $props; | ||||||||||||||||||||||||||||||
459 | } | ||||||||||||||||||||||||||||||||
460 | |||||||||||||||||||||||||||||||||
461 | } | ||||||||||||||||||||||||||||||||
462 | |||||||||||||||||||||||||||||||||
463 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
464 | 70 | 75 | return (%{ $self->{__HEADER_PROPS}}); | ||||||||||||||||||||||||||||||
70 | 1070 | ||||||||||||||||||||||||||||||||
465 | } | ||||||||||||||||||||||||||||||||
466 | |||||||||||||||||||||||||||||||||
467 | |||||||||||||||||||||||||||||||||
468 | sub header_type { | ||||||||||||||||||||||||||||||||
469 | 157 | 157 | 1 | 196 | my $self = shift; | ||||||||||||||||||||||||||||
470 | 157 | 184 | my ($header_type) = @_; | ||||||||||||||||||||||||||||||
471 | |||||||||||||||||||||||||||||||||
472 | 157 | 291 | my @allowed_header_types = qw(header redirect none); | ||||||||||||||||||||||||||||||
473 | |||||||||||||||||||||||||||||||||
474 | # First use? Create new __HEADER_TYPE! | ||||||||||||||||||||||||||||||||
475 | 157 | 100 | 508 | $self->{__HEADER_TYPE} = 'header' unless (exists($self->{__HEADER_TYPE})); | |||||||||||||||||||||||||||||
476 | |||||||||||||||||||||||||||||||||
477 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
478 | 157 | 100 | 320 | if (defined($header_type)) { | |||||||||||||||||||||||||||||
479 | 80 | 137 | $header_type = lc($header_type); | ||||||||||||||||||||||||||||||
480 | 240 | 448 | croak("Invalid header_type '$header_type'") | ||||||||||||||||||||||||||||||
481 | 80 | 50 | 136 | unless(grep { $_ eq $header_type } @allowed_header_types); | |||||||||||||||||||||||||||||
482 | 80 | 134 | $self->{__HEADER_TYPE} = $header_type; | ||||||||||||||||||||||||||||||
483 | } | ||||||||||||||||||||||||||||||||
484 | |||||||||||||||||||||||||||||||||
485 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
486 | 157 | 297 | return $self->{__HEADER_TYPE}; | ||||||||||||||||||||||||||||||
487 | } | ||||||||||||||||||||||||||||||||
488 | |||||||||||||||||||||||||||||||||
489 | |||||||||||||||||||||||||||||||||
490 | sub param { | ||||||||||||||||||||||||||||||||
491 | 106 | 106 | 1 | 15426 | my $self = shift; | ||||||||||||||||||||||||||||
492 | 106 | 183 | my (@data) = (@_); | ||||||||||||||||||||||||||||||
493 | |||||||||||||||||||||||||||||||||
494 | # First use? Create new __PARAMS! | ||||||||||||||||||||||||||||||||
495 | 106 | 100 | 242 | $self->{__PARAMS} = {} unless (exists($self->{__PARAMS})); | |||||||||||||||||||||||||||||
496 | |||||||||||||||||||||||||||||||||
497 | 106 | 110 | my $rp = $self->{__PARAMS}; | ||||||||||||||||||||||||||||||
498 | |||||||||||||||||||||||||||||||||
499 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
500 | 106 | 100 | 159 | if (scalar(@data)) { | |||||||||||||||||||||||||||||
501 | # Is it a hash, or hash-ref? | ||||||||||||||||||||||||||||||||
502 | 98 | 100 | 307 | if (ref($data[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
50 | |||||||||||||||||||||||||||||||||
503 | # Make a copy, which augments the existing contents (if any) | ||||||||||||||||||||||||||||||||
504 | 1 | 3 | %$rp = (%$rp, %{$data[0]}); | ||||||||||||||||||||||||||||||
1 | 7 | ||||||||||||||||||||||||||||||||
505 | } elsif ((scalar(@data) % 2) == 0) { | ||||||||||||||||||||||||||||||||
506 | # It appears to be a possible hash (even # of elements) | ||||||||||||||||||||||||||||||||
507 | 62 | 246 | %$rp = (%$rp, @data); | ||||||||||||||||||||||||||||||
508 | } elsif (scalar(@data) > 1) { | ||||||||||||||||||||||||||||||||
509 | 0 | 0 | croak("Odd number of elements passed to param(). Not a valid hash"); | ||||||||||||||||||||||||||||||
510 | } | ||||||||||||||||||||||||||||||||
511 | } else { | ||||||||||||||||||||||||||||||||
512 | # Return the list of param keys if no param is specified. | ||||||||||||||||||||||||||||||||
513 | 8 | 50 | return (keys(%$rp)); | ||||||||||||||||||||||||||||||
514 | } | ||||||||||||||||||||||||||||||||
515 | |||||||||||||||||||||||||||||||||
516 | # If exactly one parameter was sent to param(), return the value | ||||||||||||||||||||||||||||||||
517 | 98 | 100 | 222 | if (scalar(@data) <= 2) { | |||||||||||||||||||||||||||||
518 | 96 | 92 | my $param = $data[0]; | ||||||||||||||||||||||||||||||
519 | 96 | 276 | return $rp->{$param}; | ||||||||||||||||||||||||||||||
520 | } | ||||||||||||||||||||||||||||||||
521 | 2 | 4 | return; # Otherwise, return undef | ||||||||||||||||||||||||||||||
522 | } | ||||||||||||||||||||||||||||||||
523 | |||||||||||||||||||||||||||||||||
524 | |||||||||||||||||||||||||||||||||
525 | sub delete { | ||||||||||||||||||||||||||||||||
526 | 3 | 3 | 1 | 12 | my $self = shift; | ||||||||||||||||||||||||||||
527 | 3 | 4 | my ($param) = @_; | ||||||||||||||||||||||||||||||
528 | |||||||||||||||||||||||||||||||||
529 | # return undef it the param name isn't given | ||||||||||||||||||||||||||||||||
530 | 3 | 100 | 13 | return undef unless defined $param; | |||||||||||||||||||||||||||||
531 | |||||||||||||||||||||||||||||||||
532 | #simply delete this param from $self->{__PARAMS} | ||||||||||||||||||||||||||||||||
533 | 2 | 7 | delete $self->{__PARAMS}->{$param}; | ||||||||||||||||||||||||||||||
534 | } | ||||||||||||||||||||||||||||||||
535 | |||||||||||||||||||||||||||||||||
536 | |||||||||||||||||||||||||||||||||
537 | sub query { | ||||||||||||||||||||||||||||||||
538 | 247 | 247 | 1 | 13074 | my $self = shift; | ||||||||||||||||||||||||||||
539 | 247 | 245 | my ($query) = @_; | ||||||||||||||||||||||||||||||
540 | |||||||||||||||||||||||||||||||||
541 | # If data is provided, set it! Otherwise, create a new one. | ||||||||||||||||||||||||||||||||
542 | 247 | 100 | 363 | if (defined($query)) { | |||||||||||||||||||||||||||||
543 | 44 | 80 | $self->{__QUERY_OBJ} = $query; | ||||||||||||||||||||||||||||||
544 | } else { | ||||||||||||||||||||||||||||||||
545 | # We're only allowed to create a new query object if one does not yet exist! | ||||||||||||||||||||||||||||||||
546 | 203 | 100 | 440 | unless (exists($self->{__QUERY_OBJ})) { | |||||||||||||||||||||||||||||
547 | 15 | 70 | $self->{__QUERY_OBJ} = $self->cgiapp_get_query(); | ||||||||||||||||||||||||||||||
548 | } | ||||||||||||||||||||||||||||||||
549 | } | ||||||||||||||||||||||||||||||||
550 | |||||||||||||||||||||||||||||||||
551 | 247 | 15891 | return $self->{__QUERY_OBJ}; | ||||||||||||||||||||||||||||||
552 | } | ||||||||||||||||||||||||||||||||
553 | |||||||||||||||||||||||||||||||||
554 | |||||||||||||||||||||||||||||||||
555 | sub run_modes { | ||||||||||||||||||||||||||||||||
556 | 131 | 131 | 1 | 400 | my $self = shift; | ||||||||||||||||||||||||||||
557 | 131 | 200 | my (@data) = (@_); | ||||||||||||||||||||||||||||||
558 | |||||||||||||||||||||||||||||||||
559 | # First use? Create new __RUN_MODES! | ||||||||||||||||||||||||||||||||
560 | 131 | 100 | 469 | $self->{__RUN_MODES} = { 'start' => 'no_runmodes' } unless (exists($self->{__RUN_MODES})); | |||||||||||||||||||||||||||||
561 | |||||||||||||||||||||||||||||||||
562 | 131 | 158 | my $rr_m = $self->{__RUN_MODES}; | ||||||||||||||||||||||||||||||
563 | |||||||||||||||||||||||||||||||||
564 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
565 | 131 | 100 | 235 | if (scalar(@data)) { | |||||||||||||||||||||||||||||
566 | # Is it a hash, hash-ref, or array-ref? | ||||||||||||||||||||||||||||||||
567 | 70 | 100 | 252 | if (ref($data[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
568 | # Make a copy, which augments the existing contents (if any) | ||||||||||||||||||||||||||||||||
569 | 1 | 2 | %$rr_m = (%$rr_m, %{$data[0]}); | ||||||||||||||||||||||||||||||
1 | 4 | ||||||||||||||||||||||||||||||||
570 | } elsif (ref($data[0]) eq 'ARRAY') { | ||||||||||||||||||||||||||||||||
571 | # Convert array-ref into hash table | ||||||||||||||||||||||||||||||||
572 | 12 | 16 | foreach my $rm (@{$data[0]}) { | ||||||||||||||||||||||||||||||
12 | 24 | ||||||||||||||||||||||||||||||||
573 | 26 | 44 | $rr_m->{$rm} = $rm; | ||||||||||||||||||||||||||||||
574 | } | ||||||||||||||||||||||||||||||||
575 | } elsif ((scalar(@data) % 2) == 0) { | ||||||||||||||||||||||||||||||||
576 | # It appears to be a possible hash (even # of elements) | ||||||||||||||||||||||||||||||||
577 | 56 | 363 | %$rr_m = (%$rr_m, @data); | ||||||||||||||||||||||||||||||
578 | } else { | ||||||||||||||||||||||||||||||||
579 | 1 | 179 | croak("Odd number of elements passed to run_modes(). Not a valid hash"); | ||||||||||||||||||||||||||||||
580 | } | ||||||||||||||||||||||||||||||||
581 | } | ||||||||||||||||||||||||||||||||
582 | |||||||||||||||||||||||||||||||||
583 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
584 | 130 | 466 | return (%$rr_m); | ||||||||||||||||||||||||||||||
585 | } | ||||||||||||||||||||||||||||||||
586 | |||||||||||||||||||||||||||||||||
587 | |||||||||||||||||||||||||||||||||
588 | sub start_mode { | ||||||||||||||||||||||||||||||||
589 | 145 | 145 | 1 | 257 | my $self = shift; | ||||||||||||||||||||||||||||
590 | 145 | 155 | my ($start_mode) = @_; | ||||||||||||||||||||||||||||||
591 | |||||||||||||||||||||||||||||||||
592 | # First use? Create new __START_MODE | ||||||||||||||||||||||||||||||||
593 | 145 | 100 | 380 | $self->{__START_MODE} = 'start' unless (exists($self->{__START_MODE})); | |||||||||||||||||||||||||||||
594 | |||||||||||||||||||||||||||||||||
595 | # If data is provided, set it | ||||||||||||||||||||||||||||||||
596 | 145 | 100 | 264 | if (defined($start_mode)) { | |||||||||||||||||||||||||||||
597 | 119 | 144 | $self->{__START_MODE} = $start_mode; | ||||||||||||||||||||||||||||||
598 | } | ||||||||||||||||||||||||||||||||
599 | |||||||||||||||||||||||||||||||||
600 | 145 | 218 | return $self->{__START_MODE}; | ||||||||||||||||||||||||||||||
601 | } | ||||||||||||||||||||||||||||||||
602 | |||||||||||||||||||||||||||||||||
603 | |||||||||||||||||||||||||||||||||
604 | sub error_mode { | ||||||||||||||||||||||||||||||||
605 | 5 | 5 | 1 | 17 | my $self = shift; | ||||||||||||||||||||||||||||
606 | 5 | 6 | my ($error_mode) = @_; | ||||||||||||||||||||||||||||||
607 | |||||||||||||||||||||||||||||||||
608 | # First use? Create new __ERROR_MODE | ||||||||||||||||||||||||||||||||
609 | 5 | 100 | 21 | $self->{__ERROR_MODE} = undef unless (exists($self->{__ERROR_MODE})); | |||||||||||||||||||||||||||||
610 | |||||||||||||||||||||||||||||||||
611 | # If data is provided, set it. | ||||||||||||||||||||||||||||||||
612 | 5 | 100 | 12 | if (defined($error_mode)) { | |||||||||||||||||||||||||||||
613 | 2 | 7 | $self->{__ERROR_MODE} = $error_mode; | ||||||||||||||||||||||||||||||
614 | } | ||||||||||||||||||||||||||||||||
615 | |||||||||||||||||||||||||||||||||
616 | 5 | 14 | return $self->{__ERROR_MODE}; | ||||||||||||||||||||||||||||||
617 | } | ||||||||||||||||||||||||||||||||
618 | |||||||||||||||||||||||||||||||||
619 | |||||||||||||||||||||||||||||||||
620 | sub tmpl_path { | ||||||||||||||||||||||||||||||||
621 | 13 | 13 | 1 | 30 | my $self = shift; | ||||||||||||||||||||||||||||
622 | 13 | 16 | my ($tmpl_path) = @_; | ||||||||||||||||||||||||||||||
623 | |||||||||||||||||||||||||||||||||
624 | # First use? Create new __TMPL_PATH! | ||||||||||||||||||||||||||||||||
625 | 13 | 100 | 45 | $self->{__TMPL_PATH} = '' unless (exists($self->{__TMPL_PATH})); | |||||||||||||||||||||||||||||
626 | |||||||||||||||||||||||||||||||||
627 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
628 | 13 | 100 | 33 | if (defined($tmpl_path)) { | |||||||||||||||||||||||||||||
629 | 5 | 10 | $self->{__TMPL_PATH} = $tmpl_path; | ||||||||||||||||||||||||||||||
630 | } | ||||||||||||||||||||||||||||||||
631 | |||||||||||||||||||||||||||||||||
632 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
633 | 13 | 33 | return $self->{__TMPL_PATH}; | ||||||||||||||||||||||||||||||
634 | } | ||||||||||||||||||||||||||||||||
635 | |||||||||||||||||||||||||||||||||
636 | |||||||||||||||||||||||||||||||||
637 | sub prerun_mode { | ||||||||||||||||||||||||||||||||
638 | 64 | 64 | 1 | 77 | my $self = shift; | ||||||||||||||||||||||||||||
639 | 64 | 71 | my ($prerun_mode) = @_; | ||||||||||||||||||||||||||||||
640 | |||||||||||||||||||||||||||||||||
641 | # First use? Create new __PRERUN_MODE | ||||||||||||||||||||||||||||||||
642 | 64 | 100 | 195 | $self->{__PRERUN_MODE} = '' unless (exists($self->{__PRERUN_MODE})); | |||||||||||||||||||||||||||||
643 | |||||||||||||||||||||||||||||||||
644 | # Was data provided? | ||||||||||||||||||||||||||||||||
645 | 64 | 100 | 130 | if (defined($prerun_mode)) { | |||||||||||||||||||||||||||||
646 | # Are we allowed to set prerun_mode? | ||||||||||||||||||||||||||||||||
647 | 3 | 100 | 24 | if (exists($self->{__PRERUN_MODE_LOCKED})) { | |||||||||||||||||||||||||||||
648 | # Not allowed! Throw an exception. | ||||||||||||||||||||||||||||||||
649 | 2 | 311 | croak("prerun_mode() can only be called within cgiapp_prerun()! Error"); | ||||||||||||||||||||||||||||||
650 | } else { | ||||||||||||||||||||||||||||||||
651 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
652 | 1 | 2 | $self->{__PRERUN_MODE} = $prerun_mode; | ||||||||||||||||||||||||||||||
653 | } | ||||||||||||||||||||||||||||||||
654 | } | ||||||||||||||||||||||||||||||||
655 | |||||||||||||||||||||||||||||||||
656 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
657 | 62 | 106 | return $self->{__PRERUN_MODE}; | ||||||||||||||||||||||||||||||
658 | } | ||||||||||||||||||||||||||||||||
659 | |||||||||||||||||||||||||||||||||
660 | |||||||||||||||||||||||||||||||||
661 | sub get_current_runmode { | ||||||||||||||||||||||||||||||||
662 | 22 | 22 | 1 | 923 | my $self = shift; | ||||||||||||||||||||||||||||
663 | |||||||||||||||||||||||||||||||||
664 | # It's OK if we return undef if this method is called too early | ||||||||||||||||||||||||||||||||
665 | 22 | 55 | return $self->{__CURRENT_RUNMODE}; | ||||||||||||||||||||||||||||||
666 | } | ||||||||||||||||||||||||||||||||
667 | |||||||||||||||||||||||||||||||||
668 | |||||||||||||||||||||||||||||||||
669 | |||||||||||||||||||||||||||||||||
670 | |||||||||||||||||||||||||||||||||
671 | |||||||||||||||||||||||||||||||||
672 | ########################### | ||||||||||||||||||||||||||||||||
673 | #### PRIVATE METHODS #### | ||||||||||||||||||||||||||||||||
674 | ########################### | ||||||||||||||||||||||||||||||||
675 | |||||||||||||||||||||||||||||||||
676 | |||||||||||||||||||||||||||||||||
677 | # return headers as a string | ||||||||||||||||||||||||||||||||
678 | sub _send_headers { | ||||||||||||||||||||||||||||||||
679 | 57 | 57 | 74 | my $self = shift; | |||||||||||||||||||||||||||||
680 | 57 | 101 | my $q = $self->query; | ||||||||||||||||||||||||||||||
681 | 57 | 118 | my $type = $self->header_type; | ||||||||||||||||||||||||||||||
682 | |||||||||||||||||||||||||||||||||
683 | return | ||||||||||||||||||||||||||||||||
684 | 57 | 50 | 273 | $type eq 'redirect' ? $q->redirect( $self->header_props ) | |||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
100 | |||||||||||||||||||||||||||||||||
685 | : $type eq 'header' ? $q->header ( $self->header_props ) | ||||||||||||||||||||||||||||||||
686 | : $type eq 'none' ? '' | ||||||||||||||||||||||||||||||||
687 | : croak "Invalid header_type '$type'" | ||||||||||||||||||||||||||||||||
688 | } | ||||||||||||||||||||||||||||||||
689 | |||||||||||||||||||||||||||||||||
690 | # return a 2 element array modeling the first PSGI redirect values: status code and arrayref of header pairs | ||||||||||||||||||||||||||||||||
691 | sub _send_psgi_headers { | ||||||||||||||||||||||||||||||||
692 | 1 | 1 | 2 | my $self = shift; | |||||||||||||||||||||||||||||
693 | 1 | 2 | my $q = $self->query; | ||||||||||||||||||||||||||||||
694 | 1 | 3 | my $type = $self->header_type; | ||||||||||||||||||||||||||||||
695 | |||||||||||||||||||||||||||||||||
696 | return | ||||||||||||||||||||||||||||||||
697 | 1 | 0 | 7 | $type eq 'redirect' ? $q->psgi_redirect( $self->header_props ) | |||||||||||||||||||||||||||||
50 | |||||||||||||||||||||||||||||||||
50 | |||||||||||||||||||||||||||||||||
698 | : $type eq 'header' ? $q->psgi_header ( $self->header_props ) | ||||||||||||||||||||||||||||||||
699 | : $type eq 'none' ? '' | ||||||||||||||||||||||||||||||||
700 | : croak "Invalid header_type '$type'" | ||||||||||||||||||||||||||||||||
701 | |||||||||||||||||||||||||||||||||
702 | } | ||||||||||||||||||||||||||||||||
703 | |||||||||||||||||||||||||||||||||
704 | |||||||||||||||||||||||||||||||||
705 | # Make all hash keys CAPITAL | ||||||||||||||||||||||||||||||||
706 | # although this method is internal, some other extensions | ||||||||||||||||||||||||||||||||
707 | # have come to rely on it, so any changes here should be | ||||||||||||||||||||||||||||||||
708 | # made with great care or avoided. | ||||||||||||||||||||||||||||||||
709 | sub _cap_hash { | ||||||||||||||||||||||||||||||||
710 | 69 | 69 | 85 | my $self = shift; | |||||||||||||||||||||||||||||
711 | 69 | 67 | my $rhash = shift; | ||||||||||||||||||||||||||||||
712 | 26 | 37 | my %hash = map { | ||||||||||||||||||||||||||||||
713 | 69 | 187 | my $k = $_; | ||||||||||||||||||||||||||||||
714 | 26 | 35 | my $v = $rhash->{$k}; | ||||||||||||||||||||||||||||||
715 | 26 | 53 | $k =~ tr/a-z/A-Z/; | ||||||||||||||||||||||||||||||
716 | 26 | 164 | $k => $v; | ||||||||||||||||||||||||||||||
717 | 69 | 108 | } keys(%{$rhash}); | ||||||||||||||||||||||||||||||
718 | 69 | 166 | return \%hash; | ||||||||||||||||||||||||||||||
719 | } | ||||||||||||||||||||||||||||||||
720 | |||||||||||||||||||||||||||||||||
721 | |||||||||||||||||||||||||||||||||
722 | |||||||||||||||||||||||||||||||||
723 | 1; | ||||||||||||||||||||||||||||||||
724 | |||||||||||||||||||||||||||||||||
725 | |||||||||||||||||||||||||||||||||
726 | |||||||||||||||||||||||||||||||||
727 | |||||||||||||||||||||||||||||||||
728 | =pod | ||||||||||||||||||||||||||||||||
729 | |||||||||||||||||||||||||||||||||
730 | =head1 NAME | ||||||||||||||||||||||||||||||||
731 | |||||||||||||||||||||||||||||||||
732 | CGI::Application - Framework for building reusable web-applications | ||||||||||||||||||||||||||||||||
733 | |||||||||||||||||||||||||||||||||
734 | =head1 SYNOPSIS | ||||||||||||||||||||||||||||||||
735 | |||||||||||||||||||||||||||||||||
736 | # In "WebApp.pm"... | ||||||||||||||||||||||||||||||||
737 | package WebApp; | ||||||||||||||||||||||||||||||||
738 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
739 | |||||||||||||||||||||||||||||||||
740 | # ( setup() can even be skipped for common cases. See docs below. ) | ||||||||||||||||||||||||||||||||
741 | sub setup { | ||||||||||||||||||||||||||||||||
742 | my $self = shift; | ||||||||||||||||||||||||||||||||
743 | $self->start_mode('mode1'); | ||||||||||||||||||||||||||||||||
744 | $self->mode_param('rm'); | ||||||||||||||||||||||||||||||||
745 | $self->run_modes( | ||||||||||||||||||||||||||||||||
746 | 'mode1' => 'do_stuff', | ||||||||||||||||||||||||||||||||
747 | 'mode2' => 'do_more_stuff', | ||||||||||||||||||||||||||||||||
748 | 'mode3' => 'do_something_else' | ||||||||||||||||||||||||||||||||
749 | ); | ||||||||||||||||||||||||||||||||
750 | } | ||||||||||||||||||||||||||||||||
751 | sub do_stuff { ... } | ||||||||||||||||||||||||||||||||
752 | sub do_more_stuff { ... } | ||||||||||||||||||||||||||||||||
753 | sub do_something_else { ... } | ||||||||||||||||||||||||||||||||
754 | 1; | ||||||||||||||||||||||||||||||||
755 | |||||||||||||||||||||||||||||||||
756 | |||||||||||||||||||||||||||||||||
757 | ### In "webapp.cgi"... | ||||||||||||||||||||||||||||||||
758 | use WebApp; | ||||||||||||||||||||||||||||||||
759 | my $webapp = WebApp->new(); | ||||||||||||||||||||||||||||||||
760 | $webapp->run(); | ||||||||||||||||||||||||||||||||
761 | |||||||||||||||||||||||||||||||||
762 | ### Or, in a PSGI file, webapp.psgi | ||||||||||||||||||||||||||||||||
763 | use WebApp; | ||||||||||||||||||||||||||||||||
764 | WebApp->psgi_app(); | ||||||||||||||||||||||||||||||||
765 | |||||||||||||||||||||||||||||||||
766 | =head1 INTRODUCTION | ||||||||||||||||||||||||||||||||
767 | |||||||||||||||||||||||||||||||||
768 | CGI::Application makes it easier to create sophisticated, high-performance, | ||||||||||||||||||||||||||||||||
769 | reusable web-based applications. CGI::Application helps makes your web | ||||||||||||||||||||||||||||||||
770 | applications easier to design, write, and evolve. | ||||||||||||||||||||||||||||||||
771 | |||||||||||||||||||||||||||||||||
772 | CGI::Application judiciously avoids employing technologies and techniques which | ||||||||||||||||||||||||||||||||
773 | would bind a developer to any one set of tools, operating system or web server. | ||||||||||||||||||||||||||||||||
774 | |||||||||||||||||||||||||||||||||
775 | It is lightweight in terms of memory usage, making it suitable for common CGI | ||||||||||||||||||||||||||||||||
776 | environments, and a high performance choice in persistent environments like | ||||||||||||||||||||||||||||||||
777 | FastCGI or mod_perl. | ||||||||||||||||||||||||||||||||
778 | |||||||||||||||||||||||||||||||||
779 | By adding L |
||||||||||||||||||||||||||||||||
780 | features when you need them. | ||||||||||||||||||||||||||||||||
781 | |||||||||||||||||||||||||||||||||
782 | First released in 2000 and used and expanded by a number of professional | ||||||||||||||||||||||||||||||||
783 | website developers, CGI::Application is a stable, reliable choice. | ||||||||||||||||||||||||||||||||
784 | |||||||||||||||||||||||||||||||||
785 | =head1 USAGE EXAMPLE | ||||||||||||||||||||||||||||||||
786 | |||||||||||||||||||||||||||||||||
787 | Imagine you have to write an application to search through a database | ||||||||||||||||||||||||||||||||
788 | of widgets. Your application has three screens: | ||||||||||||||||||||||||||||||||
789 | |||||||||||||||||||||||||||||||||
790 | 1. Search form | ||||||||||||||||||||||||||||||||
791 | 2. List of results | ||||||||||||||||||||||||||||||||
792 | 3. Detail of a single record | ||||||||||||||||||||||||||||||||
793 | |||||||||||||||||||||||||||||||||
794 | To write this application using CGI::Application you will create two files: | ||||||||||||||||||||||||||||||||
795 | |||||||||||||||||||||||||||||||||
796 | 1. WidgetView.pm -- Your "Application Module" | ||||||||||||||||||||||||||||||||
797 | 2. widgetview.cgi -- Your "Instance Script" | ||||||||||||||||||||||||||||||||
798 | |||||||||||||||||||||||||||||||||
799 | The Application Module contains all the code specific to your | ||||||||||||||||||||||||||||||||
800 | application functionality, and it exists outside of your web server's | ||||||||||||||||||||||||||||||||
801 | document root, somewhere in the Perl library search path. | ||||||||||||||||||||||||||||||||
802 | |||||||||||||||||||||||||||||||||
803 | The Instance Script is what is actually called by your web server. It is | ||||||||||||||||||||||||||||||||
804 | a very small, simple file which simply creates an instance of your | ||||||||||||||||||||||||||||||||
805 | application and calls an inherited method, run(). Following is the | ||||||||||||||||||||||||||||||||
806 | entirety of "widgetview.cgi": | ||||||||||||||||||||||||||||||||
807 | |||||||||||||||||||||||||||||||||
808 | #!/usr/bin/perl -w | ||||||||||||||||||||||||||||||||
809 | use WidgetView; | ||||||||||||||||||||||||||||||||
810 | my $webapp = WidgetView->new(); | ||||||||||||||||||||||||||||||||
811 | $webapp->run(); | ||||||||||||||||||||||||||||||||
812 | |||||||||||||||||||||||||||||||||
813 | As you can see, widgetview.cgi simply "uses" your Application module | ||||||||||||||||||||||||||||||||
814 | (which implements a Perl package called "WidgetView"). Your Application Module, | ||||||||||||||||||||||||||||||||
815 | "WidgetView.pm", is somewhat more lengthy: | ||||||||||||||||||||||||||||||||
816 | |||||||||||||||||||||||||||||||||
817 | package WidgetView; | ||||||||||||||||||||||||||||||||
818 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
819 | use strict; | ||||||||||||||||||||||||||||||||
820 | |||||||||||||||||||||||||||||||||
821 | # Needed for our database connection | ||||||||||||||||||||||||||||||||
822 | use CGI::Application::Plugin::DBH; | ||||||||||||||||||||||||||||||||
823 | |||||||||||||||||||||||||||||||||
824 | sub setup { | ||||||||||||||||||||||||||||||||
825 | my $self = shift; | ||||||||||||||||||||||||||||||||
826 | $self->start_mode('mode1'); | ||||||||||||||||||||||||||||||||
827 | $self->run_modes( | ||||||||||||||||||||||||||||||||
828 | 'mode1' => 'showform', | ||||||||||||||||||||||||||||||||
829 | 'mode2' => 'showlist', | ||||||||||||||||||||||||||||||||
830 | 'mode3' => 'showdetail' | ||||||||||||||||||||||||||||||||
831 | ); | ||||||||||||||||||||||||||||||||
832 | |||||||||||||||||||||||||||||||||
833 | # Connect to DBI database, with the same args as DBI->connect(); | ||||||||||||||||||||||||||||||||
834 | $self->dbh_config(); | ||||||||||||||||||||||||||||||||
835 | } | ||||||||||||||||||||||||||||||||
836 | |||||||||||||||||||||||||||||||||
837 | sub teardown { | ||||||||||||||||||||||||||||||||
838 | my $self = shift; | ||||||||||||||||||||||||||||||||
839 | |||||||||||||||||||||||||||||||||
840 | # Disconnect when we're done, (Although DBI usually does this automatically) | ||||||||||||||||||||||||||||||||
841 | $self->dbh->disconnect(); | ||||||||||||||||||||||||||||||||
842 | } | ||||||||||||||||||||||||||||||||
843 | |||||||||||||||||||||||||||||||||
844 | sub showform { | ||||||||||||||||||||||||||||||||
845 | my $self = shift; | ||||||||||||||||||||||||||||||||
846 | |||||||||||||||||||||||||||||||||
847 | # Get CGI query object | ||||||||||||||||||||||||||||||||
848 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
849 | |||||||||||||||||||||||||||||||||
850 | my $output = ''; | ||||||||||||||||||||||||||||||||
851 | $output .= $q->start_html(-title => 'Widget Search Form'); | ||||||||||||||||||||||||||||||||
852 | $output .= $q->start_form(); | ||||||||||||||||||||||||||||||||
853 | $output .= $q->textfield(-name => 'widgetcode'); | ||||||||||||||||||||||||||||||||
854 | $output .= $q->hidden(-name => 'rm', -value => 'mode2'); | ||||||||||||||||||||||||||||||||
855 | $output .= $q->submit(); | ||||||||||||||||||||||||||||||||
856 | $output .= $q->end_form(); | ||||||||||||||||||||||||||||||||
857 | $output .= $q->end_html(); | ||||||||||||||||||||||||||||||||
858 | |||||||||||||||||||||||||||||||||
859 | return $output; | ||||||||||||||||||||||||||||||||
860 | } | ||||||||||||||||||||||||||||||||
861 | |||||||||||||||||||||||||||||||||
862 | sub showlist { | ||||||||||||||||||||||||||||||||
863 | my $self = shift; | ||||||||||||||||||||||||||||||||
864 | |||||||||||||||||||||||||||||||||
865 | # Get our database connection | ||||||||||||||||||||||||||||||||
866 | my $dbh = $self->dbh(); | ||||||||||||||||||||||||||||||||
867 | |||||||||||||||||||||||||||||||||
868 | # Get CGI query object | ||||||||||||||||||||||||||||||||
869 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
870 | my $widgetcode = $q->param("widgetcode"); | ||||||||||||||||||||||||||||||||
871 | |||||||||||||||||||||||||||||||||
872 | my $output = ''; | ||||||||||||||||||||||||||||||||
873 | $output .= $q->start_html(-title => 'List of Matching Widgets'); | ||||||||||||||||||||||||||||||||
874 | |||||||||||||||||||||||||||||||||
875 | ## Do a bunch of stuff to select "widgets" from a DBI-connected | ||||||||||||||||||||||||||||||||
876 | ## database which match the user-supplied value of "widgetcode" | ||||||||||||||||||||||||||||||||
877 | ## which has been supplied from the previous HTML form via a | ||||||||||||||||||||||||||||||||
878 | ## CGI.pm query object. | ||||||||||||||||||||||||||||||||
879 | ## | ||||||||||||||||||||||||||||||||
880 | ## Each row will contain a link to a "Widget Detail" which | ||||||||||||||||||||||||||||||||
881 | ## provides an anchor tag, as follows: | ||||||||||||||||||||||||||||||||
882 | ## | ||||||||||||||||||||||||||||||||
883 | ## "widgetview.cgi?rm=mode3&widgetid=XXX" | ||||||||||||||||||||||||||||||||
884 | ## | ||||||||||||||||||||||||||||||||
885 | ## ...Where "XXX" is a unique value referencing the ID of | ||||||||||||||||||||||||||||||||
886 | ## the particular "widget" upon which the user has clicked. | ||||||||||||||||||||||||||||||||
887 | |||||||||||||||||||||||||||||||||
888 | $output .= $q->end_html(); | ||||||||||||||||||||||||||||||||
889 | |||||||||||||||||||||||||||||||||
890 | return $output; | ||||||||||||||||||||||||||||||||
891 | } | ||||||||||||||||||||||||||||||||
892 | |||||||||||||||||||||||||||||||||
893 | sub showdetail { | ||||||||||||||||||||||||||||||||
894 | my $self = shift; | ||||||||||||||||||||||||||||||||
895 | |||||||||||||||||||||||||||||||||
896 | # Get our database connection | ||||||||||||||||||||||||||||||||
897 | my $dbh = $self->dbh(); | ||||||||||||||||||||||||||||||||
898 | |||||||||||||||||||||||||||||||||
899 | # Get CGI query object | ||||||||||||||||||||||||||||||||
900 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
901 | my $widgetid = $q->param("widgetid"); | ||||||||||||||||||||||||||||||||
902 | |||||||||||||||||||||||||||||||||
903 | my $output = ''; | ||||||||||||||||||||||||||||||||
904 | $output .= $q->start_html(-title => 'Widget Detail'); | ||||||||||||||||||||||||||||||||
905 | |||||||||||||||||||||||||||||||||
906 | ## Do a bunch of things to select all the properties of | ||||||||||||||||||||||||||||||||
907 | ## the particular "widget" upon which the user has | ||||||||||||||||||||||||||||||||
908 | ## clicked. The key id value of this widget is provided | ||||||||||||||||||||||||||||||||
909 | ## via the "widgetid" property, accessed via the CGI.pm | ||||||||||||||||||||||||||||||||
910 | ## query object. | ||||||||||||||||||||||||||||||||
911 | |||||||||||||||||||||||||||||||||
912 | $output .= $q->end_html(); | ||||||||||||||||||||||||||||||||
913 | |||||||||||||||||||||||||||||||||
914 | return $output; | ||||||||||||||||||||||||||||||||
915 | } | ||||||||||||||||||||||||||||||||
916 | |||||||||||||||||||||||||||||||||
917 | 1; # Perl requires this at the end of all modules | ||||||||||||||||||||||||||||||||
918 | |||||||||||||||||||||||||||||||||
919 | |||||||||||||||||||||||||||||||||
920 | CGI::Application takes care of implementing the new() and the run() | ||||||||||||||||||||||||||||||||
921 | methods. Notice that at no point do you call print() to send any | ||||||||||||||||||||||||||||||||
922 | output to STDOUT. Instead, all output is returned as a scalar. | ||||||||||||||||||||||||||||||||
923 | |||||||||||||||||||||||||||||||||
924 | CGI::Application's most significant contribution is in managing | ||||||||||||||||||||||||||||||||
925 | the application state. Notice that all which is needed to push | ||||||||||||||||||||||||||||||||
926 | the application forward is to set the value of a HTML form | ||||||||||||||||||||||||||||||||
927 | parameter 'rm' to the value of the "run mode" you wish to handle | ||||||||||||||||||||||||||||||||
928 | the form submission. This is the key to CGI::Application. | ||||||||||||||||||||||||||||||||
929 | |||||||||||||||||||||||||||||||||
930 | |||||||||||||||||||||||||||||||||
931 | =head1 ABSTRACT | ||||||||||||||||||||||||||||||||
932 | |||||||||||||||||||||||||||||||||
933 | The guiding philosophy behind CGI::Application is that a web-based | ||||||||||||||||||||||||||||||||
934 | application can be organized into a specific set of "Run Modes." | ||||||||||||||||||||||||||||||||
935 | Each Run Mode is roughly analogous to a single screen (a form, some | ||||||||||||||||||||||||||||||||
936 | output, etc.). All the Run Modes are managed by a single "Application | ||||||||||||||||||||||||||||||||
937 | Module" which is a Perl module. In your web server's document space | ||||||||||||||||||||||||||||||||
938 | there is an "Instance Script" which is called by the web server as a | ||||||||||||||||||||||||||||||||
939 | CGI (or an Apache::Registry script if you're using Apache + mod_perl). | ||||||||||||||||||||||||||||||||
940 | |||||||||||||||||||||||||||||||||
941 | This methodology is an inversion of the "Embedded" philosophy (ASP, JSP, | ||||||||||||||||||||||||||||||||
942 | EmbPerl, Mason, etc.) in which there are "pages" for each state of the | ||||||||||||||||||||||||||||||||
943 | application, and the page drives functionality. In CGI::Application, | ||||||||||||||||||||||||||||||||
944 | form follows function -- the Application Module drives pages, and the | ||||||||||||||||||||||||||||||||
945 | code for a single application is in one place; not spread out over | ||||||||||||||||||||||||||||||||
946 | multiple "pages". If you feel that Embedded architectures are | ||||||||||||||||||||||||||||||||
947 | confusing, unorganized, difficult to design and difficult to manage, | ||||||||||||||||||||||||||||||||
948 | CGI::Application is the methodology for you! | ||||||||||||||||||||||||||||||||
949 | |||||||||||||||||||||||||||||||||
950 | Apache is NOT a requirement for CGI::Application. Web applications based on | ||||||||||||||||||||||||||||||||
951 | CGI::Application will run equally well on NT/IIS or any other | ||||||||||||||||||||||||||||||||
952 | CGI-compatible environment. CGI::Application-based projects | ||||||||||||||||||||||||||||||||
953 | are, however, ripe for use on Apache/mod_perl servers, as they | ||||||||||||||||||||||||||||||||
954 | naturally encourage Good Programming Practices and will often work | ||||||||||||||||||||||||||||||||
955 | in persistent environments without modification. | ||||||||||||||||||||||||||||||||
956 | |||||||||||||||||||||||||||||||||
957 | For more information on using CGI::Application with mod_perl, please see our | ||||||||||||||||||||||||||||||||
958 | website at http://www.cgi-app.org/, as well as | ||||||||||||||||||||||||||||||||
959 | L |
||||||||||||||||||||||||||||||||
960 | |||||||||||||||||||||||||||||||||
961 | =head1 DESCRIPTION | ||||||||||||||||||||||||||||||||
962 | |||||||||||||||||||||||||||||||||
963 | It is intended that your Application Module will be implemented as a sub-class | ||||||||||||||||||||||||||||||||
964 | of CGI::Application. This is done simply as follows: | ||||||||||||||||||||||||||||||||
965 | |||||||||||||||||||||||||||||||||
966 | package My::App; | ||||||||||||||||||||||||||||||||
967 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
968 | |||||||||||||||||||||||||||||||||
969 | B |
||||||||||||||||||||||||||||||||
970 | |||||||||||||||||||||||||||||||||
971 | For the purpose of this document, we will refer to the | ||||||||||||||||||||||||||||||||
972 | following conventions: | ||||||||||||||||||||||||||||||||
973 | |||||||||||||||||||||||||||||||||
974 | WebApp.pm The Perl module which implements your Application Module class. | ||||||||||||||||||||||||||||||||
975 | WebApp Your Application Module class; a sub-class of CGI::Application. | ||||||||||||||||||||||||||||||||
976 | webapp.cgi The Instance Script which implements your Application Module. | ||||||||||||||||||||||||||||||||
977 | $webapp An instance (object) of your Application Module class. | ||||||||||||||||||||||||||||||||
978 | $c Same as $webapp, used in instance methods to pass around the | ||||||||||||||||||||||||||||||||
979 | current object. (Sometimes referred as "$self" in other code) | ||||||||||||||||||||||||||||||||
980 | |||||||||||||||||||||||||||||||||
981 | |||||||||||||||||||||||||||||||||
982 | |||||||||||||||||||||||||||||||||
983 | |||||||||||||||||||||||||||||||||
984 | =head2 Instance Script Methods | ||||||||||||||||||||||||||||||||
985 | |||||||||||||||||||||||||||||||||
986 | By inheriting from CGI::Application you have access to a | ||||||||||||||||||||||||||||||||
987 | number of built-in methods. The following are those which | ||||||||||||||||||||||||||||||||
988 | are expected to be called from your Instance Script. | ||||||||||||||||||||||||||||||||
989 | |||||||||||||||||||||||||||||||||
990 | =head3 new() | ||||||||||||||||||||||||||||||||
991 | |||||||||||||||||||||||||||||||||
992 | The new() method is the constructor for a CGI::Application. It returns | ||||||||||||||||||||||||||||||||
993 | a blessed reference to your Application Module package (class). Optionally, | ||||||||||||||||||||||||||||||||
994 | new() may take a set of parameters as key => value pairs: | ||||||||||||||||||||||||||||||||
995 | |||||||||||||||||||||||||||||||||
996 | my $webapp = WebApp->new( | ||||||||||||||||||||||||||||||||
997 | TMPL_PATH => 'App/', | ||||||||||||||||||||||||||||||||
998 | PARAMS => { | ||||||||||||||||||||||||||||||||
999 | 'custom_thing_1' => 'some val', | ||||||||||||||||||||||||||||||||
1000 | 'another_custom_thing' => [qw/123 456/] | ||||||||||||||||||||||||||||||||
1001 | } | ||||||||||||||||||||||||||||||||
1002 | ); | ||||||||||||||||||||||||||||||||
1003 | |||||||||||||||||||||||||||||||||
1004 | This method may take some specific parameters: | ||||||||||||||||||||||||||||||||
1005 | |||||||||||||||||||||||||||||||||
1006 | B |
||||||||||||||||||||||||||||||||
1007 | This is used by the load_tmpl() method (specified below), and may also be used | ||||||||||||||||||||||||||||||||
1008 | for the same purpose by other template plugins. This run-time parameter allows | ||||||||||||||||||||||||||||||||
1009 | you to further encapsulate instantiating templates, providing potential for | ||||||||||||||||||||||||||||||||
1010 | more re-usability. It can be either a scalar or an array reference of multiple | ||||||||||||||||||||||||||||||||
1011 | paths. | ||||||||||||||||||||||||||||||||
1012 | |||||||||||||||||||||||||||||||||
1013 | B |
||||||||||||||||||||||||||||||||
1014 | already-created CGI.pm query object. Under normal use, | ||||||||||||||||||||||||||||||||
1015 | CGI::Application will instantiate its own CGI.pm query object. | ||||||||||||||||||||||||||||||||
1016 | Under certain conditions, it might be useful to be able to use | ||||||||||||||||||||||||||||||||
1017 | one which has already been created. | ||||||||||||||||||||||||||||||||
1018 | |||||||||||||||||||||||||||||||||
1019 | B |
||||||||||||||||||||||||||||||||
1020 | of custom parameters at run-time. By passing in different | ||||||||||||||||||||||||||||||||
1021 | values in different instance scripts which use the same application | ||||||||||||||||||||||||||||||||
1022 | module you can achieve a higher level of re-usability. For instance, | ||||||||||||||||||||||||||||||||
1023 | imagine an application module, "Mailform.pm". The application takes | ||||||||||||||||||||||||||||||||
1024 | the contents of a HTML form and emails it to a specified recipient. | ||||||||||||||||||||||||||||||||
1025 | You could have multiple instance scripts throughout your site which | ||||||||||||||||||||||||||||||||
1026 | all use this "Mailform.pm" module, but which set different recipients | ||||||||||||||||||||||||||||||||
1027 | or different forms. | ||||||||||||||||||||||||||||||||
1028 | |||||||||||||||||||||||||||||||||
1029 | One common use of instance scripts is to provide a path to a config file. This | ||||||||||||||||||||||||||||||||
1030 | design allows you to define project wide configuration objects used by many | ||||||||||||||||||||||||||||||||
1031 | several instance scripts. There are several plugins which simplify the syntax | ||||||||||||||||||||||||||||||||
1032 | for this and provide lazy loading. Here's an example using | ||||||||||||||||||||||||||||||||
1033 | L |
||||||||||||||||||||||||||||||||
1034 | many configuration file formats. | ||||||||||||||||||||||||||||||||
1035 | |||||||||||||||||||||||||||||||||
1036 | my $app = WebApp->new(PARAMS => { cfg_file => 'config.pl' }); | ||||||||||||||||||||||||||||||||
1037 | |||||||||||||||||||||||||||||||||
1038 | # Later in your app: | ||||||||||||||||||||||||||||||||
1039 | my %cfg = $self->cfg() | ||||||||||||||||||||||||||||||||
1040 | # or ... $self->cfg('HTML_ROOT_DIR'); | ||||||||||||||||||||||||||||||||
1041 | |||||||||||||||||||||||||||||||||
1042 | See the list of plugins below for more config file integration solutions. | ||||||||||||||||||||||||||||||||
1043 | |||||||||||||||||||||||||||||||||
1044 | =head3 run() | ||||||||||||||||||||||||||||||||
1045 | |||||||||||||||||||||||||||||||||
1046 | The run() method is called upon your Application Module object, from | ||||||||||||||||||||||||||||||||
1047 | your Instance Script. When called, it executes the functionality | ||||||||||||||||||||||||||||||||
1048 | in your Application Module. | ||||||||||||||||||||||||||||||||
1049 | |||||||||||||||||||||||||||||||||
1050 | my $webapp = WebApp->new(); | ||||||||||||||||||||||||||||||||
1051 | $webapp->run(); | ||||||||||||||||||||||||||||||||
1052 | |||||||||||||||||||||||||||||||||
1053 | This method first determines the application state by looking at the | ||||||||||||||||||||||||||||||||
1054 | value of the CGI parameter specified by mode_param() (defaults to | ||||||||||||||||||||||||||||||||
1055 | 'rm' for "Run Mode"), which is expected to contain the name of the mode of | ||||||||||||||||||||||||||||||||
1056 | operation. If not specified, the state defaults to the value | ||||||||||||||||||||||||||||||||
1057 | of start_mode(). | ||||||||||||||||||||||||||||||||
1058 | |||||||||||||||||||||||||||||||||
1059 | Once the mode has been determined, run() looks at the dispatch | ||||||||||||||||||||||||||||||||
1060 | table stored in run_modes() and finds the function pointer which | ||||||||||||||||||||||||||||||||
1061 | is keyed from the mode name. If found, the function is called and the | ||||||||||||||||||||||||||||||||
1062 | data returned is print()'ed to STDOUT and to the browser. If | ||||||||||||||||||||||||||||||||
1063 | the specified mode is not found in the run_modes() table, run() will | ||||||||||||||||||||||||||||||||
1064 | croak(). | ||||||||||||||||||||||||||||||||
1065 | |||||||||||||||||||||||||||||||||
1066 | =head2 PSGI support | ||||||||||||||||||||||||||||||||
1067 | |||||||||||||||||||||||||||||||||
1068 | CGI::Application offers native L |
||||||||||||||||||||||||||||||||
1069 | for this is L |
||||||||||||||||||||||||||||||||
1070 | support to it. | ||||||||||||||||||||||||||||||||
1071 | |||||||||||||||||||||||||||||||||
1072 | =head3 psgi_app() | ||||||||||||||||||||||||||||||||
1073 | |||||||||||||||||||||||||||||||||
1074 | $psgi_coderef = WebApp->psgi_app({ ... args to new() ... }); | ||||||||||||||||||||||||||||||||
1075 | |||||||||||||||||||||||||||||||||
1076 | The simplest way to create and return a PSGI-compatible coderef. Pass in | ||||||||||||||||||||||||||||||||
1077 | arguments to a hashref just as would to new. This returns a PSGI-compatible | ||||||||||||||||||||||||||||||||
1078 | coderef, using L |
||||||||||||||||||||||||||||||||
1079 | object, construct your own object using C<< run_as_psgi() >>, as shown below. | ||||||||||||||||||||||||||||||||
1080 | |||||||||||||||||||||||||||||||||
1081 | It's possible that we'll change from CGI::PSGI to a different-but-compatible | ||||||||||||||||||||||||||||||||
1082 | query object for PSGI support in the future, perhaps if CGI.pm adds native | ||||||||||||||||||||||||||||||||
1083 | PSGI support. | ||||||||||||||||||||||||||||||||
1084 | |||||||||||||||||||||||||||||||||
1085 | =head3 run_as_psgi() | ||||||||||||||||||||||||||||||||
1086 | |||||||||||||||||||||||||||||||||
1087 | my $psgi_aref = $webapp->run_as_psgi; | ||||||||||||||||||||||||||||||||
1088 | |||||||||||||||||||||||||||||||||
1089 | Just like C<< run >>, but prints no output and returns the data structure | ||||||||||||||||||||||||||||||||
1090 | required by the L |
||||||||||||||||||||||||||||||||
1091 | application on top of a PSGI-compatible handler, such as L |
||||||||||||||||||||||||||||||||
1092 | |||||||||||||||||||||||||||||||||
1093 | If you are just getting started, just use C<< run() >>. It's easy to switch to using | ||||||||||||||||||||||||||||||||
1094 | C<< run_as_psgi >> later. | ||||||||||||||||||||||||||||||||
1095 | |||||||||||||||||||||||||||||||||
1096 | Why use C<< run_as_psgi() >>? There are already solutions to run | ||||||||||||||||||||||||||||||||
1097 | CGI::Application-based projects on several web servers with dozens of plugins. | ||||||||||||||||||||||||||||||||
1098 | Running as a PSGI-compatible application provides the ability to run on | ||||||||||||||||||||||||||||||||
1099 | additional PSGI-compatible servers, as well as providing access to all of the | ||||||||||||||||||||||||||||||||
1100 | "Middleware" solutions available through the L |
||||||||||||||||||||||||||||||||
1101 | |||||||||||||||||||||||||||||||||
1102 | The structure returned is an arrayref, containing the status code, an arrayref | ||||||||||||||||||||||||||||||||
1103 | of header key/values and an arrayref containing the body. | ||||||||||||||||||||||||||||||||
1104 | |||||||||||||||||||||||||||||||||
1105 | [ 200, [ 'Content-Type' => 'text/html' ], [ $body ] ] | ||||||||||||||||||||||||||||||||
1106 | |||||||||||||||||||||||||||||||||
1107 | By default the body is a single scalar, but plugins may modify this to return | ||||||||||||||||||||||||||||||||
1108 | other value PSGI values. See L |
||||||||||||||||||||||||||||||||
1109 | response format. | ||||||||||||||||||||||||||||||||
1110 | |||||||||||||||||||||||||||||||||
1111 | Note that calling C<< run_as_psgi >> only handles the I | ||||||||||||||||||||||||||||||||
1112 | PSGI spec. to handle the input, you need to use a CGI.pm-like query object that | ||||||||||||||||||||||||||||||||
1113 | is PSGI-compliant, such as L |
||||||||||||||||||||||||||||||||
1114 | and L |
||||||||||||||||||||||||||||||||
1115 | |||||||||||||||||||||||||||||||||
1116 | The final result might look like this: | ||||||||||||||||||||||||||||||||
1117 | |||||||||||||||||||||||||||||||||
1118 | use WebApp; | ||||||||||||||||||||||||||||||||
1119 | use CGI::PSGI; | ||||||||||||||||||||||||||||||||
1120 | |||||||||||||||||||||||||||||||||
1121 | my $handler = sub { | ||||||||||||||||||||||||||||||||
1122 | my $env = shift; | ||||||||||||||||||||||||||||||||
1123 | my $webapp = WebApp->new({ QUERY => CGI::PSGI->new($env) }); | ||||||||||||||||||||||||||||||||
1124 | $webapp->run_as_psgi; | ||||||||||||||||||||||||||||||||
1125 | }; | ||||||||||||||||||||||||||||||||
1126 | |||||||||||||||||||||||||||||||||
1127 | =head2 Additional PSGI Return Values | ||||||||||||||||||||||||||||||||
1128 | |||||||||||||||||||||||||||||||||
1129 | The PSGI Specification allows for returning a file handle or a subroutine reference instead of byte strings. In PSGI mode this is supported directly by CGI::Application. Have your run mode return a file handle or compatible subref as follows: | ||||||||||||||||||||||||||||||||
1130 | |||||||||||||||||||||||||||||||||
1131 | sub returning_a_file_handle { | ||||||||||||||||||||||||||||||||
1132 | my $self = shift; | ||||||||||||||||||||||||||||||||
1133 | |||||||||||||||||||||||||||||||||
1134 | $self->header_props(-type => 'text/plain'); | ||||||||||||||||||||||||||||||||
1135 | |||||||||||||||||||||||||||||||||
1136 | open my $fh, "<", 'test_file.txt' or die "OOPS! $!"; | ||||||||||||||||||||||||||||||||
1137 | |||||||||||||||||||||||||||||||||
1138 | return $fh; | ||||||||||||||||||||||||||||||||
1139 | } | ||||||||||||||||||||||||||||||||
1140 | |||||||||||||||||||||||||||||||||
1141 | sub returning_a_subref { | ||||||||||||||||||||||||||||||||
1142 | my $self = shift; | ||||||||||||||||||||||||||||||||
1143 | |||||||||||||||||||||||||||||||||
1144 | $self->header_props(-type => 'text/plain'); | ||||||||||||||||||||||||||||||||
1145 | return sub { | ||||||||||||||||||||||||||||||||
1146 | my $writer = shift; | ||||||||||||||||||||||||||||||||
1147 | foreach my $i (1..10) { | ||||||||||||||||||||||||||||||||
1148 | #sleep 1; | ||||||||||||||||||||||||||||||||
1149 | $writer->write("check $i: " . time . "\n"); | ||||||||||||||||||||||||||||||||
1150 | } | ||||||||||||||||||||||||||||||||
1151 | }; | ||||||||||||||||||||||||||||||||
1152 | } | ||||||||||||||||||||||||||||||||
1153 | |||||||||||||||||||||||||||||||||
1154 | =head2 Methods to possibly override | ||||||||||||||||||||||||||||||||
1155 | |||||||||||||||||||||||||||||||||
1156 | CGI::Application implements some methods which are expected to be overridden | ||||||||||||||||||||||||||||||||
1157 | by implementing them in your sub-class module. These methods are as follows: | ||||||||||||||||||||||||||||||||
1158 | |||||||||||||||||||||||||||||||||
1159 | =head3 setup() | ||||||||||||||||||||||||||||||||
1160 | |||||||||||||||||||||||||||||||||
1161 | This method is called by the inherited new() constructor method. The | ||||||||||||||||||||||||||||||||
1162 | setup() method should be used to define the following property/methods: | ||||||||||||||||||||||||||||||||
1163 | |||||||||||||||||||||||||||||||||
1164 | mode_param() - set the name of the run mode CGI param. | ||||||||||||||||||||||||||||||||
1165 | start_mode() - text scalar containing the default run mode. | ||||||||||||||||||||||||||||||||
1166 | error_mode() - text scalar containing the error mode. | ||||||||||||||||||||||||||||||||
1167 | run_modes() - hash table containing mode => function mappings. | ||||||||||||||||||||||||||||||||
1168 | tmpl_path() - text scalar or array reference containing path(s) to template files. | ||||||||||||||||||||||||||||||||
1169 | |||||||||||||||||||||||||||||||||
1170 | Your setup() method may call any of the instance methods of your application. | ||||||||||||||||||||||||||||||||
1171 | This function is a good place to define properties specific to your application | ||||||||||||||||||||||||||||||||
1172 | via the $webapp->param() method. | ||||||||||||||||||||||||||||||||
1173 | |||||||||||||||||||||||||||||||||
1174 | Your setup() method might be implemented something like this: | ||||||||||||||||||||||||||||||||
1175 | |||||||||||||||||||||||||||||||||
1176 | sub setup { | ||||||||||||||||||||||||||||||||
1177 | my $self = shift; | ||||||||||||||||||||||||||||||||
1178 | $self->tmpl_path('/path/to/my/templates/'); | ||||||||||||||||||||||||||||||||
1179 | $self->start_mode('putform'); | ||||||||||||||||||||||||||||||||
1180 | $self->error_mode('my_error_rm'); | ||||||||||||||||||||||||||||||||
1181 | $self->run_modes({ | ||||||||||||||||||||||||||||||||
1182 | 'putform' => 'my_putform_func', | ||||||||||||||||||||||||||||||||
1183 | 'postdata' => 'my_data_func' | ||||||||||||||||||||||||||||||||
1184 | }); | ||||||||||||||||||||||||||||||||
1185 | $self->param('myprop1'); | ||||||||||||||||||||||||||||||||
1186 | $self->param('myprop2', 'prop2value'); | ||||||||||||||||||||||||||||||||
1187 | $self->param('myprop3', ['p3v1', 'p3v2', 'p3v3']); | ||||||||||||||||||||||||||||||||
1188 | } | ||||||||||||||||||||||||||||||||
1189 | |||||||||||||||||||||||||||||||||
1190 | However, often times all that needs to be in setup() is defining your run modes | ||||||||||||||||||||||||||||||||
1191 | and your start mode. L |
||||||||||||||||||||||||||||||||
1192 | this with a simple syntax, using run mode attributes: | ||||||||||||||||||||||||||||||||
1193 | |||||||||||||||||||||||||||||||||
1194 | use CGI::Application::Plugin::AutoRunmode; | ||||||||||||||||||||||||||||||||
1195 | |||||||||||||||||||||||||||||||||
1196 | sub show_first : StartRunmode { ... }; | ||||||||||||||||||||||||||||||||
1197 | sub do_next : Runmode { ... } | ||||||||||||||||||||||||||||||||
1198 | |||||||||||||||||||||||||||||||||
1199 | =head3 teardown() | ||||||||||||||||||||||||||||||||
1200 | |||||||||||||||||||||||||||||||||
1201 | If implemented, this method is called automatically after your application runs. It | ||||||||||||||||||||||||||||||||
1202 | can be used to clean up after your operations. A typical use of the | ||||||||||||||||||||||||||||||||
1203 | teardown() function is to disconnect a database connection which was | ||||||||||||||||||||||||||||||||
1204 | established in the setup() function. You could also use the teardown() | ||||||||||||||||||||||||||||||||
1205 | method to store state information about the application to the server. | ||||||||||||||||||||||||||||||||
1206 | |||||||||||||||||||||||||||||||||
1207 | |||||||||||||||||||||||||||||||||
1208 | =head3 cgiapp_init() | ||||||||||||||||||||||||||||||||
1209 | |||||||||||||||||||||||||||||||||
1210 | If implemented, this method is called automatically right before the | ||||||||||||||||||||||||||||||||
1211 | setup() method is called. This method provides an optional initialization | ||||||||||||||||||||||||||||||||
1212 | hook, which improves the object-oriented characteristics of | ||||||||||||||||||||||||||||||||
1213 | CGI::Application. The cgiapp_init() method receives, as its parameters, | ||||||||||||||||||||||||||||||||
1214 | all the arguments which were sent to the new() method. | ||||||||||||||||||||||||||||||||
1215 | |||||||||||||||||||||||||||||||||
1216 | An example of the benefits provided by utilizing this hook is | ||||||||||||||||||||||||||||||||
1217 | creating a custom "application super-class" from which all | ||||||||||||||||||||||||||||||||
1218 | your web applications would inherit, instead of CGI::Application. | ||||||||||||||||||||||||||||||||
1219 | |||||||||||||||||||||||||||||||||
1220 | Consider the following: | ||||||||||||||||||||||||||||||||
1221 | |||||||||||||||||||||||||||||||||
1222 | # In MySuperclass.pm: | ||||||||||||||||||||||||||||||||
1223 | package MySuperclass; | ||||||||||||||||||||||||||||||||
1224 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
1225 | sub cgiapp_init { | ||||||||||||||||||||||||||||||||
1226 | my $self = shift; | ||||||||||||||||||||||||||||||||
1227 | # Perform some project-specific init behavior | ||||||||||||||||||||||||||||||||
1228 | # such as to load settings from a database or file. | ||||||||||||||||||||||||||||||||
1229 | } | ||||||||||||||||||||||||||||||||
1230 | |||||||||||||||||||||||||||||||||
1231 | |||||||||||||||||||||||||||||||||
1232 | # In MyApplication.pm: | ||||||||||||||||||||||||||||||||
1233 | package MyApplication; | ||||||||||||||||||||||||||||||||
1234 | use base 'MySuperclass'; | ||||||||||||||||||||||||||||||||
1235 | sub setup { ... } | ||||||||||||||||||||||||||||||||
1236 | sub teardown { ... } | ||||||||||||||||||||||||||||||||
1237 | # The rest of your CGI::Application-based follows... | ||||||||||||||||||||||||||||||||
1238 | |||||||||||||||||||||||||||||||||
1239 | |||||||||||||||||||||||||||||||||
1240 | By using CGI::Application and the cgiapp_init() method as illustrated, | ||||||||||||||||||||||||||||||||
1241 | a suite of applications could be designed to share certain | ||||||||||||||||||||||||||||||||
1242 | characteristics. This has the potential for much cleaner code | ||||||||||||||||||||||||||||||||
1243 | built on object-oriented inheritance. | ||||||||||||||||||||||||||||||||
1244 | |||||||||||||||||||||||||||||||||
1245 | |||||||||||||||||||||||||||||||||
1246 | =head3 cgiapp_prerun() | ||||||||||||||||||||||||||||||||
1247 | |||||||||||||||||||||||||||||||||
1248 | If implemented, this method is called automatically right before the | ||||||||||||||||||||||||||||||||
1249 | selected run mode method is called. This method provides an optional | ||||||||||||||||||||||||||||||||
1250 | pre-runmode hook, which permits functionality to be added at the point | ||||||||||||||||||||||||||||||||
1251 | right before the run mode method is called. To further leverage this | ||||||||||||||||||||||||||||||||
1252 | hook, the value of the run mode is passed into cgiapp_prerun(). | ||||||||||||||||||||||||||||||||
1253 | |||||||||||||||||||||||||||||||||
1254 | Another benefit provided by utilizing this hook is | ||||||||||||||||||||||||||||||||
1255 | creating a custom "application super-class" from which all | ||||||||||||||||||||||||||||||||
1256 | your web applications would inherit, instead of CGI::Application. | ||||||||||||||||||||||||||||||||
1257 | |||||||||||||||||||||||||||||||||
1258 | Consider the following: | ||||||||||||||||||||||||||||||||
1259 | |||||||||||||||||||||||||||||||||
1260 | # In MySuperclass.pm: | ||||||||||||||||||||||||||||||||
1261 | package MySuperclass; | ||||||||||||||||||||||||||||||||
1262 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
1263 | sub cgiapp_prerun { | ||||||||||||||||||||||||||||||||
1264 | my $self = shift; | ||||||||||||||||||||||||||||||||
1265 | # Perform some project-specific init behavior | ||||||||||||||||||||||||||||||||
1266 | # such as to implement run mode specific | ||||||||||||||||||||||||||||||||
1267 | # authorization functions. | ||||||||||||||||||||||||||||||||
1268 | } | ||||||||||||||||||||||||||||||||
1269 | |||||||||||||||||||||||||||||||||
1270 | |||||||||||||||||||||||||||||||||
1271 | # In MyApplication.pm: | ||||||||||||||||||||||||||||||||
1272 | package MyApplication; | ||||||||||||||||||||||||||||||||
1273 | use base 'MySuperclass'; | ||||||||||||||||||||||||||||||||
1274 | sub setup { ... } | ||||||||||||||||||||||||||||||||
1275 | sub teardown { ... } | ||||||||||||||||||||||||||||||||
1276 | # The rest of your CGI::Application-based follows... | ||||||||||||||||||||||||||||||||
1277 | |||||||||||||||||||||||||||||||||
1278 | |||||||||||||||||||||||||||||||||
1279 | By using CGI::Application and the cgiapp_prerun() method as illustrated, | ||||||||||||||||||||||||||||||||
1280 | a suite of applications could be designed to share certain | ||||||||||||||||||||||||||||||||
1281 | characteristics. This has the potential for much cleaner code | ||||||||||||||||||||||||||||||||
1282 | built on object-oriented inheritance. | ||||||||||||||||||||||||||||||||
1283 | |||||||||||||||||||||||||||||||||
1284 | It is also possible, within your cgiapp_prerun() method, to change the | ||||||||||||||||||||||||||||||||
1285 | run mode of your application. This can be done via the prerun_mode() | ||||||||||||||||||||||||||||||||
1286 | method, which is discussed elsewhere in this POD. | ||||||||||||||||||||||||||||||||
1287 | |||||||||||||||||||||||||||||||||
1288 | =head3 cgiapp_postrun() | ||||||||||||||||||||||||||||||||
1289 | |||||||||||||||||||||||||||||||||
1290 | If implemented, this hook will be called after the run mode method | ||||||||||||||||||||||||||||||||
1291 | has returned its output, but before HTTP headers are generated. This | ||||||||||||||||||||||||||||||||
1292 | will give you an opportunity to modify the body and headers before they | ||||||||||||||||||||||||||||||||
1293 | are returned to the web browser. | ||||||||||||||||||||||||||||||||
1294 | |||||||||||||||||||||||||||||||||
1295 | A typical use for this hook is pipelining the output of a CGI-Application | ||||||||||||||||||||||||||||||||
1296 | through a series of "filter" processors. For example: | ||||||||||||||||||||||||||||||||
1297 | |||||||||||||||||||||||||||||||||
1298 | * You want to enclose the output of all your CGI-Applications in | ||||||||||||||||||||||||||||||||
1299 | an HTML table in a larger page. | ||||||||||||||||||||||||||||||||
1300 | |||||||||||||||||||||||||||||||||
1301 | * Your run modes return structured data (such as XML), which you | ||||||||||||||||||||||||||||||||
1302 | want to transform using a standard mechanism (such as XSLT). | ||||||||||||||||||||||||||||||||
1303 | |||||||||||||||||||||||||||||||||
1304 | * You want to post-process CGI-App output through another system, | ||||||||||||||||||||||||||||||||
1305 | such as HTML::Mason. | ||||||||||||||||||||||||||||||||
1306 | |||||||||||||||||||||||||||||||||
1307 | * You want to modify HTTP headers in a particular way across all | ||||||||||||||||||||||||||||||||
1308 | run modes, based on particular criteria. | ||||||||||||||||||||||||||||||||
1309 | |||||||||||||||||||||||||||||||||
1310 | The cgiapp_postrun() hook receives a reference to the output from | ||||||||||||||||||||||||||||||||
1311 | your run mode method, in addition to the CGI-App object. A typical | ||||||||||||||||||||||||||||||||
1312 | cgiapp_postrun() method might be implemented as follows: | ||||||||||||||||||||||||||||||||
1313 | |||||||||||||||||||||||||||||||||
1314 | sub cgiapp_postrun { | ||||||||||||||||||||||||||||||||
1315 | my $self = shift; | ||||||||||||||||||||||||||||||||
1316 | my $output_ref = shift; | ||||||||||||||||||||||||||||||||
1317 | |||||||||||||||||||||||||||||||||
1318 | # Enclose output HTML table | ||||||||||||||||||||||||||||||||
1319 | my $new_output = "
|
||||||||||||||||||||||||||||||||
1323 | |||||||||||||||||||||||||||||||||
1324 | # Replace old output with new output | ||||||||||||||||||||||||||||||||
1325 | $$output_ref = $new_output; | ||||||||||||||||||||||||||||||||
1326 | } | ||||||||||||||||||||||||||||||||
1327 | |||||||||||||||||||||||||||||||||
1328 | |||||||||||||||||||||||||||||||||
1329 | Obviously, with access to the CGI-App object you have full access to use all | ||||||||||||||||||||||||||||||||
1330 | the methods normally available in a run mode. You could, for example, use | ||||||||||||||||||||||||||||||||
1331 | C |
||||||||||||||||||||||||||||||||
1332 | You could change the HTTP headers (via C |
||||||||||||||||||||||||||||||||
1333 | methods) to set up a redirect. You could also use the objects properties | ||||||||||||||||||||||||||||||||
1334 | to apply changes only under certain circumstance, such as a in only certain run | ||||||||||||||||||||||||||||||||
1335 | modes, and when a C is a particular value. | ||||||||||||||||||||||||||||||||
1336 | |||||||||||||||||||||||||||||||||
1337 | |||||||||||||||||||||||||||||||||
1338 | =head3 cgiapp_get_query() | ||||||||||||||||||||||||||||||||
1339 | |||||||||||||||||||||||||||||||||
1340 | my $q = $webapp->cgiapp_get_query; | ||||||||||||||||||||||||||||||||
1341 | |||||||||||||||||||||||||||||||||
1342 | Override this method to retrieve the query object if you wish to use a | ||||||||||||||||||||||||||||||||
1343 | different query interface instead of CGI.pm. | ||||||||||||||||||||||||||||||||
1344 | |||||||||||||||||||||||||||||||||
1345 | CGI.pm is only loaded if it is used on a given request. | ||||||||||||||||||||||||||||||||
1346 | |||||||||||||||||||||||||||||||||
1347 | If you can use an alternative to CGI.pm, it needs to have some compatibility | ||||||||||||||||||||||||||||||||
1348 | with the CGI.pm API. For normal use, just having a compatible C method | ||||||||||||||||||||||||||||||||
1349 | should be sufficient. | ||||||||||||||||||||||||||||||||
1350 | |||||||||||||||||||||||||||||||||
1351 | If you use the C |
||||||||||||||||||||||||||||||||
1352 | the C |
||||||||||||||||||||||||||||||||
1353 | |||||||||||||||||||||||||||||||||
1354 | If you use the C |
||||||||||||||||||||||||||||||||
1355 | C |
||||||||||||||||||||||||||||||||
1356 | |||||||||||||||||||||||||||||||||
1357 | =head2 Essential Application Methods | ||||||||||||||||||||||||||||||||
1358 | |||||||||||||||||||||||||||||||||
1359 | The following methods are inherited from CGI::Application, and are | ||||||||||||||||||||||||||||||||
1360 | available to be called by your application within your Application | ||||||||||||||||||||||||||||||||
1361 | Module. They are called essential because you will use all are most | ||||||||||||||||||||||||||||||||
1362 | of them to get any application up and running. These functions are listed in alphabetical order. | ||||||||||||||||||||||||||||||||
1363 | |||||||||||||||||||||||||||||||||
1364 | =head3 load_tmpl() | ||||||||||||||||||||||||||||||||
1365 | |||||||||||||||||||||||||||||||||
1366 | my $tmpl_obj = $webapp->load_tmpl; | ||||||||||||||||||||||||||||||||
1367 | my $tmpl_obj = $webapp->load_tmpl('some.html'); | ||||||||||||||||||||||||||||||||
1368 | my $tmpl_obj = $webapp->load_tmpl( \$template_content ); | ||||||||||||||||||||||||||||||||
1369 | my $tmpl_obj = $webapp->load_tmpl( FILEHANDLE ); | ||||||||||||||||||||||||||||||||
1370 | |||||||||||||||||||||||||||||||||
1371 | This method takes the name of a template file, a reference to template data | ||||||||||||||||||||||||||||||||
1372 | or a FILEHANDLE and returns an HTML::Template object. If the filename is undefined or missing, CGI::Application will default to trying to use the current run mode name, plus the extension ".html". | ||||||||||||||||||||||||||||||||
1373 | |||||||||||||||||||||||||||||||||
1374 | If you use the default template naming system, you should also use | ||||||||||||||||||||||||||||||||
1375 | L |
||||||||||||||||||||||||||||||||
1376 | name accurate when you pass control from one run mode to another. | ||||||||||||||||||||||||||||||||
1377 | |||||||||||||||||||||||||||||||||
1378 | ( For integration with other template systems | ||||||||||||||||||||||||||||||||
1379 | and automated template names, see "Alternatives to load_tmpl() below. ) | ||||||||||||||||||||||||||||||||
1380 | |||||||||||||||||||||||||||||||||
1381 | When you pass in a filename, the HTML::Template->new_file() constructor | ||||||||||||||||||||||||||||||||
1382 | is used for create the object. When you pass in a reference to the template | ||||||||||||||||||||||||||||||||
1383 | content, the HTML::Template->new_scalar_ref() constructor is used and | ||||||||||||||||||||||||||||||||
1384 | when you pass in a filehandle, the HTML::Template->new_filehandle() | ||||||||||||||||||||||||||||||||
1385 | constructor is used. | ||||||||||||||||||||||||||||||||
1386 | |||||||||||||||||||||||||||||||||
1387 | Refer to L |
||||||||||||||||||||||||||||||||
1388 | |||||||||||||||||||||||||||||||||
1389 | If tmpl_path() has been specified, load_tmpl() will set the | ||||||||||||||||||||||||||||||||
1390 | HTML::Template C |
||||||||||||||||||||||||||||||||
1391 | assists in encapsulating template usage. | ||||||||||||||||||||||||||||||||
1392 | |||||||||||||||||||||||||||||||||
1393 | The load_tmpl() method will pass any extra parameters sent to it directly to | ||||||||||||||||||||||||||||||||
1394 | HTML::Template->new_file() (or new_scalar_ref() or new_filehandle()). | ||||||||||||||||||||||||||||||||
1395 | This will allow the HTML::Template object to be further customized: | ||||||||||||||||||||||||||||||||
1396 | |||||||||||||||||||||||||||||||||
1397 | my $tmpl_obj = $webapp->load_tmpl('some_other.html', | ||||||||||||||||||||||||||||||||
1398 | die_on_bad_params => 0, | ||||||||||||||||||||||||||||||||
1399 | cache => 1 | ||||||||||||||||||||||||||||||||
1400 | ); | ||||||||||||||||||||||||||||||||
1401 | |||||||||||||||||||||||||||||||||
1402 | Note that if you want to pass extra arguments but use the default template | ||||||||||||||||||||||||||||||||
1403 | name, you still need to provide a name of C |
||||||||||||||||||||||||||||||||
1404 | |||||||||||||||||||||||||||||||||
1405 | my $tmpl_obj = $webapp->load_tmpl(undef, | ||||||||||||||||||||||||||||||||
1406 | die_on_bad_params => 0, | ||||||||||||||||||||||||||||||||
1407 | cache => 1 | ||||||||||||||||||||||||||||||||
1408 | ); | ||||||||||||||||||||||||||||||||
1409 | |||||||||||||||||||||||||||||||||
1410 | B |
||||||||||||||||||||||||||||||||
1411 | |||||||||||||||||||||||||||||||||
1412 | If your application requires more specialized behavior than this, you can | ||||||||||||||||||||||||||||||||
1413 | always replace it by overriding load_tmpl() by implementing your own | ||||||||||||||||||||||||||||||||
1414 | load_tmpl() in your CGI::Application sub-class application module. | ||||||||||||||||||||||||||||||||
1415 | |||||||||||||||||||||||||||||||||
1416 | First, you may want to check out the template related plugins. | ||||||||||||||||||||||||||||||||
1417 | |||||||||||||||||||||||||||||||||
1418 | L |
||||||||||||||||||||||||||||||||
1419 | and features pre-and-post features, singleton support and more. | ||||||||||||||||||||||||||||||||
1420 | |||||||||||||||||||||||||||||||||
1421 | L |
||||||||||||||||||||||||||||||||
1422 | not a file. It features a simple syntax and MIME-type detection. | ||||||||||||||||||||||||||||||||
1423 | |||||||||||||||||||||||||||||||||
1424 | B |
||||||||||||||||||||||||||||||||
1425 | |||||||||||||||||||||||||||||||||
1426 | You may specify an API-compatible alternative to L |
||||||||||||||||||||||||||||||||
1427 | a new C |
||||||||||||||||||||||||||||||||
1428 | |||||||||||||||||||||||||||||||||
1429 | $self->html_tmpl_class('HTML::Template::Dumper'); | ||||||||||||||||||||||||||||||||
1430 | |||||||||||||||||||||||||||||||||
1431 | The default is "HTML::Template". The alternate class should | ||||||||||||||||||||||||||||||||
1432 | provide at least the following parts of the HTML::Template API: | ||||||||||||||||||||||||||||||||
1433 | |||||||||||||||||||||||||||||||||
1434 | $t = $class->new( scalarref => ... ); # If you use scalarref templates | ||||||||||||||||||||||||||||||||
1435 | $t = $class->new( filehandle => ... ); # If you use filehandle templates | ||||||||||||||||||||||||||||||||
1436 | $t = $class->new( filename => ... ); | ||||||||||||||||||||||||||||||||
1437 | $t->param(...); | ||||||||||||||||||||||||||||||||
1438 | |||||||||||||||||||||||||||||||||
1439 | Here's an example case allowing you to precisely test what's sent to your | ||||||||||||||||||||||||||||||||
1440 | templates: | ||||||||||||||||||||||||||||||||
1441 | |||||||||||||||||||||||||||||||||
1442 | $ENV{CGI_APP_RETURN_ONLY} = 1; | ||||||||||||||||||||||||||||||||
1443 | my $webapp = WebApp->new; | ||||||||||||||||||||||||||||||||
1444 | $webapp->html_tmpl_class('HTML::Template::Dumper'); | ||||||||||||||||||||||||||||||||
1445 | my $out_str = $webapp->run; | ||||||||||||||||||||||||||||||||
1446 | my $tmpl_href = eval "$out_str"; | ||||||||||||||||||||||||||||||||
1447 | |||||||||||||||||||||||||||||||||
1448 | # Now Precisely test what would be set to the template | ||||||||||||||||||||||||||||||||
1449 | is ($tmpl_href->{pet_name}, 'Daisy', "Daisy is sent template"); | ||||||||||||||||||||||||||||||||
1450 | |||||||||||||||||||||||||||||||||
1451 | This is a powerful technique because HTML::Template::Dumper loads and considers | ||||||||||||||||||||||||||||||||
1452 | the template file that would actually be used. If the 'pet_name' token was missing | ||||||||||||||||||||||||||||||||
1453 | in the template, the above test would fail. So, you are testing both your code | ||||||||||||||||||||||||||||||||
1454 | and your templates in a much more precise way than using simple regular | ||||||||||||||||||||||||||||||||
1455 | expressions to see if the string "Daisy" appeared somewhere on the page. | ||||||||||||||||||||||||||||||||
1456 | |||||||||||||||||||||||||||||||||
1457 | B |
||||||||||||||||||||||||||||||||
1458 | |||||||||||||||||||||||||||||||||
1459 | Plugin authors will be interested to know that you can register a callback that | ||||||||||||||||||||||||||||||||
1460 | will be executed just before load_tmpl() returns: | ||||||||||||||||||||||||||||||||
1461 | |||||||||||||||||||||||||||||||||
1462 | $self->add_callback('load_tmpl',\&your_method); | ||||||||||||||||||||||||||||||||
1463 | |||||||||||||||||||||||||||||||||
1464 | When C |
||||||||||||||||||||||||||||||||
1465 | |||||||||||||||||||||||||||||||||
1466 | 1. A hash reference of the extra params passed into C |
||||||||||||||||||||||||||||||||
1467 | 2. Followed by a hash reference to template parameters. | ||||||||||||||||||||||||||||||||
1468 | With both of these, you can modify them by reference to affect | ||||||||||||||||||||||||||||||||
1469 | values that are actually passed to the new() and param() methods of the | ||||||||||||||||||||||||||||||||
1470 | template object. | ||||||||||||||||||||||||||||||||
1471 | 3. The name of the template file. | ||||||||||||||||||||||||||||||||
1472 | |||||||||||||||||||||||||||||||||
1473 | Here's an example stub for a load_tmpl() callback: | ||||||||||||||||||||||||||||||||
1474 | |||||||||||||||||||||||||||||||||
1475 | sub my_load_tmpl_callback { | ||||||||||||||||||||||||||||||||
1476 | my ($c, $ht_params, $tmpl_params, $tmpl_file) = @_ | ||||||||||||||||||||||||||||||||
1477 | # modify $ht_params or $tmpl_params by reference... | ||||||||||||||||||||||||||||||||
1478 | } | ||||||||||||||||||||||||||||||||
1479 | |||||||||||||||||||||||||||||||||
1480 | =head3 param() | ||||||||||||||||||||||||||||||||
1481 | |||||||||||||||||||||||||||||||||
1482 | $webapp->param('pname', $somevalue); | ||||||||||||||||||||||||||||||||
1483 | |||||||||||||||||||||||||||||||||
1484 | The param() method provides a facility through which you may set | ||||||||||||||||||||||||||||||||
1485 | application instance properties which are accessible throughout | ||||||||||||||||||||||||||||||||
1486 | your application. | ||||||||||||||||||||||||||||||||
1487 | |||||||||||||||||||||||||||||||||
1488 | The param() method may be used in two basic ways. First, you may use it | ||||||||||||||||||||||||||||||||
1489 | to get or set the value of a parameter: | ||||||||||||||||||||||||||||||||
1490 | |||||||||||||||||||||||||||||||||
1491 | $webapp->param('scalar_param', '123'); | ||||||||||||||||||||||||||||||||
1492 | my $scalar_param_values = $webapp->param('some_param'); | ||||||||||||||||||||||||||||||||
1493 | |||||||||||||||||||||||||||||||||
1494 | Second, when called in the context of an array, with no parameter name | ||||||||||||||||||||||||||||||||
1495 | specified, param() returns an array containing all the parameters which | ||||||||||||||||||||||||||||||||
1496 | currently exist: | ||||||||||||||||||||||||||||||||
1497 | |||||||||||||||||||||||||||||||||
1498 | my @all_params = $webapp->param(); | ||||||||||||||||||||||||||||||||
1499 | |||||||||||||||||||||||||||||||||
1500 | The param() method also allows you to set a bunch of parameters at once | ||||||||||||||||||||||||||||||||
1501 | by passing in a hash (or hashref): | ||||||||||||||||||||||||||||||||
1502 | |||||||||||||||||||||||||||||||||
1503 | $webapp->param( | ||||||||||||||||||||||||||||||||
1504 | 'key1' => 'val1', | ||||||||||||||||||||||||||||||||
1505 | 'key2' => 'val2', | ||||||||||||||||||||||||||||||||
1506 | 'key3' => 'val3', | ||||||||||||||||||||||||||||||||
1507 | ); | ||||||||||||||||||||||||||||||||
1508 | |||||||||||||||||||||||||||||||||
1509 | The param() method enables a very valuable system for | ||||||||||||||||||||||||||||||||
1510 | customizing your applications on a per-instance basis. | ||||||||||||||||||||||||||||||||
1511 | One Application Module might be instantiated by different | ||||||||||||||||||||||||||||||||
1512 | Instance Scripts. Each Instance Script might set different values for a | ||||||||||||||||||||||||||||||||
1513 | set of parameters. This allows similar applications to share a common | ||||||||||||||||||||||||||||||||
1514 | code-base, but behave differently. For example, imagine a mail form | ||||||||||||||||||||||||||||||||
1515 | application with a single Application Module, but multiple Instance | ||||||||||||||||||||||||||||||||
1516 | Scripts. Each Instance Script might specify a different recipient. | ||||||||||||||||||||||||||||||||
1517 | Another example would be a web bulletin boards system. There could be | ||||||||||||||||||||||||||||||||
1518 | multiple boards, each with a different topic and set of administrators. | ||||||||||||||||||||||||||||||||
1519 | |||||||||||||||||||||||||||||||||
1520 | The new() method provides a shortcut for specifying a number of run-time | ||||||||||||||||||||||||||||||||
1521 | parameters at once. Internally, CGI::Application calls the param() | ||||||||||||||||||||||||||||||||
1522 | method to set these properties. The param() method is a powerful tool for | ||||||||||||||||||||||||||||||||
1523 | greatly increasing your application's re-usability. | ||||||||||||||||||||||||||||||||
1524 | |||||||||||||||||||||||||||||||||
1525 | =head3 query() | ||||||||||||||||||||||||||||||||
1526 | |||||||||||||||||||||||||||||||||
1527 | my $q = $webapp->query(); | ||||||||||||||||||||||||||||||||
1528 | my $remote_user = $q->remote_user(); | ||||||||||||||||||||||||||||||||
1529 | |||||||||||||||||||||||||||||||||
1530 | This method retrieves the CGI.pm query object which has been created | ||||||||||||||||||||||||||||||||
1531 | by instantiating your Application Module. For details on usage of this | ||||||||||||||||||||||||||||||||
1532 | query object, refer to L |
||||||||||||||||||||||||||||||||
1533 | module. Generally speaking, you will want to become very familiar | ||||||||||||||||||||||||||||||||
1534 | with CGI.pm, as you will use the query object whenever you want to | ||||||||||||||||||||||||||||||||
1535 | interact with form data. | ||||||||||||||||||||||||||||||||
1536 | |||||||||||||||||||||||||||||||||
1537 | When the new() method is called, a CGI query object is automatically created. | ||||||||||||||||||||||||||||||||
1538 | If, for some reason, you want to use your own CGI query object, the new() | ||||||||||||||||||||||||||||||||
1539 | method supports passing in your existing query object on construction using | ||||||||||||||||||||||||||||||||
1540 | the QUERY attribute. | ||||||||||||||||||||||||||||||||
1541 | |||||||||||||||||||||||||||||||||
1542 | There are a few rare situations where you want your own query object to be | ||||||||||||||||||||||||||||||||
1543 | used after your Application Module has already been constructed. In that case | ||||||||||||||||||||||||||||||||
1544 | you can pass it to c |
||||||||||||||||||||||||||||||||
1545 | |||||||||||||||||||||||||||||||||
1546 | $webapp->query($new_query_object); | ||||||||||||||||||||||||||||||||
1547 | my $q = $webapp->query(); # now uses $new_query_object | ||||||||||||||||||||||||||||||||
1548 | |||||||||||||||||||||||||||||||||
1549 | =head3 run_modes() | ||||||||||||||||||||||||||||||||
1550 | |||||||||||||||||||||||||||||||||
1551 | # The common usage: an arrayref of run mode names that exactly match subroutine names | ||||||||||||||||||||||||||||||||
1552 | $webapp->run_modes([qw/ | ||||||||||||||||||||||||||||||||
1553 | form_display | ||||||||||||||||||||||||||||||||
1554 | form_process | ||||||||||||||||||||||||||||||||
1555 | /]); | ||||||||||||||||||||||||||||||||
1556 | |||||||||||||||||||||||||||||||||
1557 | # With a hashref, use a different name or a code ref | ||||||||||||||||||||||||||||||||
1558 | $webapp->run_modes( | ||||||||||||||||||||||||||||||||
1559 | 'mode1' => 'some_sub_by_name', | ||||||||||||||||||||||||||||||||
1560 | 'mode2' => \&some_other_sub_by_ref | ||||||||||||||||||||||||||||||||
1561 | ); | ||||||||||||||||||||||||||||||||
1562 | |||||||||||||||||||||||||||||||||
1563 | This accessor/mutator specifies the dispatch table for the | ||||||||||||||||||||||||||||||||
1564 | application states, using the syntax examples above. It returns | ||||||||||||||||||||||||||||||||
1565 | the dispatch table as a hash. | ||||||||||||||||||||||||||||||||
1566 | |||||||||||||||||||||||||||||||||
1567 | The run_modes() method may be called more than once. Additional values passed | ||||||||||||||||||||||||||||||||
1568 | into run_modes() will be added to the run modes table. In the case that an | ||||||||||||||||||||||||||||||||
1569 | existing run mode is re-defined, the new value will override the existing value. | ||||||||||||||||||||||||||||||||
1570 | This behavior might be useful for applications which are created via inheritance | ||||||||||||||||||||||||||||||||
1571 | from another application, or some advanced application which modifies its | ||||||||||||||||||||||||||||||||
1572 | own capabilities based on user input. | ||||||||||||||||||||||||||||||||
1573 | |||||||||||||||||||||||||||||||||
1574 | The run() method uses the data in this table to send the application to the | ||||||||||||||||||||||||||||||||
1575 | correct function as determined by reading the CGI parameter specified by | ||||||||||||||||||||||||||||||||
1576 | mode_param() (defaults to 'rm' for "Run Mode"). These functions are referred | ||||||||||||||||||||||||||||||||
1577 | to as "run mode methods". | ||||||||||||||||||||||||||||||||
1578 | |||||||||||||||||||||||||||||||||
1579 | The hash table set by this method is expected to contain the mode | ||||||||||||||||||||||||||||||||
1580 | name as a key. The value should be either a hard reference (a subref) | ||||||||||||||||||||||||||||||||
1581 | to the run mode method which you want to be called when the application enters | ||||||||||||||||||||||||||||||||
1582 | the specified run mode, or the name of the run mode method to be called: | ||||||||||||||||||||||||||||||||
1583 | |||||||||||||||||||||||||||||||||
1584 | 'mode_name_by_ref' => \&mode_function | ||||||||||||||||||||||||||||||||
1585 | 'mode_name_by_name' => 'mode_function' | ||||||||||||||||||||||||||||||||
1586 | |||||||||||||||||||||||||||||||||
1587 | The run mode method specified is expected to return a block of text (e.g.: | ||||||||||||||||||||||||||||||||
1588 | HTML) which will eventually be sent back to the web browser. The run mode | ||||||||||||||||||||||||||||||||
1589 | method may return its block of text as a scalar or a scalar-ref. | ||||||||||||||||||||||||||||||||
1590 | |||||||||||||||||||||||||||||||||
1591 | An advantage of specifying your run mode methods by name instead of | ||||||||||||||||||||||||||||||||
1592 | by reference is that you can more easily create derivative applications | ||||||||||||||||||||||||||||||||
1593 | using inheritance. For instance, if you have a new application which is | ||||||||||||||||||||||||||||||||
1594 | exactly the same as an existing application with the exception of one | ||||||||||||||||||||||||||||||||
1595 | run mode, you could simply inherit from that other application and override | ||||||||||||||||||||||||||||||||
1596 | the run mode method which is different. If you specified your run mode | ||||||||||||||||||||||||||||||||
1597 | method by reference, your child class would still use the function | ||||||||||||||||||||||||||||||||
1598 | from the parent class. | ||||||||||||||||||||||||||||||||
1599 | |||||||||||||||||||||||||||||||||
1600 | An advantage of specifying your run mode methods by reference instead of by name | ||||||||||||||||||||||||||||||||
1601 | is performance. Dereferencing a subref is faster than eval()-ing | ||||||||||||||||||||||||||||||||
1602 | a code block. If run-time performance is a critical issue, specify | ||||||||||||||||||||||||||||||||
1603 | your run mode methods by reference and not by name. The speed differences | ||||||||||||||||||||||||||||||||
1604 | are generally small, however, so specifying by name is preferred. | ||||||||||||||||||||||||||||||||
1605 | |||||||||||||||||||||||||||||||||
1606 | Specifying the run modes by array reference: | ||||||||||||||||||||||||||||||||
1607 | |||||||||||||||||||||||||||||||||
1608 | $webapp->run_modes([ 'mode1', 'mode2', 'mode3' ]); | ||||||||||||||||||||||||||||||||
1609 | |||||||||||||||||||||||||||||||||
1610 | This is the same as using a hash, with keys equal to values | ||||||||||||||||||||||||||||||||
1611 | |||||||||||||||||||||||||||||||||
1612 | $webapp->run_modes( | ||||||||||||||||||||||||||||||||
1613 | 'mode1' => 'mode1', | ||||||||||||||||||||||||||||||||
1614 | 'mode2' => 'mode2', | ||||||||||||||||||||||||||||||||
1615 | 'mode3' => 'mode3' | ||||||||||||||||||||||||||||||||
1616 | ); | ||||||||||||||||||||||||||||||||
1617 | |||||||||||||||||||||||||||||||||
1618 | Often, it makes good organizational sense to have your run modes map to | ||||||||||||||||||||||||||||||||
1619 | methods of the same name. The array-ref interface provides a shortcut | ||||||||||||||||||||||||||||||||
1620 | to that behavior while reducing verbosity of your code. | ||||||||||||||||||||||||||||||||
1621 | |||||||||||||||||||||||||||||||||
1622 | Note that another importance of specifying your run modes in either a | ||||||||||||||||||||||||||||||||
1623 | hash or array-ref is to assure that only those Perl methods which are | ||||||||||||||||||||||||||||||||
1624 | specifically designated may be called via your application. Application | ||||||||||||||||||||||||||||||||
1625 | environments which don't specify allowed methods and disallow all others | ||||||||||||||||||||||||||||||||
1626 | are insecure, potentially opening the door to allowing execution of | ||||||||||||||||||||||||||||||||
1627 | arbitrary code. CGI::Application maintains a strict "default-deny" stance | ||||||||||||||||||||||||||||||||
1628 | on all method invocation, thereby allowing secure applications | ||||||||||||||||||||||||||||||||
1629 | to be built upon it. | ||||||||||||||||||||||||||||||||
1630 | |||||||||||||||||||||||||||||||||
1631 | B |
||||||||||||||||||||||||||||||||
1632 | |||||||||||||||||||||||||||||||||
1633 | Your application should *NEVER* print() to STDOUT. | ||||||||||||||||||||||||||||||||
1634 | Using print() to send output to STDOUT (including HTTP headers) is | ||||||||||||||||||||||||||||||||
1635 | exclusively the domain of the inherited run() method. Breaking this | ||||||||||||||||||||||||||||||||
1636 | rule is a common source of errors. If your program is erroneously | ||||||||||||||||||||||||||||||||
1637 | sending content before your HTTP header, you are probably breaking this rule. | ||||||||||||||||||||||||||||||||
1638 | |||||||||||||||||||||||||||||||||
1639 | |||||||||||||||||||||||||||||||||
1640 | B |
||||||||||||||||||||||||||||||||
1641 | |||||||||||||||||||||||||||||||||
1642 | If CGI::Application is asked to go to a run mode which doesn't exist | ||||||||||||||||||||||||||||||||
1643 | it will usually croak() with errors. If this is not your desired | ||||||||||||||||||||||||||||||||
1644 | behavior, it is possible to catch this exception by implementing | ||||||||||||||||||||||||||||||||
1645 | a run mode with the reserved name "AUTOLOAD": | ||||||||||||||||||||||||||||||||
1646 | |||||||||||||||||||||||||||||||||
1647 | $self->run_modes( | ||||||||||||||||||||||||||||||||
1648 | "AUTOLOAD" => \&catch_my_exception | ||||||||||||||||||||||||||||||||
1649 | ); | ||||||||||||||||||||||||||||||||
1650 | |||||||||||||||||||||||||||||||||
1651 | Before CGI::Application calls croak() it will check for the existence | ||||||||||||||||||||||||||||||||
1652 | of a run mode called "AUTOLOAD". If specified, this run mode will in | ||||||||||||||||||||||||||||||||
1653 | invoked just like a regular run mode, with one exception: It will | ||||||||||||||||||||||||||||||||
1654 | receive, as an argument, the name of the run mode which invoked it: | ||||||||||||||||||||||||||||||||
1655 | |||||||||||||||||||||||||||||||||
1656 | sub catch_my_exception { | ||||||||||||||||||||||||||||||||
1657 | my $self = shift; | ||||||||||||||||||||||||||||||||
1658 | my $intended_runmode = shift; | ||||||||||||||||||||||||||||||||
1659 | |||||||||||||||||||||||||||||||||
1660 | my $output = "Looking for '$intended_runmode', but found 'AUTOLOAD' instead"; | ||||||||||||||||||||||||||||||||
1661 | return $output; | ||||||||||||||||||||||||||||||||
1662 | } | ||||||||||||||||||||||||||||||||
1663 | |||||||||||||||||||||||||||||||||
1664 | This functionality could be used for a simple human-readable error | ||||||||||||||||||||||||||||||||
1665 | screen, or for more sophisticated application behaviors. | ||||||||||||||||||||||||||||||||
1666 | |||||||||||||||||||||||||||||||||
1667 | |||||||||||||||||||||||||||||||||
1668 | =head3 start_mode() | ||||||||||||||||||||||||||||||||
1669 | |||||||||||||||||||||||||||||||||
1670 | $webapp->start_mode('mode1'); | ||||||||||||||||||||||||||||||||
1671 | |||||||||||||||||||||||||||||||||
1672 | The start_mode contains the name of the mode as specified in the run_modes() | ||||||||||||||||||||||||||||||||
1673 | table. Default mode is "start". The mode key specified here will be used | ||||||||||||||||||||||||||||||||
1674 | whenever the value of the CGI form parameter specified by mode_param() is | ||||||||||||||||||||||||||||||||
1675 | not defined. Generally, this is the first time your application is executed. | ||||||||||||||||||||||||||||||||
1676 | |||||||||||||||||||||||||||||||||
1677 | =head3 tmpl_path() | ||||||||||||||||||||||||||||||||
1678 | |||||||||||||||||||||||||||||||||
1679 | $webapp->tmpl_path('/path/to/some/templates/'); | ||||||||||||||||||||||||||||||||
1680 | |||||||||||||||||||||||||||||||||
1681 | This access/mutator method sets the file path to the directory (or directories) | ||||||||||||||||||||||||||||||||
1682 | where the templates are stored. It is used by load_tmpl() to find the template | ||||||||||||||||||||||||||||||||
1683 | files, using HTML::Template's C |
||||||||||||||||||||||||||||||||
1684 | pass in a text scalar or an array reference of multiple paths. | ||||||||||||||||||||||||||||||||
1685 | |||||||||||||||||||||||||||||||||
1686 | |||||||||||||||||||||||||||||||||
1687 | |||||||||||||||||||||||||||||||||
1688 | =head2 More Application Methods | ||||||||||||||||||||||||||||||||
1689 | |||||||||||||||||||||||||||||||||
1690 | You can skip this section if you are just getting started. | ||||||||||||||||||||||||||||||||
1691 | |||||||||||||||||||||||||||||||||
1692 | The following additional methods are inherited from CGI::Application, and are | ||||||||||||||||||||||||||||||||
1693 | available to be called by your application within your Application Module. | ||||||||||||||||||||||||||||||||
1694 | These functions are listed in alphabetical order. | ||||||||||||||||||||||||||||||||
1695 | |||||||||||||||||||||||||||||||||
1696 | =head3 delete() | ||||||||||||||||||||||||||||||||
1697 | |||||||||||||||||||||||||||||||||
1698 | $webapp->delete('my_param'); | ||||||||||||||||||||||||||||||||
1699 | |||||||||||||||||||||||||||||||||
1700 | The delete() method is used to delete a parameter that was previously | ||||||||||||||||||||||||||||||||
1701 | stored inside of your application either by using the PARAMS hash that | ||||||||||||||||||||||||||||||||
1702 | was passed in your call to new() or by a call to the param() method. | ||||||||||||||||||||||||||||||||
1703 | This is similar to the delete() method of CGI.pm. It is useful if your | ||||||||||||||||||||||||||||||||
1704 | application makes decisions based on the existence of certain params that | ||||||||||||||||||||||||||||||||
1705 | may have been removed in previous sections of your app or simply to | ||||||||||||||||||||||||||||||||
1706 | clean-up your param()s. | ||||||||||||||||||||||||||||||||
1707 | |||||||||||||||||||||||||||||||||
1708 | |||||||||||||||||||||||||||||||||
1709 | =head3 dump() | ||||||||||||||||||||||||||||||||
1710 | |||||||||||||||||||||||||||||||||
1711 | print STDERR $webapp->dump(); | ||||||||||||||||||||||||||||||||
1712 | |||||||||||||||||||||||||||||||||
1713 | The dump() method is a debugging function which will return a | ||||||||||||||||||||||||||||||||
1714 | chunk of text which contains all the environment and web form | ||||||||||||||||||||||||||||||||
1715 | data of the request, formatted nicely for human readability. | ||||||||||||||||||||||||||||||||
1716 | Useful for outputting to STDERR. | ||||||||||||||||||||||||||||||||
1717 | |||||||||||||||||||||||||||||||||
1718 | |||||||||||||||||||||||||||||||||
1719 | =head3 dump_html() | ||||||||||||||||||||||||||||||||
1720 | |||||||||||||||||||||||||||||||||
1721 | my $output = $webapp->dump_html(); | ||||||||||||||||||||||||||||||||
1722 | |||||||||||||||||||||||||||||||||
1723 | The dump_html() method is a debugging function which will return | ||||||||||||||||||||||||||||||||
1724 | a chunk of text which contains all the environment and web form | ||||||||||||||||||||||||||||||||
1725 | data of the request, formatted nicely for human readability via | ||||||||||||||||||||||||||||||||
1726 | a web browser. Useful for outputting to a browser. Please consider | ||||||||||||||||||||||||||||||||
1727 | the security implications of using this in production code. | ||||||||||||||||||||||||||||||||
1728 | |||||||||||||||||||||||||||||||||
1729 | =head3 error_mode() | ||||||||||||||||||||||||||||||||
1730 | |||||||||||||||||||||||||||||||||
1731 | $webapp->error_mode('my_error_rm'); | ||||||||||||||||||||||||||||||||
1732 | |||||||||||||||||||||||||||||||||
1733 | If the runmode dies for whatever reason, C |
||||||||||||||||||||||||||||||||
1734 | value for C |
||||||||||||||||||||||||||||||||
1735 | as a run mode, passing $@ as the only parameter. | ||||||||||||||||||||||||||||||||
1736 | |||||||||||||||||||||||||||||||||
1737 | Plugins authors will be interested to know that just before C |
||||||||||||||||||||||||||||||||
1738 | called, the C |
||||||||||||||||||||||||||||||||
1739 | the only parameter. | ||||||||||||||||||||||||||||||||
1740 | |||||||||||||||||||||||||||||||||
1741 | No C |
||||||||||||||||||||||||||||||||
1742 | mode is not trapped, so you can also use it to die in your own special way. | ||||||||||||||||||||||||||||||||
1743 | |||||||||||||||||||||||||||||||||
1744 | For a complete integrated logging solution, check out L |
||||||||||||||||||||||||||||||||
1745 | |||||||||||||||||||||||||||||||||
1746 | =head3 get_current_runmode() | ||||||||||||||||||||||||||||||||
1747 | |||||||||||||||||||||||||||||||||
1748 | $webapp->get_current_runmode(); | ||||||||||||||||||||||||||||||||
1749 | |||||||||||||||||||||||||||||||||
1750 | The C |
||||||||||||||||||||||||||||||||
1751 | the name of the run mode which is currently being executed. If the | ||||||||||||||||||||||||||||||||
1752 | run mode has not yet been determined, such as during setup(), this method | ||||||||||||||||||||||||||||||||
1753 | will return undef. | ||||||||||||||||||||||||||||||||
1754 | |||||||||||||||||||||||||||||||||
1755 | =head3 header_add() | ||||||||||||||||||||||||||||||||
1756 | |||||||||||||||||||||||||||||||||
1757 | # add or replace the 'type' header | ||||||||||||||||||||||||||||||||
1758 | $webapp->header_add( -type => 'image/png' ); | ||||||||||||||||||||||||||||||||
1759 | |||||||||||||||||||||||||||||||||
1760 | - or - | ||||||||||||||||||||||||||||||||
1761 | |||||||||||||||||||||||||||||||||
1762 | # add an additional cookie | ||||||||||||||||||||||||||||||||
1763 | $webapp->header_add(-cookie=>[$extra_cookie]); | ||||||||||||||||||||||||||||||||
1764 | |||||||||||||||||||||||||||||||||
1765 | The C |
||||||||||||||||||||||||||||||||
1766 | response headers. The parameters will eventually be passed on to the CGI.pm | ||||||||||||||||||||||||||||||||
1767 | header() method, so refer to the L |
||||||||||||||||||||||||||||||||
1768 | |||||||||||||||||||||||||||||||||
1769 | Unlike calling C |
||||||||||||||||||||||||||||||||
1770 | headers. If a scalar value is passed to C |
||||||||||||||||||||||||||||||||
1771 | the existing value for that key. | ||||||||||||||||||||||||||||||||
1772 | |||||||||||||||||||||||||||||||||
1773 | If an array reference is passed as a value to C |
||||||||||||||||||||||||||||||||
1774 | that array ref will be appended to any existing values for that key. | ||||||||||||||||||||||||||||||||
1775 | This is primarily useful for setting an additional cookie after one has already | ||||||||||||||||||||||||||||||||
1776 | been set. | ||||||||||||||||||||||||||||||||
1777 | |||||||||||||||||||||||||||||||||
1778 | =head3 header_props() | ||||||||||||||||||||||||||||||||
1779 | |||||||||||||||||||||||||||||||||
1780 | # Set a complete set of headers | ||||||||||||||||||||||||||||||||
1781 | %set_headers = $webapp->header_props(-type=>'image/gif',-expires=>'+3d'); | ||||||||||||||||||||||||||||||||
1782 | |||||||||||||||||||||||||||||||||
1783 | # clobber / reset all headers | ||||||||||||||||||||||||||||||||
1784 | %set_headers = $webapp->header_props({}); | ||||||||||||||||||||||||||||||||
1785 | |||||||||||||||||||||||||||||||||
1786 | # Just retrieve the headers | ||||||||||||||||||||||||||||||||
1787 | %set_headers = $webapp->header_props(); | ||||||||||||||||||||||||||||||||
1788 | |||||||||||||||||||||||||||||||||
1789 | The C |
||||||||||||||||||||||||||||||||
1790 | HTTP header properties. These properties will be passed directly | ||||||||||||||||||||||||||||||||
1791 | to the C |
||||||||||||||||||||||||||||||||
1792 | to the docs of your query object for details. (Be default, it's L |
||||||||||||||||||||||||||||||||
1793 | |||||||||||||||||||||||||||||||||
1794 | Calling header_props with an empty hashref clobber any existing headers that have | ||||||||||||||||||||||||||||||||
1795 | previously set. | ||||||||||||||||||||||||||||||||
1796 | |||||||||||||||||||||||||||||||||
1797 | C |
||||||||||||||||||||||||||||||||
1798 | set. It can be called with no arguments just to get the hash current headers | ||||||||||||||||||||||||||||||||
1799 | back. | ||||||||||||||||||||||||||||||||
1800 | |||||||||||||||||||||||||||||||||
1801 | To add additional headers later without clobbering the old ones, | ||||||||||||||||||||||||||||||||
1802 | see C |
||||||||||||||||||||||||||||||||
1803 | |||||||||||||||||||||||||||||||||
1804 | B |
||||||||||||||||||||||||||||||||
1805 | |||||||||||||||||||||||||||||||||
1806 | It is through the C |
||||||||||||||||||||||||||||||||
1807 | HTTP headers. This is necessary when you want to set a cookie, set the mime | ||||||||||||||||||||||||||||||||
1808 | type to something other than "text/html", or perform a redirect. The | ||||||||||||||||||||||||||||||||
1809 | header_props() method works in conjunction with the header_type() method. | ||||||||||||||||||||||||||||||||
1810 | The value contained in header_type() determines if we use CGI::header() or | ||||||||||||||||||||||||||||||||
1811 | CGI::redirect(). The content of header_props() is passed as an argument to | ||||||||||||||||||||||||||||||||
1812 | whichever CGI.pm function is called. | ||||||||||||||||||||||||||||||||
1813 | |||||||||||||||||||||||||||||||||
1814 | Understanding this relationship is important if you wish to manipulate | ||||||||||||||||||||||||||||||||
1815 | the HTTP header properly. | ||||||||||||||||||||||||||||||||
1816 | |||||||||||||||||||||||||||||||||
1817 | =head3 header_type() | ||||||||||||||||||||||||||||||||
1818 | |||||||||||||||||||||||||||||||||
1819 | $webapp->header_type('redirect'); | ||||||||||||||||||||||||||||||||
1820 | $webapp->header_type('none'); | ||||||||||||||||||||||||||||||||
1821 | |||||||||||||||||||||||||||||||||
1822 | This method used to declare that you are setting a redirection header, | ||||||||||||||||||||||||||||||||
1823 | or that you want no header to be returned by the framework. | ||||||||||||||||||||||||||||||||
1824 | |||||||||||||||||||||||||||||||||
1825 | The value of 'header' is almost never used, as it is the default. | ||||||||||||||||||||||||||||||||
1826 | |||||||||||||||||||||||||||||||||
1827 | B |
||||||||||||||||||||||||||||||||
1828 | |||||||||||||||||||||||||||||||||
1829 | sub some_redirect_mode { | ||||||||||||||||||||||||||||||||
1830 | my $self = shift; | ||||||||||||||||||||||||||||||||
1831 | # do stuff here.... | ||||||||||||||||||||||||||||||||
1832 | $self->header_type('redirect'); | ||||||||||||||||||||||||||||||||
1833 | $self->header_props(-url=> "http://site/path/doc.html" ); | ||||||||||||||||||||||||||||||||
1834 | } | ||||||||||||||||||||||||||||||||
1835 | |||||||||||||||||||||||||||||||||
1836 | To simplify that further, use L |
||||||||||||||||||||||||||||||||
1837 | |||||||||||||||||||||||||||||||||
1838 | return $self->redirect('http://www.example.com/'); | ||||||||||||||||||||||||||||||||
1839 | |||||||||||||||||||||||||||||||||
1840 | Setting the header to 'none' may be useful if you are streaming content. | ||||||||||||||||||||||||||||||||
1841 | In other contexts, it may be more useful to set C<$ENV{CGI_APP_RETURN_ONLY} = 1;>, | ||||||||||||||||||||||||||||||||
1842 | which suppresses all printing, including headers, and returns the output instead. | ||||||||||||||||||||||||||||||||
1843 | |||||||||||||||||||||||||||||||||
1844 | That's commonly used for testing, or when using L |
||||||||||||||||||||||||||||||||
1845 | for a cron script! | ||||||||||||||||||||||||||||||||
1846 | |||||||||||||||||||||||||||||||||
1847 | =cut | ||||||||||||||||||||||||||||||||
1848 | |||||||||||||||||||||||||||||||||
1849 | sub html_tmpl_class { | ||||||||||||||||||||||||||||||||
1850 | 7 | 7 | 0 | 12 | my $self = shift; | ||||||||||||||||||||||||||||
1851 | 7 | 9 | my $tmpl_class = shift; | ||||||||||||||||||||||||||||||
1852 | |||||||||||||||||||||||||||||||||
1853 | # First use? Create new __ERROR_MODE | ||||||||||||||||||||||||||||||||
1854 | 7 | 100 | 59 | $self->{__HTML_TMPL_CLASS} = 'HTML::Template' unless (exists($self->{__HTML_TMPL_CLASS})); | |||||||||||||||||||||||||||||
1855 | |||||||||||||||||||||||||||||||||
1856 | 7 | 50 | 18 | if (defined $tmpl_class) { | |||||||||||||||||||||||||||||
1857 | 0 | 0 | $self->{__HTML_TMPL_CLASS} = $tmpl_class; | ||||||||||||||||||||||||||||||
1858 | } | ||||||||||||||||||||||||||||||||
1859 | |||||||||||||||||||||||||||||||||
1860 | 7 | 16 | return $self->{__HTML_TMPL_CLASS}; | ||||||||||||||||||||||||||||||
1861 | } | ||||||||||||||||||||||||||||||||
1862 | |||||||||||||||||||||||||||||||||
1863 | sub load_tmpl { | ||||||||||||||||||||||||||||||||
1864 | 7 | 7 | 1 | 1190 | my $self = shift; | ||||||||||||||||||||||||||||
1865 | 7 | 16 | my ($tmpl_file, @extra_params) = @_; | ||||||||||||||||||||||||||||||
1866 | |||||||||||||||||||||||||||||||||
1867 | # add tmpl_path to path array if one is set, otherwise add a path arg | ||||||||||||||||||||||||||||||||
1868 | 7 | 100 | 19 | if (my $tmpl_path = $self->tmpl_path) { | |||||||||||||||||||||||||||||
1869 | 6 | 100 | 26 | my @tmpl_paths = (ref $tmpl_path eq 'ARRAY') ? @$tmpl_path : $tmpl_path; | |||||||||||||||||||||||||||||
1870 | 6 | 10 | my $found = 0; | ||||||||||||||||||||||||||||||
1871 | 6 | 26 | for( my $x = 0; $x < @extra_params; $x += 2 ) { | ||||||||||||||||||||||||||||||
1872 | 2 | 50 | 33 | 10 | if ($extra_params[$x] eq 'path' and | ||||||||||||||||||||||||||||
1873 | ref $extra_params[$x+1] eq 'ARRAY') { | ||||||||||||||||||||||||||||||||
1874 | 0 | 0 | unshift @{$extra_params[$x+1]}, @tmpl_paths; | ||||||||||||||||||||||||||||||
0 | 0 | ||||||||||||||||||||||||||||||||
1875 | 0 | 0 | $found = 1; | ||||||||||||||||||||||||||||||
1876 | 0 | 0 | last; | ||||||||||||||||||||||||||||||
1877 | } | ||||||||||||||||||||||||||||||||
1878 | } | ||||||||||||||||||||||||||||||||
1879 | 6 | 50 | 24 | push(@extra_params, path => [ @tmpl_paths ]) unless $found; | |||||||||||||||||||||||||||||
1880 | } | ||||||||||||||||||||||||||||||||
1881 | |||||||||||||||||||||||||||||||||
1882 | 7 | 14 | my %tmpl_params = (); | ||||||||||||||||||||||||||||||
1883 | 7 | 20 | my %ht_params = @extra_params; | ||||||||||||||||||||||||||||||
1884 | 7 | 100 | 21 | %ht_params = () unless keys %ht_params; | |||||||||||||||||||||||||||||
1885 | |||||||||||||||||||||||||||||||||
1886 | # Define our extension if doesn't already exist; | ||||||||||||||||||||||||||||||||
1887 | 7 | 100 | 28 | $self->{__CURRENT_TMPL_EXTENSION} = '.html' unless defined $self->{__CURRENT_TMPL_EXTENSION}; | |||||||||||||||||||||||||||||
1888 | |||||||||||||||||||||||||||||||||
1889 | # Define a default template name based on the current run mode | ||||||||||||||||||||||||||||||||
1890 | 7 | 50 | 20 | unless (defined $tmpl_file) { | |||||||||||||||||||||||||||||
1891 | 0 | 0 | $tmpl_file = $self->get_current_runmode . $self->{__CURRENT_TMPL_EXTENSION}; | ||||||||||||||||||||||||||||||
1892 | } | ||||||||||||||||||||||||||||||||
1893 | |||||||||||||||||||||||||||||||||
1894 | 7 | 24 | $self->call_hook('load_tmpl', \%ht_params, \%tmpl_params, $tmpl_file); | ||||||||||||||||||||||||||||||
1895 | |||||||||||||||||||||||||||||||||
1896 | 7 | 32 | my $ht_class = $self->html_tmpl_class; | ||||||||||||||||||||||||||||||
1897 | 7 | 50 | 485 | eval "require $ht_class;" || die "require $ht_class failed: $@"; | |||||||||||||||||||||||||||||
1898 | |||||||||||||||||||||||||||||||||
1899 | # let's check $tmpl_file and see what kind of parameter it is - we | ||||||||||||||||||||||||||||||||
1900 | # now support 3 options: scalar (filename), ref to scalar (the | ||||||||||||||||||||||||||||||||
1901 | # actual html/template content) and reference to FILEHANDLE | ||||||||||||||||||||||||||||||||
1902 | 7 | 48684 | my $t = undef; | ||||||||||||||||||||||||||||||
1903 | 7 | 50 | 45 | if ( ref $tmpl_file eq 'SCALAR' ) { | |||||||||||||||||||||||||||||
50 | |||||||||||||||||||||||||||||||||
1904 | 0 | 0 | $t = $ht_class->new( scalarref => $tmpl_file, %ht_params ); | ||||||||||||||||||||||||||||||
1905 | } elsif ( ref $tmpl_file eq 'GLOB' ) { | ||||||||||||||||||||||||||||||||
1906 | 0 | 0 | $t = $ht_class->new( filehandle => $tmpl_file, %ht_params ); | ||||||||||||||||||||||||||||||
1907 | } else { | ||||||||||||||||||||||||||||||||
1908 | 7 | 53 | $t = $ht_class->new( filename => $tmpl_file, %ht_params); | ||||||||||||||||||||||||||||||
1909 | } | ||||||||||||||||||||||||||||||||
1910 | |||||||||||||||||||||||||||||||||
1911 | 7 | 100 | 3828 | if (keys %tmpl_params) { | |||||||||||||||||||||||||||||
1912 | 1 | 7 | $t->param(%tmpl_params); | ||||||||||||||||||||||||||||||
1913 | } | ||||||||||||||||||||||||||||||||
1914 | |||||||||||||||||||||||||||||||||
1915 | 7 | 95 | return $t; | ||||||||||||||||||||||||||||||
1916 | } | ||||||||||||||||||||||||||||||||
1917 | |||||||||||||||||||||||||||||||||
1918 | =pod | ||||||||||||||||||||||||||||||||
1919 | |||||||||||||||||||||||||||||||||
1920 | =head3 mode_param() | ||||||||||||||||||||||||||||||||
1921 | |||||||||||||||||||||||||||||||||
1922 | # Name the CGI form parameter that contains the run mode name. | ||||||||||||||||||||||||||||||||
1923 | # This is the default behavior, and is often sufficient. | ||||||||||||||||||||||||||||||||
1924 | $webapp->mode_param('rm'); | ||||||||||||||||||||||||||||||||
1925 | |||||||||||||||||||||||||||||||||
1926 | # Set the run mode name directly from a code ref | ||||||||||||||||||||||||||||||||
1927 | $webapp->mode_param(\&some_method); | ||||||||||||||||||||||||||||||||
1928 | |||||||||||||||||||||||||||||||||
1929 | # Alternate interface, which allows you to set the run | ||||||||||||||||||||||||||||||||
1930 | # mode name directly from $ENV{PATH_INFO}. | ||||||||||||||||||||||||||||||||
1931 | $webapp->mode_param( | ||||||||||||||||||||||||||||||||
1932 | path_info=> 1, | ||||||||||||||||||||||||||||||||
1933 | param =>'rm' | ||||||||||||||||||||||||||||||||
1934 | ); | ||||||||||||||||||||||||||||||||
1935 | |||||||||||||||||||||||||||||||||
1936 | This accessor/mutator method is generally called in the setup() method. | ||||||||||||||||||||||||||||||||
1937 | It is used to help determine the run mode to call. There are three options for calling it. | ||||||||||||||||||||||||||||||||
1938 | |||||||||||||||||||||||||||||||||
1939 | $webapp->mode_param('rm'); | ||||||||||||||||||||||||||||||||
1940 | |||||||||||||||||||||||||||||||||
1941 | Here, a CGI form parameter is named that will contain the name of the run mode | ||||||||||||||||||||||||||||||||
1942 | to use. This is the default behavior, with 'rm' being the parameter named used. | ||||||||||||||||||||||||||||||||
1943 | |||||||||||||||||||||||||||||||||
1944 | $webapp->mode_param(\&some_method); | ||||||||||||||||||||||||||||||||
1945 | |||||||||||||||||||||||||||||||||
1946 | Here a code reference is provided. It will return the name of the run mode | ||||||||||||||||||||||||||||||||
1947 | to use directly. Example: | ||||||||||||||||||||||||||||||||
1948 | |||||||||||||||||||||||||||||||||
1949 | sub some_method { | ||||||||||||||||||||||||||||||||
1950 | my $self = shift; | ||||||||||||||||||||||||||||||||
1951 | return 'run_mode_x'; | ||||||||||||||||||||||||||||||||
1952 | } | ||||||||||||||||||||||||||||||||
1953 | |||||||||||||||||||||||||||||||||
1954 | This would allow you to programmatically set the run mode based on arbitrary logic. | ||||||||||||||||||||||||||||||||
1955 | |||||||||||||||||||||||||||||||||
1956 | $webapp->mode_param( | ||||||||||||||||||||||||||||||||
1957 | path_info=> 1, | ||||||||||||||||||||||||||||||||
1958 | param =>'rm' | ||||||||||||||||||||||||||||||||
1959 | ); | ||||||||||||||||||||||||||||||||
1960 | |||||||||||||||||||||||||||||||||
1961 | This syntax allows you to easily set the run mode from $ENV{PATH_INFO}. It | ||||||||||||||||||||||||||||||||
1962 | will try to set the run mode from the first part of $ENV{PATH_INFO} (before the | ||||||||||||||||||||||||||||||||
1963 | first "/"). To specify that you would rather get the run mode name from the 2nd | ||||||||||||||||||||||||||||||||
1964 | part of $ENV{PATH_INFO}: | ||||||||||||||||||||||||||||||||
1965 | |||||||||||||||||||||||||||||||||
1966 | $webapp->mode_param( path_info=> 2 ); | ||||||||||||||||||||||||||||||||
1967 | |||||||||||||||||||||||||||||||||
1968 | This also demonstrates that you don't need to pass in the C hash key. It will | ||||||||||||||||||||||||||||||||
1969 | still default to C |
||||||||||||||||||||||||||||||||
1970 | |||||||||||||||||||||||||||||||||
1971 | You can also set C |
||||||||||||||||||||||||||||||||
1972 | list index: if it is -1 the run mode name will be taken from the last part of | ||||||||||||||||||||||||||||||||
1973 | $ENV{PATH_INFO}, if it is -2, the one before that, and so on. | ||||||||||||||||||||||||||||||||
1974 | |||||||||||||||||||||||||||||||||
1975 | |||||||||||||||||||||||||||||||||
1976 | If no run mode is found in $ENV{PATH_INFO}, it will fall back to looking in the | ||||||||||||||||||||||||||||||||
1977 | value of a the CGI form field defined with 'param', as described above. This | ||||||||||||||||||||||||||||||||
1978 | allows you to use the convenient $ENV{PATH_INFO} trick most of the time, but | ||||||||||||||||||||||||||||||||
1979 | also supports the edge cases, such as when you don't know what the run mode | ||||||||||||||||||||||||||||||||
1980 | will be ahead of time and want to define it with JavaScript. | ||||||||||||||||||||||||||||||||
1981 | |||||||||||||||||||||||||||||||||
1982 | B |
||||||||||||||||||||||||||||||||
1983 | |||||||||||||||||||||||||||||||||
1984 | Using $ENV{PATH_INFO} to name your run mode creates a clean separation between | ||||||||||||||||||||||||||||||||
1985 | the form variables you submit and how you determine the processing run mode. It | ||||||||||||||||||||||||||||||||
1986 | also creates URLs that are more search engine friendly. Let's look at an | ||||||||||||||||||||||||||||||||
1987 | example form submission using this syntax: | ||||||||||||||||||||||||||||||||
1988 | |||||||||||||||||||||||||||||||||
1989 | |||||||||||||||||||||||||||||||||
1990 | |||||||||||||||||||||||||||||||||
1991 | |||||||||||||||||||||||||||||||||
1992 | Here the run mode would be set to "edit_form". Here's another example with a | ||||||||||||||||||||||||||||||||
1993 | query string: | ||||||||||||||||||||||||||||||||
1994 | |||||||||||||||||||||||||||||||||
1995 | /cgi-bin/instance.cgi/edit_form?breed_id=2 | ||||||||||||||||||||||||||||||||
1996 | |||||||||||||||||||||||||||||||||
1997 | This demonstrates that you can use $ENV{PATH_INFO} and a query string together | ||||||||||||||||||||||||||||||||
1998 | without problems. $ENV{PATH_INFO} is defined as part of the CGI specification | ||||||||||||||||||||||||||||||||
1999 | should be supported by any web server that supports CGI scripts. | ||||||||||||||||||||||||||||||||
2000 | |||||||||||||||||||||||||||||||||
2001 | =cut | ||||||||||||||||||||||||||||||||
2002 | |||||||||||||||||||||||||||||||||
2003 | sub mode_param { | ||||||||||||||||||||||||||||||||
2004 | 172 | 172 | 1 | 299 | my $self = shift; | ||||||||||||||||||||||||||||
2005 | 172 | 167 | my $mode_param; | ||||||||||||||||||||||||||||||
2006 | |||||||||||||||||||||||||||||||||
2007 | # First use? Create new __MODE_PARAM | ||||||||||||||||||||||||||||||||
2008 | 172 | 100 | 416 | $self->{__MODE_PARAM} = 'rm' unless (exists($self->{__MODE_PARAM})); | |||||||||||||||||||||||||||||
2009 | |||||||||||||||||||||||||||||||||
2010 | 172 | 177 | my %p; | ||||||||||||||||||||||||||||||
2011 | # expecting a scalar or code ref | ||||||||||||||||||||||||||||||||
2012 | 172 | 100 | 323 | if ((scalar @_) == 1) { | |||||||||||||||||||||||||||||
2013 | 104 | 134 | $mode_param = $_[0]; | ||||||||||||||||||||||||||||||
2014 | } | ||||||||||||||||||||||||||||||||
2015 | # expecting hash style params | ||||||||||||||||||||||||||||||||
2016 | else { | ||||||||||||||||||||||||||||||||
2017 | 68 | 50 | 169 | croak("CGI::Application->mode_param() : You gave me an odd number of parameters to mode_param()!") | |||||||||||||||||||||||||||||
2018 | unless ((@_ % 2) == 0); | ||||||||||||||||||||||||||||||||
2019 | 68 | 106 | %p = @_; | ||||||||||||||||||||||||||||||
2020 | 68 | 86 | $mode_param = $p{param}; | ||||||||||||||||||||||||||||||
2021 | |||||||||||||||||||||||||||||||||
2022 | 68 | 100 | 100 | 184 | if ( $p{path_info} && $self->query->path_info() ) { | ||||||||||||||||||||||||||||
2023 | 4 | 718 | my $pi = $self->query->path_info(); | ||||||||||||||||||||||||||||||
2024 | |||||||||||||||||||||||||||||||||
2025 | 4 | 95 | my $idx = $p{path_info}; | ||||||||||||||||||||||||||||||
2026 | # two cases: negative or positive index | ||||||||||||||||||||||||||||||||
2027 | # negative index counts from the end of path_info | ||||||||||||||||||||||||||||||||
2028 | # positive index needs to be fixed because | ||||||||||||||||||||||||||||||||
2029 | # computer scientists like to start counting from zero. | ||||||||||||||||||||||||||||||||
2030 | 4 | 100 | 13 | $idx -= 1 if ($idx > 0) ; | |||||||||||||||||||||||||||||
2031 | |||||||||||||||||||||||||||||||||
2032 | # remove the leading slash | ||||||||||||||||||||||||||||||||
2033 | 4 | 21 | $pi =~ s!^/!!; | ||||||||||||||||||||||||||||||
2034 | |||||||||||||||||||||||||||||||||
2035 | # grab the requested field location | ||||||||||||||||||||||||||||||||
2036 | 4 | 50 | 17 | $pi = (split q'/', $pi)[$idx] || ''; | |||||||||||||||||||||||||||||
2037 | |||||||||||||||||||||||||||||||||
2038 | 4 | 50 | 15 | $mode_param = (length $pi) ? { run_mode => $pi } : $mode_param; | |||||||||||||||||||||||||||||
2039 | } | ||||||||||||||||||||||||||||||||
2040 | |||||||||||||||||||||||||||||||||
2041 | } | ||||||||||||||||||||||||||||||||
2042 | |||||||||||||||||||||||||||||||||
2043 | # If data is provided, set it | ||||||||||||||||||||||||||||||||
2044 | 172 | 100 | 66 | 731 | if (defined $mode_param and length $mode_param) { | ||||||||||||||||||||||||||||
2045 | 109 | 158 | $self->{__MODE_PARAM} = $mode_param; | ||||||||||||||||||||||||||||||
2046 | } | ||||||||||||||||||||||||||||||||
2047 | |||||||||||||||||||||||||||||||||
2048 | 172 | 299 | return $self->{__MODE_PARAM}; | ||||||||||||||||||||||||||||||
2049 | } | ||||||||||||||||||||||||||||||||
2050 | |||||||||||||||||||||||||||||||||
2051 | |||||||||||||||||||||||||||||||||
2052 | =head3 prerun_mode() | ||||||||||||||||||||||||||||||||
2053 | |||||||||||||||||||||||||||||||||
2054 | $webapp->prerun_mode('new_run_mode'); | ||||||||||||||||||||||||||||||||
2055 | |||||||||||||||||||||||||||||||||
2056 | The prerun_mode() method is an accessor/mutator which can be used within | ||||||||||||||||||||||||||||||||
2057 | your cgiapp_prerun() method to change the run mode which is about to be executed. | ||||||||||||||||||||||||||||||||
2058 | For example, consider: | ||||||||||||||||||||||||||||||||
2059 | |||||||||||||||||||||||||||||||||
2060 | # In WebApp.pm: | ||||||||||||||||||||||||||||||||
2061 | package WebApp; | ||||||||||||||||||||||||||||||||
2062 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
2063 | sub cgiapp_prerun { | ||||||||||||||||||||||||||||||||
2064 | my $self = shift; | ||||||||||||||||||||||||||||||||
2065 | |||||||||||||||||||||||||||||||||
2066 | # Get the web user name, if any | ||||||||||||||||||||||||||||||||
2067 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
2068 | my $user = $q->remote_user(); | ||||||||||||||||||||||||||||||||
2069 | |||||||||||||||||||||||||||||||||
2070 | # Redirect to login, if necessary | ||||||||||||||||||||||||||||||||
2071 | unless ($user) { | ||||||||||||||||||||||||||||||||
2072 | $self->prerun_mode('login'); | ||||||||||||||||||||||||||||||||
2073 | } | ||||||||||||||||||||||||||||||||
2074 | } | ||||||||||||||||||||||||||||||||
2075 | |||||||||||||||||||||||||||||||||
2076 | |||||||||||||||||||||||||||||||||
2077 | In this example, the web user will be forced into the "login" run mode | ||||||||||||||||||||||||||||||||
2078 | unless they have already logged in. The prerun_mode() method permits | ||||||||||||||||||||||||||||||||
2079 | a scalar text string to be set which overrides whatever the run mode | ||||||||||||||||||||||||||||||||
2080 | would otherwise be. | ||||||||||||||||||||||||||||||||
2081 | |||||||||||||||||||||||||||||||||
2082 | The use of prerun_mode() within cgiapp_prerun() differs from setting | ||||||||||||||||||||||||||||||||
2083 | mode_param() to use a call-back via subroutine reference. It differs | ||||||||||||||||||||||||||||||||
2084 | because cgiapp_prerun() allows you to selectively set the run mode based | ||||||||||||||||||||||||||||||||
2085 | on some logic in your cgiapp_prerun() method. The call-back facility of | ||||||||||||||||||||||||||||||||
2086 | mode_param() forces you to entirely replace CGI::Application's mechanism | ||||||||||||||||||||||||||||||||
2087 | for determining the run mode with your own method. The prerun_mode() | ||||||||||||||||||||||||||||||||
2088 | method should be used in cases where you want to use CGI::Application's | ||||||||||||||||||||||||||||||||
2089 | normal run mode switching facility, but you want to make selective | ||||||||||||||||||||||||||||||||
2090 | changes to the mode under specific conditions. | ||||||||||||||||||||||||||||||||
2091 | |||||||||||||||||||||||||||||||||
2092 | B |
||||||||||||||||||||||||||||||||
2093 | a cgiapp_prerun() method. Your application will die() if you call | ||||||||||||||||||||||||||||||||
2094 | prerun_mode() elsewhere, such as in setup() or a run mode method. | ||||||||||||||||||||||||||||||||
2095 | |||||||||||||||||||||||||||||||||
2096 | =head2 Dispatching Clean URIs to run modes | ||||||||||||||||||||||||||||||||
2097 | |||||||||||||||||||||||||||||||||
2098 | Modern web frameworks dispense with cruft in URIs, providing in clean | ||||||||||||||||||||||||||||||||
2099 | URIs instead. Instead of: | ||||||||||||||||||||||||||||||||
2100 | |||||||||||||||||||||||||||||||||
2101 | /cgi-bin/item.cgi?rm=view&id=15 | ||||||||||||||||||||||||||||||||
2102 | |||||||||||||||||||||||||||||||||
2103 | A clean URI to describe the same resource might be: | ||||||||||||||||||||||||||||||||
2104 | |||||||||||||||||||||||||||||||||
2105 | /item/15/view | ||||||||||||||||||||||||||||||||
2106 | |||||||||||||||||||||||||||||||||
2107 | The process of mapping these URIs to run modes is called dispatching and is | ||||||||||||||||||||||||||||||||
2108 | handled by L |
||||||||||||||||||||||||||||||||
2109 | layer you can fairly easily add to an application later. | ||||||||||||||||||||||||||||||||
2110 | |||||||||||||||||||||||||||||||||
2111 | =head2 Offline website development | ||||||||||||||||||||||||||||||||
2112 | |||||||||||||||||||||||||||||||||
2113 | You can work on your CGI::Application project on your desktop or laptop without | ||||||||||||||||||||||||||||||||
2114 | installing a full-featured web-server like Apache. Instead, install | ||||||||||||||||||||||||||||||||
2115 | L |
||||||||||||||||||||||||||||||||
2116 | have your own private application server up and running. | ||||||||||||||||||||||||||||||||
2117 | |||||||||||||||||||||||||||||||||
2118 | =head2 Automated Testing | ||||||||||||||||||||||||||||||||
2119 | |||||||||||||||||||||||||||||||||
2120 | L |
||||||||||||||||||||||||||||||||
2121 | without starting a web server. L |
||||||||||||||||||||||||||||||||
2122 | through a real web server. | ||||||||||||||||||||||||||||||||
2123 | |||||||||||||||||||||||||||||||||
2124 | Direct testing is also easy. CGI::Application will normally print the output of it's | ||||||||||||||||||||||||||||||||
2125 | run modes directly to STDOUT. This can be suppressed with an environment variable, | ||||||||||||||||||||||||||||||||
2126 | CGI_APP_RETURN_ONLY. For example: | ||||||||||||||||||||||||||||||||
2127 | |||||||||||||||||||||||||||||||||
2128 | $ENV{CGI_APP_RETURN_ONLY} = 1; | ||||||||||||||||||||||||||||||||
2129 | $output = $webapp->run(); | ||||||||||||||||||||||||||||||||
2130 | like($output, qr/good/, "output is good"); | ||||||||||||||||||||||||||||||||
2131 | |||||||||||||||||||||||||||||||||
2132 | Examples of this style can be seen in our own test suite. | ||||||||||||||||||||||||||||||||
2133 | |||||||||||||||||||||||||||||||||
2134 | =head1 PLUG-INS | ||||||||||||||||||||||||||||||||
2135 | |||||||||||||||||||||||||||||||||
2136 | CGI::Application has a plug-in architecture that is easy to use and easy | ||||||||||||||||||||||||||||||||
2137 | to develop new plug-ins for. | ||||||||||||||||||||||||||||||||
2138 | |||||||||||||||||||||||||||||||||
2139 | =head2 Recommended Plug-ins | ||||||||||||||||||||||||||||||||
2140 | |||||||||||||||||||||||||||||||||
2141 | The following plugins are recommended for general purpose web/db development: | ||||||||||||||||||||||||||||||||
2142 | |||||||||||||||||||||||||||||||||
2143 | =over 4 | ||||||||||||||||||||||||||||||||
2144 | |||||||||||||||||||||||||||||||||
2145 | =item * | ||||||||||||||||||||||||||||||||
2146 | |||||||||||||||||||||||||||||||||
2147 | L |
||||||||||||||||||||||||||||||||
2148 | |||||||||||||||||||||||||||||||||
2149 | =item * | ||||||||||||||||||||||||||||||||
2150 | |||||||||||||||||||||||||||||||||
2151 | L |
||||||||||||||||||||||||||||||||
2152 | |||||||||||||||||||||||||||||||||
2153 | =item * | ||||||||||||||||||||||||||||||||
2154 | |||||||||||||||||||||||||||||||||
2155 | L |
||||||||||||||||||||||||||||||||
2156 | |||||||||||||||||||||||||||||||||
2157 | =item * | ||||||||||||||||||||||||||||||||
2158 | |||||||||||||||||||||||||||||||||
2159 | L |
||||||||||||||||||||||||||||||||
2160 | |||||||||||||||||||||||||||||||||
2161 | =item * | ||||||||||||||||||||||||||||||||
2162 | |||||||||||||||||||||||||||||||||
2163 | L |
||||||||||||||||||||||||||||||||
2164 | management, this plugin provides a useful wrapper around L |
||||||||||||||||||||||||||||||||
2165 | |||||||||||||||||||||||||||||||||
2166 | =item * | ||||||||||||||||||||||||||||||||
2167 | |||||||||||||||||||||||||||||||||
2168 | L |
||||||||||||||||||||||||||||||||
2169 | |||||||||||||||||||||||||||||||||
2170 | =back | ||||||||||||||||||||||||||||||||
2171 | |||||||||||||||||||||||||||||||||
2172 | =head2 More plug-ins | ||||||||||||||||||||||||||||||||
2173 | |||||||||||||||||||||||||||||||||
2174 | Many more plugins are available as alternatives and for specific uses. For a | ||||||||||||||||||||||||||||||||
2175 | current complete list, please consult CPAN: | ||||||||||||||||||||||||||||||||
2176 | |||||||||||||||||||||||||||||||||
2177 | http://search.cpan.org/search?m=dist&q=CGI%2DApplication%2DPlugin | ||||||||||||||||||||||||||||||||
2178 | |||||||||||||||||||||||||||||||||
2179 | =over 4 | ||||||||||||||||||||||||||||||||
2180 | |||||||||||||||||||||||||||||||||
2181 | =item * | ||||||||||||||||||||||||||||||||
2182 | |||||||||||||||||||||||||||||||||
2183 | L |
||||||||||||||||||||||||||||||||
2184 | |||||||||||||||||||||||||||||||||
2185 | =item * | ||||||||||||||||||||||||||||||||
2186 | |||||||||||||||||||||||||||||||||
2187 | L |
||||||||||||||||||||||||||||||||
2188 | |||||||||||||||||||||||||||||||||
2189 | =item * | ||||||||||||||||||||||||||||||||
2190 | |||||||||||||||||||||||||||||||||
2191 | L |
||||||||||||||||||||||||||||||||
2192 | |||||||||||||||||||||||||||||||||
2193 | |||||||||||||||||||||||||||||||||
2194 | =item * | ||||||||||||||||||||||||||||||||
2195 | |||||||||||||||||||||||||||||||||
2196 | L |
||||||||||||||||||||||||||||||||
2197 | |||||||||||||||||||||||||||||||||
2198 | =item * | ||||||||||||||||||||||||||||||||
2199 | |||||||||||||||||||||||||||||||||
2200 | L |
||||||||||||||||||||||||||||||||
2201 | |||||||||||||||||||||||||||||||||
2202 | =item * | ||||||||||||||||||||||||||||||||
2203 | |||||||||||||||||||||||||||||||||
2204 | L |
||||||||||||||||||||||||||||||||
2205 | |||||||||||||||||||||||||||||||||
2206 | =item * | ||||||||||||||||||||||||||||||||
2207 | |||||||||||||||||||||||||||||||||
2208 | L |
||||||||||||||||||||||||||||||||
2209 | |||||||||||||||||||||||||||||||||
2210 | |||||||||||||||||||||||||||||||||
2211 | =item * | ||||||||||||||||||||||||||||||||
2212 | |||||||||||||||||||||||||||||||||
2213 | L |
||||||||||||||||||||||||||||||||
2214 | |||||||||||||||||||||||||||||||||
2215 | =item * | ||||||||||||||||||||||||||||||||
2216 | |||||||||||||||||||||||||||||||||
2217 | L |
||||||||||||||||||||||||||||||||
2218 | |||||||||||||||||||||||||||||||||
2219 | =item * | ||||||||||||||||||||||||||||||||
2220 | |||||||||||||||||||||||||||||||||
2221 | L |
||||||||||||||||||||||||||||||||
2222 | code structure, with the difference that code and HTML for each screen are in | ||||||||||||||||||||||||||||||||
2223 | separate files. | ||||||||||||||||||||||||||||||||
2224 | |||||||||||||||||||||||||||||||||
2225 | =item * | ||||||||||||||||||||||||||||||||
2226 | |||||||||||||||||||||||||||||||||
2227 | L |
||||||||||||||||||||||||||||||||
2228 | |||||||||||||||||||||||||||||||||
2229 | |||||||||||||||||||||||||||||||||
2230 | =back | ||||||||||||||||||||||||||||||||
2231 | |||||||||||||||||||||||||||||||||
2232 | |||||||||||||||||||||||||||||||||
2233 | |||||||||||||||||||||||||||||||||
2234 | Consult each plug-in for the exact usage syntax. | ||||||||||||||||||||||||||||||||
2235 | |||||||||||||||||||||||||||||||||
2236 | =head2 Writing Plug-ins | ||||||||||||||||||||||||||||||||
2237 | |||||||||||||||||||||||||||||||||
2238 | Writing plug-ins is simple. Simply create a new package, and export the | ||||||||||||||||||||||||||||||||
2239 | methods that you want to become part of a CGI::Application project. See | ||||||||||||||||||||||||||||||||
2240 | L |
||||||||||||||||||||||||||||||||
2241 | |||||||||||||||||||||||||||||||||
2242 | In order to avoid namespace conflicts within a CGI::Application object, | ||||||||||||||||||||||||||||||||
2243 | plugin developers are recommended to use a unique prefix, such as the | ||||||||||||||||||||||||||||||||
2244 | name of plugin package, when storing information. For instance: | ||||||||||||||||||||||||||||||||
2245 | |||||||||||||||||||||||||||||||||
2246 | $app->{__PARAM} = 'foo'; # BAD! Could conflict. | ||||||||||||||||||||||||||||||||
2247 | $app->{'MyPlugin::Module::__PARAM'} = 'foo'; # Good. | ||||||||||||||||||||||||||||||||
2248 | $app->{'MyPlugin::Module'}{__PARAM} = 'foo'; # Good. | ||||||||||||||||||||||||||||||||
2249 | |||||||||||||||||||||||||||||||||
2250 | =head2 Writing Advanced Plug-ins - Using callbacks | ||||||||||||||||||||||||||||||||
2251 | |||||||||||||||||||||||||||||||||
2252 | When writing a plug-in, you may want some action to happen automatically at a | ||||||||||||||||||||||||||||||||
2253 | particular stage, such as setting up a database connection or initializing a | ||||||||||||||||||||||||||||||||
2254 | session. By using these 'callback' methods, you can register a subroutine | ||||||||||||||||||||||||||||||||
2255 | to run at a particular phase, accomplishing this goal. | ||||||||||||||||||||||||||||||||
2256 | |||||||||||||||||||||||||||||||||
2257 | B |
||||||||||||||||||||||||||||||||
2258 | |||||||||||||||||||||||||||||||||
2259 | # register a callback to the standard CGI::Application hooks | ||||||||||||||||||||||||||||||||
2260 | # one of 'init', 'prerun', 'postrun', 'teardown' or 'load_tmpl' | ||||||||||||||||||||||||||||||||
2261 | # As a plug-in author, this is probably the only method you need. | ||||||||||||||||||||||||||||||||
2262 | |||||||||||||||||||||||||||||||||
2263 | # Class-based: callback will persist for all runs of the application | ||||||||||||||||||||||||||||||||
2264 | $class->add_callback('init', \&some_other_method); | ||||||||||||||||||||||||||||||||
2265 | |||||||||||||||||||||||||||||||||
2266 | # Object-based: callback will only last for lifetime of this object | ||||||||||||||||||||||||||||||||
2267 | $self->add_callback('prerun', \&some_method); | ||||||||||||||||||||||||||||||||
2268 | |||||||||||||||||||||||||||||||||
2269 | # If you want to create a new hook location in your application, | ||||||||||||||||||||||||||||||||
2270 | # You'll need to know about the following two methods to create | ||||||||||||||||||||||||||||||||
2271 | # the hook and call it. | ||||||||||||||||||||||||||||||||
2272 | |||||||||||||||||||||||||||||||||
2273 | # Create a new hook | ||||||||||||||||||||||||||||||||
2274 | $self->new_hook('pretemplate'); | ||||||||||||||||||||||||||||||||
2275 | |||||||||||||||||||||||||||||||||
2276 | # Then later execute all the callbacks registered at this hook | ||||||||||||||||||||||||||||||||
2277 | $self->call_hook('pretemplate'); | ||||||||||||||||||||||||||||||||
2278 | |||||||||||||||||||||||||||||||||
2279 | B |
||||||||||||||||||||||||||||||||
2280 | |||||||||||||||||||||||||||||||||
2281 | =head3 add_callback() | ||||||||||||||||||||||||||||||||
2282 | |||||||||||||||||||||||||||||||||
2283 | $self->add_callback ('teardown', \&callback); | ||||||||||||||||||||||||||||||||
2284 | $class->add_callback('teardown', 'method'); | ||||||||||||||||||||||||||||||||
2285 | |||||||||||||||||||||||||||||||||
2286 | The add_callback method allows you to register a callback | ||||||||||||||||||||||||||||||||
2287 | function that is to be called at the given stage of execution. | ||||||||||||||||||||||||||||||||
2288 | Valid hooks include 'init', 'prerun', 'postrun' and 'teardown', | ||||||||||||||||||||||||||||||||
2289 | 'load_tmpl', and any other hooks defined using the C |
||||||||||||||||||||||||||||||||
2290 | method. | ||||||||||||||||||||||||||||||||
2291 | |||||||||||||||||||||||||||||||||
2292 | The callback should be a reference to a subroutine or the name of a | ||||||||||||||||||||||||||||||||
2293 | method. | ||||||||||||||||||||||||||||||||
2294 | |||||||||||||||||||||||||||||||||
2295 | If multiple callbacks are added to the same hook, they will all be | ||||||||||||||||||||||||||||||||
2296 | executed one after the other. The exact order depends on which class | ||||||||||||||||||||||||||||||||
2297 | installed each callback, as described below under B |
||||||||||||||||||||||||||||||||
2298 | |||||||||||||||||||||||||||||||||
2299 | Callbacks can either be I |
||||||||||||||||||||||||||||||||
2300 | upon whether you call C |
||||||||||||||||||||||||||||||||
2301 | method: | ||||||||||||||||||||||||||||||||
2302 | |||||||||||||||||||||||||||||||||
2303 | # add object-based callback | ||||||||||||||||||||||||||||||||
2304 | $self->add_callback('teardown', \&callback); | ||||||||||||||||||||||||||||||||
2305 | |||||||||||||||||||||||||||||||||
2306 | # add class-based callbacks | ||||||||||||||||||||||||||||||||
2307 | $class->add_callback('teardown', \&callback); | ||||||||||||||||||||||||||||||||
2308 | My::Project->add_callback('teardown', \&callback); | ||||||||||||||||||||||||||||||||
2309 | |||||||||||||||||||||||||||||||||
2310 | Object-based callbacks are stored in your web application's C<$c> | ||||||||||||||||||||||||||||||||
2311 | object; at the end of the request when the C<$c> object goes out of | ||||||||||||||||||||||||||||||||
2312 | scope, the callbacks are gone too. | ||||||||||||||||||||||||||||||||
2313 | |||||||||||||||||||||||||||||||||
2314 | Object-based callbacks are useful for one-time tasks that apply only to | ||||||||||||||||||||||||||||||||
2315 | the current running application. For instance you could install a | ||||||||||||||||||||||||||||||||
2316 | C |
||||||||||||||||||||||||||||||||
2317 | end of the current request, after all the HTML has been sent to the | ||||||||||||||||||||||||||||||||
2318 | browser. | ||||||||||||||||||||||||||||||||
2319 | |||||||||||||||||||||||||||||||||
2320 | Class-based callbacks survive for the duration of the running Perl | ||||||||||||||||||||||||||||||||
2321 | process. (In a persistent environment such as C |
||||||||||||||||||||||||||||||||
2322 | C |
||||||||||||||||||||||||||||||||
2323 | |||||||||||||||||||||||||||||||||
2324 | Class-based callbacks are useful for plugins to add features to all web | ||||||||||||||||||||||||||||||||
2325 | applications. | ||||||||||||||||||||||||||||||||
2326 | |||||||||||||||||||||||||||||||||
2327 | Another feature of class-based callbacks is that your plugin can create | ||||||||||||||||||||||||||||||||
2328 | hooks and add callbacks at any time - even before the web application's | ||||||||||||||||||||||||||||||||
2329 | C<$c> object has been initialized. A good place to do this is in | ||||||||||||||||||||||||||||||||
2330 | your plugin's C |
||||||||||||||||||||||||||||||||
2331 | |||||||||||||||||||||||||||||||||
2332 | package CGI::Application::Plugin::MyPlugin; | ||||||||||||||||||||||||||||||||
2333 | use base 'Exporter'; | ||||||||||||||||||||||||||||||||
2334 | sub import { | ||||||||||||||||||||||||||||||||
2335 | my $caller = scalar(caller); | ||||||||||||||||||||||||||||||||
2336 | $caller->add_callback('init', 'my_setup'); | ||||||||||||||||||||||||||||||||
2337 | goto &Exporter::import; | ||||||||||||||||||||||||||||||||
2338 | } | ||||||||||||||||||||||||||||||||
2339 | |||||||||||||||||||||||||||||||||
2340 | Notice that C<< $caller->add_callback >> installs the callback | ||||||||||||||||||||||||||||||||
2341 | on behalf of the module that contained the line: | ||||||||||||||||||||||||||||||||
2342 | |||||||||||||||||||||||||||||||||
2343 | use CGI::Application::Plugin::MyPlugin; | ||||||||||||||||||||||||||||||||
2344 | |||||||||||||||||||||||||||||||||
2345 | =cut | ||||||||||||||||||||||||||||||||
2346 | |||||||||||||||||||||||||||||||||
2347 | sub add_callback { | ||||||||||||||||||||||||||||||||
2348 | 44 | 44 | 1 | 1908 | my ($c_or_class, $hook, $callback) = @_; | ||||||||||||||||||||||||||||
2349 | |||||||||||||||||||||||||||||||||
2350 | 44 | 51 | $hook = lc $hook; | ||||||||||||||||||||||||||||||
2351 | |||||||||||||||||||||||||||||||||
2352 | 44 | 50 | 90 | die "no callback provided when calling add_callback" unless $callback; | |||||||||||||||||||||||||||||
2353 | 44 | 50 | 125 | die "Unknown hook ($hook)" unless exists $INSTALLED_CALLBACKS{$hook}; | |||||||||||||||||||||||||||||
2354 | |||||||||||||||||||||||||||||||||
2355 | 44 | 100 | 57 | if (ref $c_or_class) { | |||||||||||||||||||||||||||||
2356 | # Install in object | ||||||||||||||||||||||||||||||||
2357 | 5 | 6 | my $self = $c_or_class; | ||||||||||||||||||||||||||||||
2358 | 5 | 6 | push @{ $self->{__INSTALLED_CALLBACKS}{$hook} }, $callback; | ||||||||||||||||||||||||||||||
5 | 18 | ||||||||||||||||||||||||||||||||
2359 | } | ||||||||||||||||||||||||||||||||
2360 | else { | ||||||||||||||||||||||||||||||||
2361 | # Install in class | ||||||||||||||||||||||||||||||||
2362 | 39 | 36 | my $class = $c_or_class; | ||||||||||||||||||||||||||||||
2363 | 39 | 29 | push @{ $INSTALLED_CALLBACKS{$hook}{$class} }, $callback; | ||||||||||||||||||||||||||||||
39 | 99 | ||||||||||||||||||||||||||||||||
2364 | } | ||||||||||||||||||||||||||||||||
2365 | |||||||||||||||||||||||||||||||||
2366 | } | ||||||||||||||||||||||||||||||||
2367 | |||||||||||||||||||||||||||||||||
2368 | =head3 new_hook(HOOK) | ||||||||||||||||||||||||||||||||
2369 | |||||||||||||||||||||||||||||||||
2370 | $self->new_hook('pretemplate'); | ||||||||||||||||||||||||||||||||
2371 | |||||||||||||||||||||||||||||||||
2372 | The C |
||||||||||||||||||||||||||||||||
2373 | register callbacks. It takes one argument, a hook name. The hook location is | ||||||||||||||||||||||||||||||||
2374 | created if it does not already exist. A true value is always returned. | ||||||||||||||||||||||||||||||||
2375 | |||||||||||||||||||||||||||||||||
2376 | For an example, L |
||||||||||||||||||||||||||||||||
2377 | template is processed. | ||||||||||||||||||||||||||||||||
2378 | |||||||||||||||||||||||||||||||||
2379 | See C |
||||||||||||||||||||||||||||||||
2380 | |||||||||||||||||||||||||||||||||
2381 | =cut | ||||||||||||||||||||||||||||||||
2382 | |||||||||||||||||||||||||||||||||
2383 | sub new_hook { | ||||||||||||||||||||||||||||||||
2384 | 5 | 5 | 1 | 311 | my ($class, $hook) = @_; | ||||||||||||||||||||||||||||
2385 | 5 | 100 | 25 | $INSTALLED_CALLBACKS{$hook} ||= {}; | |||||||||||||||||||||||||||||
2386 | 5 | 11 | return 1; | ||||||||||||||||||||||||||||||
2387 | } | ||||||||||||||||||||||||||||||||
2388 | |||||||||||||||||||||||||||||||||
2389 | =head3 call_hook(HOOK) | ||||||||||||||||||||||||||||||||
2390 | |||||||||||||||||||||||||||||||||
2391 | $self->call_hook('pretemplate', @args); | ||||||||||||||||||||||||||||||||
2392 | |||||||||||||||||||||||||||||||||
2393 | The C |
||||||||||||||||||||||||||||||||
2394 | at the given hook. It is used in conjunction with the C |
||||||||||||||||||||||||||||||||
2395 | allows you to create a new hook location. | ||||||||||||||||||||||||||||||||
2396 | |||||||||||||||||||||||||||||||||
2397 | The first argument to C |
||||||||||||||||||||||||||||||||
2398 | are passed to every callback executed at the hook location. So, a stub for a | ||||||||||||||||||||||||||||||||
2399 | callback at the 'pretemplate' hook would look like this: | ||||||||||||||||||||||||||||||||
2400 | |||||||||||||||||||||||||||||||||
2401 | sub my_hook { | ||||||||||||||||||||||||||||||||
2402 | my ($c,@args) = @_; | ||||||||||||||||||||||||||||||||
2403 | # .... | ||||||||||||||||||||||||||||||||
2404 | } | ||||||||||||||||||||||||||||||||
2405 | |||||||||||||||||||||||||||||||||
2406 | Note that hooks are semi-public locations. Calling a hook means executing | ||||||||||||||||||||||||||||||||
2407 | callbacks that were registered to that hook by the current object and also | ||||||||||||||||||||||||||||||||
2408 | those registered by any of the current object's parent classes. See below for | ||||||||||||||||||||||||||||||||
2409 | the exact ordering. | ||||||||||||||||||||||||||||||||
2410 | |||||||||||||||||||||||||||||||||
2411 | =cut | ||||||||||||||||||||||||||||||||
2412 | |||||||||||||||||||||||||||||||||
2413 | sub call_hook { | ||||||||||||||||||||||||||||||||
2414 | 261 | 261 | 1 | 326 | my $self = shift; | ||||||||||||||||||||||||||||
2415 | 261 | 33 | 546 | my $app_class = ref $self || $self; | |||||||||||||||||||||||||||||
2416 | 261 | 345 | my $hook = lc shift; | ||||||||||||||||||||||||||||||
2417 | 261 | 329 | my @args = @_; | ||||||||||||||||||||||||||||||
2418 | |||||||||||||||||||||||||||||||||
2419 | 261 | 50 | 543 | die "Unknown hook ($hook)" unless exists $INSTALLED_CALLBACKS{$hook}; | |||||||||||||||||||||||||||||
2420 | |||||||||||||||||||||||||||||||||
2421 | 261 | 203 | my %executed_callback; | ||||||||||||||||||||||||||||||
2422 | |||||||||||||||||||||||||||||||||
2423 | # First, run callbacks installed in the object | ||||||||||||||||||||||||||||||||
2424 | 261 | 223 | foreach my $callback (@{ $self->{__INSTALLED_CALLBACKS}{$hook} }) { | ||||||||||||||||||||||||||||||
261 | 774 | ||||||||||||||||||||||||||||||||
2425 | 5 | 50 | 13 | next if $executed_callback{$callback}; | |||||||||||||||||||||||||||||
2426 | 5 | 5 | eval { $self->$callback(@args); }; | ||||||||||||||||||||||||||||||
5 | 20 | ||||||||||||||||||||||||||||||||
2427 | 5 | 38 | $executed_callback{$callback} = 1; | ||||||||||||||||||||||||||||||
2428 | 5 | 50 | 14 | die "Error executing object callback in $hook stage: $@" if $@; | |||||||||||||||||||||||||||||
2429 | } | ||||||||||||||||||||||||||||||||
2430 | |||||||||||||||||||||||||||||||||
2431 | # Next, run callbacks installed in class hierarchy | ||||||||||||||||||||||||||||||||
2432 | |||||||||||||||||||||||||||||||||
2433 | # Cache this value as a performance boost | ||||||||||||||||||||||||||||||||
2434 | 261 | 100 | 776 | $self->{__CALLBACK_CLASSES} ||= [ Class::ISA::self_and_super_path($app_class) ]; | |||||||||||||||||||||||||||||
2435 | |||||||||||||||||||||||||||||||||
2436 | # Get list of classes that the current app inherits from | ||||||||||||||||||||||||||||||||
2437 | 261 | 2389 | foreach my $class (@{ $self->{__CALLBACK_CLASSES} }) { | ||||||||||||||||||||||||||||||
261 | 439 | ||||||||||||||||||||||||||||||||
2438 | |||||||||||||||||||||||||||||||||
2439 | # skip those classes that contain no callbacks | ||||||||||||||||||||||||||||||||
2440 | 521 | 100 | 1099 | next unless exists $INSTALLED_CALLBACKS{$hook}{$class}; | |||||||||||||||||||||||||||||
2441 | |||||||||||||||||||||||||||||||||
2442 | # call all of the callbacks in the class | ||||||||||||||||||||||||||||||||
2443 | 277 | 305 | foreach my $callback (@{ $INSTALLED_CALLBACKS{$hook}{$class} }) { | ||||||||||||||||||||||||||||||
277 | 463 | ||||||||||||||||||||||||||||||||
2444 | 305 | 100 | 703 | next if $executed_callback{$callback}; | |||||||||||||||||||||||||||||
2445 | 295 | 312 | eval { $self->$callback(@args); }; | ||||||||||||||||||||||||||||||
295 | 958 | ||||||||||||||||||||||||||||||||
2446 | 295 | 764 | $executed_callback{$callback} = 1; | ||||||||||||||||||||||||||||||
2447 | 295 | 50 | 1023 | die "Error executing class callback in $hook stage: $@" if $@; | |||||||||||||||||||||||||||||
2448 | } | ||||||||||||||||||||||||||||||||
2449 | } | ||||||||||||||||||||||||||||||||
2450 | |||||||||||||||||||||||||||||||||
2451 | } | ||||||||||||||||||||||||||||||||
2452 | |||||||||||||||||||||||||||||||||
2453 | =pod | ||||||||||||||||||||||||||||||||
2454 | |||||||||||||||||||||||||||||||||
2455 | B |
||||||||||||||||||||||||||||||||
2456 | |||||||||||||||||||||||||||||||||
2457 | Object-based callbacks are run before class-based callbacks. | ||||||||||||||||||||||||||||||||
2458 | |||||||||||||||||||||||||||||||||
2459 | The order of class-based callbacks is determined by the inheritance tree of the | ||||||||||||||||||||||||||||||||
2460 | running application. The built-in methods of C |
||||||||||||||||||||||||||||||||
2461 | C |
||||||||||||||||||||||||||||||||
2462 | ordering below. | ||||||||||||||||||||||||||||||||
2463 | |||||||||||||||||||||||||||||||||
2464 | In a persistent environment, there might be a lot of applications | ||||||||||||||||||||||||||||||||
2465 | in memory at the same time. For instance: | ||||||||||||||||||||||||||||||||
2466 | |||||||||||||||||||||||||||||||||
2467 | CGI::Application | ||||||||||||||||||||||||||||||||
2468 | Other::Project # uses CGI::Application::Plugin::Baz | ||||||||||||||||||||||||||||||||
2469 | Other::App # uses CGI::Application::Plugin::Bam | ||||||||||||||||||||||||||||||||
2470 | |||||||||||||||||||||||||||||||||
2471 | My::Project # uses CGI::Application::Plugin::Foo | ||||||||||||||||||||||||||||||||
2472 | My::App # uses CGI::Application::Plugin::Bar | ||||||||||||||||||||||||||||||||
2473 | |||||||||||||||||||||||||||||||||
2474 | Suppose that each of the above plugins each added a callback to be run | ||||||||||||||||||||||||||||||||
2475 | at the 'init' stage: | ||||||||||||||||||||||||||||||||
2476 | |||||||||||||||||||||||||||||||||
2477 | Plugin init callback | ||||||||||||||||||||||||||||||||
2478 | ------ ------------- | ||||||||||||||||||||||||||||||||
2479 | CGI::Application::Plugin::Baz baz_startup | ||||||||||||||||||||||||||||||||
2480 | CGI::Application::Plugin::Bam bam_startup | ||||||||||||||||||||||||||||||||
2481 | |||||||||||||||||||||||||||||||||
2482 | CGI::Application::Plugin::Foo foo_startup | ||||||||||||||||||||||||||||||||
2483 | CGI::Application::Plugin::Bar bar_startup | ||||||||||||||||||||||||||||||||
2484 | |||||||||||||||||||||||||||||||||
2485 | When C |
||||||||||||||||||||||||||||||||
2486 | run. The other callbacks are skipped. | ||||||||||||||||||||||||||||||||
2487 | |||||||||||||||||||||||||||||||||
2488 | The C<@ISA> list of C |
||||||||||||||||||||||||||||||||
2489 | |||||||||||||||||||||||||||||||||
2490 | My::App | ||||||||||||||||||||||||||||||||
2491 | My::Project | ||||||||||||||||||||||||||||||||
2492 | CGI::Application | ||||||||||||||||||||||||||||||||
2493 | |||||||||||||||||||||||||||||||||
2494 | This order determines the order of callbacks run. | ||||||||||||||||||||||||||||||||
2495 | |||||||||||||||||||||||||||||||||
2496 | When C |
||||||||||||||||||||||||||||||||
2497 | installed by these modules are run in order, resulting in: | ||||||||||||||||||||||||||||||||
2498 | C |
||||||||||||||||||||||||||||||||
2499 | |||||||||||||||||||||||||||||||||
2500 | If a single class installs more than one callback at the same hook, then | ||||||||||||||||||||||||||||||||
2501 | these callbacks are run in the order they were registered (FIFO). | ||||||||||||||||||||||||||||||||
2502 | |||||||||||||||||||||||||||||||||
2503 | |||||||||||||||||||||||||||||||||
2504 | |||||||||||||||||||||||||||||||||
2505 | =cut | ||||||||||||||||||||||||||||||||
2506 | |||||||||||||||||||||||||||||||||
2507 | |||||||||||||||||||||||||||||||||
2508 | =head1 COMMUNITY | ||||||||||||||||||||||||||||||||
2509 | |||||||||||||||||||||||||||||||||
2510 | Therese are primary resources available for those who wish to learn more | ||||||||||||||||||||||||||||||||
2511 | about CGI::Application and discuss it with others. | ||||||||||||||||||||||||||||||||
2512 | |||||||||||||||||||||||||||||||||
2513 | B |
||||||||||||||||||||||||||||||||
2514 | |||||||||||||||||||||||||||||||||
2515 | This is a community built and maintained resource that anyone is welcome to | ||||||||||||||||||||||||||||||||
2516 | contribute to. It contains a number of articles of its own and links | ||||||||||||||||||||||||||||||||
2517 | to many other CGI::Application related pages: | ||||||||||||||||||||||||||||||||
2518 | |||||||||||||||||||||||||||||||||
2519 | L |
||||||||||||||||||||||||||||||||
2520 | |||||||||||||||||||||||||||||||||
2521 | B |
||||||||||||||||||||||||||||||||
2522 | |||||||||||||||||||||||||||||||||
2523 | If you have any questions, comments, bug reports or feature suggestions, | ||||||||||||||||||||||||||||||||
2524 | post them to the support mailing list! To join the mailing list, simply | ||||||||||||||||||||||||||||||||
2525 | send a blank message to "cgiapp-subscribe@lists.erlbaum.net". | ||||||||||||||||||||||||||||||||
2526 | |||||||||||||||||||||||||||||||||
2527 | B |
||||||||||||||||||||||||||||||||
2528 | |||||||||||||||||||||||||||||||||
2529 | You can also drop by C<#cgiapp> on C |
||||||||||||||||||||||||||||||||
2530 | some people involved with the project there. | ||||||||||||||||||||||||||||||||
2531 | |||||||||||||||||||||||||||||||||
2532 | B | ||||||||||||||||||||||||||||||||
2533 | |||||||||||||||||||||||||||||||||
2534 | This project is managed using git and is available on Github: | ||||||||||||||||||||||||||||||||
2535 | |||||||||||||||||||||||||||||||||
2536 | L |
||||||||||||||||||||||||||||||||
2537 | |||||||||||||||||||||||||||||||||
2538 | =head1 SEE ALSO | ||||||||||||||||||||||||||||||||
2539 | |||||||||||||||||||||||||||||||||
2540 | =over 4 | ||||||||||||||||||||||||||||||||
2541 | |||||||||||||||||||||||||||||||||
2542 | =item o | ||||||||||||||||||||||||||||||||
2543 | |||||||||||||||||||||||||||||||||
2544 | L |
||||||||||||||||||||||||||||||||
2545 | |||||||||||||||||||||||||||||||||
2546 | =item o | ||||||||||||||||||||||||||||||||
2547 | |||||||||||||||||||||||||||||||||
2548 | L |
||||||||||||||||||||||||||||||||
2549 | |||||||||||||||||||||||||||||||||
2550 | =item o | ||||||||||||||||||||||||||||||||
2551 | |||||||||||||||||||||||||||||||||
2552 | B |
||||||||||||||||||||||||||||||||
2553 | CGI::Application. http://www.cafweb.org/ | ||||||||||||||||||||||||||||||||
2554 | |||||||||||||||||||||||||||||||||
2555 | =back | ||||||||||||||||||||||||||||||||
2556 | |||||||||||||||||||||||||||||||||
2557 | =head1 MORE READING | ||||||||||||||||||||||||||||||||
2558 | |||||||||||||||||||||||||||||||||
2559 | If you're interested in finding out more about CGI::Application, the | ||||||||||||||||||||||||||||||||
2560 | following articles are available on Perl.com: | ||||||||||||||||||||||||||||||||
2561 | |||||||||||||||||||||||||||||||||
2562 | Using CGI::Application | ||||||||||||||||||||||||||||||||
2563 | http://www.perl.com/pub/a/2001/06/05/cgi.html | ||||||||||||||||||||||||||||||||
2564 | |||||||||||||||||||||||||||||||||
2565 | Rapid Website Development with CGI::Application | ||||||||||||||||||||||||||||||||
2566 | http://www.perl.com/pub/a/2006/10/19/cgi_application.html | ||||||||||||||||||||||||||||||||
2567 | |||||||||||||||||||||||||||||||||
2568 | Thanks to O'Reilly for publishing these articles, and for the incredible value | ||||||||||||||||||||||||||||||||
2569 | they provide to the Perl community! | ||||||||||||||||||||||||||||||||
2570 | |||||||||||||||||||||||||||||||||
2571 | =head1 AUTHOR | ||||||||||||||||||||||||||||||||
2572 | |||||||||||||||||||||||||||||||||
2573 | Jesse Erlbaum |
||||||||||||||||||||||||||||||||
2574 | |||||||||||||||||||||||||||||||||
2575 | Mark Stosberg has served as a co-maintainer since version 3.2, Martin McGrath | ||||||||||||||||||||||||||||||||
2576 | became a co-maintainer as of version 4.51, with the help of the numerous | ||||||||||||||||||||||||||||||||
2577 | contributors documented in the Changes file. | ||||||||||||||||||||||||||||||||
2578 | |||||||||||||||||||||||||||||||||
2579 | =head1 CREDITS | ||||||||||||||||||||||||||||||||
2580 | |||||||||||||||||||||||||||||||||
2581 | CGI::Application was originally developed by The Erlbaum Group, a software | ||||||||||||||||||||||||||||||||
2582 | engineering and consulting firm in New York City. | ||||||||||||||||||||||||||||||||
2583 | |||||||||||||||||||||||||||||||||
2584 | Thanks to Vanguard Media (http://www.vm.com) for funding the initial | ||||||||||||||||||||||||||||||||
2585 | development of this library and for encouraging Jesse Erlbaum to release it to | ||||||||||||||||||||||||||||||||
2586 | the world. | ||||||||||||||||||||||||||||||||
2587 | |||||||||||||||||||||||||||||||||
2588 | Many thanks to Sam Tregar (author of the most excellent | ||||||||||||||||||||||||||||||||
2589 | HTML::Template module!) for his innumerable contributions | ||||||||||||||||||||||||||||||||
2590 | to this module over the years, and most of all for getting | ||||||||||||||||||||||||||||||||
2591 | me off my ass to finally get this thing up on CPAN! | ||||||||||||||||||||||||||||||||
2592 | |||||||||||||||||||||||||||||||||
2593 | Many other people have contributed specific suggestions or patches, | ||||||||||||||||||||||||||||||||
2594 | which are documented in the C |
||||||||||||||||||||||||||||||||
2595 | |||||||||||||||||||||||||||||||||
2596 | Thanks also to all the members of the CGI-App mailing list! | ||||||||||||||||||||||||||||||||
2597 | Your ideas, suggestions, insights (and criticism!) have helped | ||||||||||||||||||||||||||||||||
2598 | shape this module immeasurably. (To join the mailing list, simply | ||||||||||||||||||||||||||||||||
2599 | send a blank message to "cgiapp-subscribe@lists.erlbaum.net".) | ||||||||||||||||||||||||||||||||
2600 | |||||||||||||||||||||||||||||||||
2601 | =head1 LICENSE | ||||||||||||||||||||||||||||||||
2602 | |||||||||||||||||||||||||||||||||
2603 | CGI::Application : Framework for building reusable web-applications | ||||||||||||||||||||||||||||||||
2604 | Copyright (C) 2000-2003 Jesse Erlbaum |
||||||||||||||||||||||||||||||||
2605 | |||||||||||||||||||||||||||||||||
2606 | This module is free software; you can redistribute it and/or modify it | ||||||||||||||||||||||||||||||||
2607 | under the terms of either: | ||||||||||||||||||||||||||||||||
2608 | |||||||||||||||||||||||||||||||||
2609 | a) the GNU General Public License as published by the Free Software | ||||||||||||||||||||||||||||||||
2610 | Foundation; either version 1, or (at your option) any later version, | ||||||||||||||||||||||||||||||||
2611 | |||||||||||||||||||||||||||||||||
2612 | or | ||||||||||||||||||||||||||||||||
2613 | |||||||||||||||||||||||||||||||||
2614 | b) the "Artistic License" which comes with this module. | ||||||||||||||||||||||||||||||||
2615 | |||||||||||||||||||||||||||||||||
2616 | This program is distributed in the hope that it will be useful, | ||||||||||||||||||||||||||||||||
2617 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||||||||||||||||||||||||||||
2618 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either | ||||||||||||||||||||||||||||||||
2619 | the GNU General Public License or the Artistic License for more details. | ||||||||||||||||||||||||||||||||
2620 | |||||||||||||||||||||||||||||||||
2621 | You should have received a copy of the Artistic License with this | ||||||||||||||||||||||||||||||||
2622 | module, in the file ARTISTIC. If not, I'll be glad to provide one. | ||||||||||||||||||||||||||||||||
2623 | |||||||||||||||||||||||||||||||||
2624 | You should have received a copy of the GNU General Public License | ||||||||||||||||||||||||||||||||
2625 | along with this program; if not, write to the Free Software | ||||||||||||||||||||||||||||||||
2626 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||||||||||||||||||||||||||||||||
2627 | USA | ||||||||||||||||||||||||||||||||
2628 | |||||||||||||||||||||||||||||||||
2629 | |||||||||||||||||||||||||||||||||
2630 | =cut | ||||||||||||||||||||||||||||||||
2631 |