| blib/lib/CGI/Application.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 356 | 379 | 93.9 |
| branch | 158 | 184 | 85.8 |
| condition | 17 | 27 | 62.9 |
| subroutine | 41 | 44 | 93.1 |
| pod | 29 | 31 | 93.5 |
| total | 601 | 665 | 90.3 |
| line | stmt | bran | cond | sub | pod | time | code | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | package CGI::Application; | ||||||||||||||||||||||||||||||||
| 2 | 17 | 17 | 837466 | use Carp; | |||||||||||||||||||||||||||||
| 17 | 171 | ||||||||||||||||||||||||||||||||
| 17 | 1078 | ||||||||||||||||||||||||||||||||
| 3 | 17 | 17 | 104 | use strict; | |||||||||||||||||||||||||||||
| 17 | 32 | ||||||||||||||||||||||||||||||||
| 17 | 336 | ||||||||||||||||||||||||||||||||
| 4 | 17 | 17 | 7559 | use Class::ISA; | |||||||||||||||||||||||||||||
| 17 | 28125 | ||||||||||||||||||||||||||||||||
| 17 | 473 | ||||||||||||||||||||||||||||||||
| 5 | 17 | 17 | 107 | use Scalar::Util; | |||||||||||||||||||||||||||||
| 17 | 34 | ||||||||||||||||||||||||||||||||
| 17 | 70672 | ||||||||||||||||||||||||||||||||
| 6 | |||||||||||||||||||||||||||||||||
| 7 | $CGI::Application::VERSION = '4.61'; | ||||||||||||||||||||||||||||||||
| 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 | 85050 | my $class = shift; | ||||||||||||||||||||||||||||
| 25 | |||||||||||||||||||||||||||||||||
| 26 | 69 | 149 | my @args = @_; | ||||||||||||||||||||||||||||||
| 27 | |||||||||||||||||||||||||||||||||
| 28 | 69 | 50 | 205 | if (ref($class)) { | |||||||||||||||||||||||||||||
| 29 | # No copy constructor yet! | ||||||||||||||||||||||||||||||||
| 30 | 0 | 0 | $class = ref($class); | ||||||||||||||||||||||||||||||
| 31 | } | ||||||||||||||||||||||||||||||||
| 32 | |||||||||||||||||||||||||||||||||
| 33 | # Create our object! | ||||||||||||||||||||||||||||||||
| 34 | 69 | 120 | my $self = {}; | ||||||||||||||||||||||||||||||
| 35 | 69 | 146 | 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 | 253 | $self->header_type('header'); | ||||||||||||||||||||||||||||||
| 43 | 69 | 254 | $self->mode_param('rm'); | ||||||||||||||||||||||||||||||
| 44 | 69 | 243 | $self->start_mode('start'); | ||||||||||||||||||||||||||||||
| 45 | |||||||||||||||||||||||||||||||||
| 46 | # Process optional new() parameters | ||||||||||||||||||||||||||||||||
| 47 | 69 | 97 | my $rprops; | ||||||||||||||||||||||||||||||
| 48 | 69 | 100 | 158 | if (ref($args[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
| 49 | 1 | 4 | $rprops = $self->_cap_hash($args[0]); | ||||||||||||||||||||||||||||||
| 50 | } else { | ||||||||||||||||||||||||||||||||
| 51 | 68 | 282 | $rprops = $self->_cap_hash({ @args }); | ||||||||||||||||||||||||||||||
| 52 | } | ||||||||||||||||||||||||||||||||
| 53 | |||||||||||||||||||||||||||||||||
| 54 | # Set tmpl_path() | ||||||||||||||||||||||||||||||||
| 55 | 69 | 100 | 202 | if (exists($rprops->{TMPL_PATH})) { | |||||||||||||||||||||||||||||
| 56 | 4 | 18 | $self->tmpl_path($rprops->{TMPL_PATH}); | ||||||||||||||||||||||||||||||
| 57 | } | ||||||||||||||||||||||||||||||||
| 58 | |||||||||||||||||||||||||||||||||
| 59 | # Set CGI query object | ||||||||||||||||||||||||||||||||
| 60 | 69 | 100 | 163 | if (exists($rprops->{QUERY})) { | |||||||||||||||||||||||||||||
| 61 | 20 | 67 | $self->query($rprops->{QUERY}); | ||||||||||||||||||||||||||||||
| 62 | } | ||||||||||||||||||||||||||||||||
| 63 | |||||||||||||||||||||||||||||||||
| 64 | # Set up init param() values | ||||||||||||||||||||||||||||||||
| 65 | 69 | 100 | 153 | if (exists($rprops->{PARAMS})) { | |||||||||||||||||||||||||||||
| 66 | 2 | 100 | 209 | croak("PARAMS is not a hash ref") unless (ref($rprops->{PARAMS}) eq 'HASH'); | |||||||||||||||||||||||||||||
| 67 | 1 | 3 | my $rparams = $rprops->{PARAMS}; | ||||||||||||||||||||||||||||||
| 68 | 1 | 8 | while (my ($k, $v) = each(%$rparams)) { | ||||||||||||||||||||||||||||||
| 69 | 2 | 12 | $self->param($k, $v); | ||||||||||||||||||||||||||||||
| 70 | } | ||||||||||||||||||||||||||||||||
| 71 | } | ||||||||||||||||||||||||||||||||
| 72 | |||||||||||||||||||||||||||||||||
| 73 | # Lock prerun_mode from being changed until cgiapp_prerun() | ||||||||||||||||||||||||||||||||
| 74 | 68 | 121 | $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 | 259 | $self->call_hook('init', @args); | ||||||||||||||||||||||||||||||
| 80 | |||||||||||||||||||||||||||||||||
| 81 | # Call setup() method, which should be implemented in the sub-class! | ||||||||||||||||||||||||||||||||
| 82 | 68 | 239 | $self->setup(); | ||||||||||||||||||||||||||||||
| 83 | |||||||||||||||||||||||||||||||||
| 84 | 67 | 279 | return $self; | ||||||||||||||||||||||||||||||
| 85 | } | ||||||||||||||||||||||||||||||||
| 86 | |||||||||||||||||||||||||||||||||
| 87 | sub __get_runmode { | ||||||||||||||||||||||||||||||||
| 88 | 61 | 61 | 88 | my $self = shift; | |||||||||||||||||||||||||||||
| 89 | 61 | 109 | my $rm_param = shift; | ||||||||||||||||||||||||||||||
| 90 | |||||||||||||||||||||||||||||||||
| 91 | 61 | 88 | my $rm; | ||||||||||||||||||||||||||||||
| 92 | # Support call-back instead of CGI mode param | ||||||||||||||||||||||||||||||||
| 93 | 61 | 100 | 188 | if (ref($rm_param) eq 'CODE') { | |||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 94 | # Get run mode from subref | ||||||||||||||||||||||||||||||||
| 95 | 4 | 10 | $rm = $rm_param->($self); | ||||||||||||||||||||||||||||||
| 96 | } | ||||||||||||||||||||||||||||||||
| 97 | # support setting run mode from PATH_INFO | ||||||||||||||||||||||||||||||||
| 98 | elsif (ref($rm_param) eq 'HASH') { | ||||||||||||||||||||||||||||||||
| 99 | 4 | 6 | $rm = $rm_param->{run_mode}; | ||||||||||||||||||||||||||||||
| 100 | } | ||||||||||||||||||||||||||||||||
| 101 | # Get run mode from CGI param | ||||||||||||||||||||||||||||||||
| 102 | else { | ||||||||||||||||||||||||||||||||
| 103 | 53 | 116 | $rm = $self->query->param($rm_param); | ||||||||||||||||||||||||||||||
| 104 | } | ||||||||||||||||||||||||||||||||
| 105 | |||||||||||||||||||||||||||||||||
| 106 | # If $rm undefined, use default (start) mode | ||||||||||||||||||||||||||||||||
| 107 | 61 | 100 | 100 | 1259 | $rm = $self->start_mode unless defined($rm) && length($rm); | ||||||||||||||||||||||||||||
| 108 | |||||||||||||||||||||||||||||||||
| 109 | 61 | 117 | return $rm; | ||||||||||||||||||||||||||||||
| 110 | } | ||||||||||||||||||||||||||||||||
| 111 | |||||||||||||||||||||||||||||||||
| 112 | sub __get_runmeth { | ||||||||||||||||||||||||||||||||
| 113 | 61 | 61 | 96 | my $self = shift; | |||||||||||||||||||||||||||||
| 114 | 61 | 92 | my $rm = shift; | ||||||||||||||||||||||||||||||
| 115 | |||||||||||||||||||||||||||||||||
| 116 | 61 | 66 | my $rmeth; | ||||||||||||||||||||||||||||||
| 117 | |||||||||||||||||||||||||||||||||
| 118 | 61 | 84 | my $is_autoload = 0; | ||||||||||||||||||||||||||||||
| 119 | |||||||||||||||||||||||||||||||||
| 120 | 61 | 130 | my %rmodes = ($self->run_modes()); | ||||||||||||||||||||||||||||||
| 121 | 61 | 100 | 196 | if (exists($rmodes{$rm})) { | |||||||||||||||||||||||||||||
| 122 | 58 | 110 | $rmeth = $rmodes{$rm}; | ||||||||||||||||||||||||||||||
| 123 | } | ||||||||||||||||||||||||||||||||
| 124 | else { | ||||||||||||||||||||||||||||||||
| 125 | # Look for run mode "AUTOLOAD" before dieing | ||||||||||||||||||||||||||||||||
| 126 | 3 | 100 | 17 | unless (exists($rmodes{'AUTOLOAD'})) { | |||||||||||||||||||||||||||||
| 127 | 1 | 159 | croak("No such run mode '$rm'"); | ||||||||||||||||||||||||||||||
| 128 | } | ||||||||||||||||||||||||||||||||
| 129 | 2 | 4 | $rmeth = $rmodes{'AUTOLOAD'}; | ||||||||||||||||||||||||||||||
| 130 | 2 | 5 | $is_autoload = 1; | ||||||||||||||||||||||||||||||
| 131 | } | ||||||||||||||||||||||||||||||||
| 132 | |||||||||||||||||||||||||||||||||
| 133 | 60 | 165 | return ($rmeth, $is_autoload); | ||||||||||||||||||||||||||||||
| 134 | } | ||||||||||||||||||||||||||||||||
| 135 | |||||||||||||||||||||||||||||||||
| 136 | sub __get_body { | ||||||||||||||||||||||||||||||||
| 137 | 61 | 61 | 87 | my $self = shift; | |||||||||||||||||||||||||||||
| 138 | 61 | 82 | my $rm = shift; | ||||||||||||||||||||||||||||||
| 139 | |||||||||||||||||||||||||||||||||
| 140 | 61 | 176 | my ($rmeth, $is_autoload) = $self->__get_runmeth($rm); | ||||||||||||||||||||||||||||||
| 141 | |||||||||||||||||||||||||||||||||
| 142 | 60 | 89 | my $body; | ||||||||||||||||||||||||||||||
| 143 | 60 | 77 | eval { | ||||||||||||||||||||||||||||||
| 144 | 60 | 100 | 231 | $body = $is_autoload ? $self->$rmeth($rm) : $self->$rmeth(); | |||||||||||||||||||||||||||||
| 145 | }; | ||||||||||||||||||||||||||||||||
| 146 | 60 | 100 | 878 | if ($@) { | |||||||||||||||||||||||||||||
| 147 | 3 | 7 | my $error = $@; | ||||||||||||||||||||||||||||||
| 148 | 3 | 11 | $self->call_hook('error', $error); | ||||||||||||||||||||||||||||||
| 149 | 3 | 100 | 18 | if (my $em = $self->error_mode) { | |||||||||||||||||||||||||||||
| 150 | 2 | 6 | $body = $self->$em( $error ); | ||||||||||||||||||||||||||||||
| 151 | } else { | ||||||||||||||||||||||||||||||||
| 152 | 1 | 89 | 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 | 211 | return defined $body ? $body : ''; | |||||||||||||||||||||||||||||
| 159 | } | ||||||||||||||||||||||||||||||||
| 160 | |||||||||||||||||||||||||||||||||
| 161 | |||||||||||||||||||||||||||||||||
| 162 | sub run { | ||||||||||||||||||||||||||||||||
| 163 | 61 | 61 | 1 | 823 | my $self = shift; | ||||||||||||||||||||||||||||
| 164 | 61 | 157 | my $q = $self->query(); | ||||||||||||||||||||||||||||||
| 165 | |||||||||||||||||||||||||||||||||
| 166 | 61 | 179 | my $rm_param = $self->mode_param(); | ||||||||||||||||||||||||||||||
| 167 | |||||||||||||||||||||||||||||||||
| 168 | 61 | 224 | my $rm = $self->__get_runmode($rm_param); | ||||||||||||||||||||||||||||||
| 169 | |||||||||||||||||||||||||||||||||
| 170 | # Set get_current_runmode() for access by user later | ||||||||||||||||||||||||||||||||
| 171 | 61 | 135 | $self->{__CURRENT_RUNMODE} = $rm; | ||||||||||||||||||||||||||||||
| 172 | |||||||||||||||||||||||||||||||||
| 173 | # Allow prerun_mode to be changed | ||||||||||||||||||||||||||||||||
| 174 | 61 | 119 | 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 | 169 | $self->call_hook('prerun', $rm); | ||||||||||||||||||||||||||||||
| 180 | |||||||||||||||||||||||||||||||||
| 181 | # Lock prerun_mode from being changed after cgiapp_prerun() | ||||||||||||||||||||||||||||||||
| 182 | 61 | 128 | $self->{__PRERUN_MODE_LOCKED} = 1; | ||||||||||||||||||||||||||||||
| 183 | |||||||||||||||||||||||||||||||||
| 184 | # If prerun_mode has been set, use it! | ||||||||||||||||||||||||||||||||
| 185 | 61 | 193 | my $prerun_mode = $self->prerun_mode(); | ||||||||||||||||||||||||||||||
| 186 | 61 | 100 | 137 | if (length($prerun_mode)) { | |||||||||||||||||||||||||||||
| 187 | 1 | 3 | $rm = $prerun_mode; | ||||||||||||||||||||||||||||||
| 188 | 1 | 3 | $self->{__CURRENT_RUNMODE} = $rm; | ||||||||||||||||||||||||||||||
| 189 | } | ||||||||||||||||||||||||||||||||
| 190 | |||||||||||||||||||||||||||||||||
| 191 | # Process run mode! | ||||||||||||||||||||||||||||||||
| 192 | 61 | 178 | my $body = $self->__get_body($rm); | ||||||||||||||||||||||||||||||
| 193 | |||||||||||||||||||||||||||||||||
| 194 | # Support scalar-ref for body return | ||||||||||||||||||||||||||||||||
| 195 | 58 | 100 | 154 | $body = $$body if ref $body eq 'SCALAR'; | |||||||||||||||||||||||||||||
| 196 | |||||||||||||||||||||||||||||||||
| 197 | # Call cgiapp_postrun() hook | ||||||||||||||||||||||||||||||||
| 198 | 58 | 182 | $self->call_hook('postrun', \$body); | ||||||||||||||||||||||||||||||
| 199 | |||||||||||||||||||||||||||||||||
| 200 | 58 | 94 | my $return_value; | ||||||||||||||||||||||||||||||
| 201 | 58 | 100 | 129 | if ($self->{__IS_PSGI}) { | |||||||||||||||||||||||||||||
| 202 | 1 | 12 | my ($status, $headers) = $self->_send_psgi_headers(); | ||||||||||||||||||||||||||||||
| 203 | |||||||||||||||||||||||||||||||||
| 204 | 1 | 50 | 33 | 97 | 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 | 185 | my $headers = $self->_send_headers(); | ||||||||||||||||||||||||||||||
| 227 | |||||||||||||||||||||||||||||||||
| 228 | # Build up total output | ||||||||||||||||||||||||||||||||
| 229 | 57 | 12738 | $return_value = $headers.$body; | ||||||||||||||||||||||||||||||
| 230 | 57 | 100 | 198 | print $return_value unless $ENV{CGI_APP_RETURN_ONLY}; | |||||||||||||||||||||||||||||
| 231 | } | ||||||||||||||||||||||||||||||||
| 232 | |||||||||||||||||||||||||||||||||
| 233 | # clean up operations | ||||||||||||||||||||||||||||||||
| 234 | 58 | 162 | $self->call_hook('teardown'); | ||||||||||||||||||||||||||||||
| 235 | |||||||||||||||||||||||||||||||||
| 236 | 58 | 212 | 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 | # PR from alter https://github.com/markstos/CGI--Application/pull/17 | ||||||||||||||||||||||||||||||||
| 248 | #if (not defined $args_to_new->{QUERY}) { | ||||||||||||||||||||||||||||||||
| 249 | 0 | 0 | require CGI::PSGI; | ||||||||||||||||||||||||||||||
| 250 | 0 | 0 | $args_to_new->{QUERY} = CGI::PSGI->new($env); | ||||||||||||||||||||||||||||||
| 251 | #} | ||||||||||||||||||||||||||||||||
| 252 | |||||||||||||||||||||||||||||||||
| 253 | 0 | 0 | my $webapp = $class->new($args_to_new); | ||||||||||||||||||||||||||||||
| 254 | 0 | 0 | return $webapp->run_as_psgi; | ||||||||||||||||||||||||||||||
| 255 | } | ||||||||||||||||||||||||||||||||
| 256 | 0 | 0 | } | ||||||||||||||||||||||||||||||
| 257 | |||||||||||||||||||||||||||||||||
| 258 | sub run_as_psgi { | ||||||||||||||||||||||||||||||||
| 259 | 1 | 1 | 1 | 8 | my $self = shift; | ||||||||||||||||||||||||||||
| 260 | 1 | 2 | $self->{__IS_PSGI} = 1; | ||||||||||||||||||||||||||||||
| 261 | |||||||||||||||||||||||||||||||||
| 262 | # Run doesn't officially support any args, but pass them through in case some sub-class uses them. | ||||||||||||||||||||||||||||||||
| 263 | 1 | 7 | return $self->run(@_); | ||||||||||||||||||||||||||||||
| 264 | } | ||||||||||||||||||||||||||||||||
| 265 | |||||||||||||||||||||||||||||||||
| 266 | |||||||||||||||||||||||||||||||||
| 267 | ############################ | ||||||||||||||||||||||||||||||||
| 268 | #### OVERRIDE METHODS #### | ||||||||||||||||||||||||||||||||
| 269 | ############################ | ||||||||||||||||||||||||||||||||
| 270 | |||||||||||||||||||||||||||||||||
| 271 | sub cgiapp_get_query { | ||||||||||||||||||||||||||||||||
| 272 | 14 | 14 | 1 | 27 | my $self = shift; | ||||||||||||||||||||||||||||
| 273 | |||||||||||||||||||||||||||||||||
| 274 | # Include CGI.pm and related modules | ||||||||||||||||||||||||||||||||
| 275 | 14 | 4660 | require CGI; | ||||||||||||||||||||||||||||||
| 276 | |||||||||||||||||||||||||||||||||
| 277 | # Get the query object | ||||||||||||||||||||||||||||||||
| 278 | 14 | 157134 | my $q = CGI->new(); | ||||||||||||||||||||||||||||||
| 279 | |||||||||||||||||||||||||||||||||
| 280 | 14 | 3620 | return $q; | ||||||||||||||||||||||||||||||
| 281 | } | ||||||||||||||||||||||||||||||||
| 282 | |||||||||||||||||||||||||||||||||
| 283 | |||||||||||||||||||||||||||||||||
| 284 | sub cgiapp_init { | ||||||||||||||||||||||||||||||||
| 285 | 45 | 45 | 1 | 86 | my $self = shift; | ||||||||||||||||||||||||||||
| 286 | 45 | 128 | my @args = (@_); | ||||||||||||||||||||||||||||||
| 287 | |||||||||||||||||||||||||||||||||
| 288 | # Nothing to init, yet! | ||||||||||||||||||||||||||||||||
| 289 | } | ||||||||||||||||||||||||||||||||
| 290 | |||||||||||||||||||||||||||||||||
| 291 | |||||||||||||||||||||||||||||||||
| 292 | sub cgiapp_prerun { | ||||||||||||||||||||||||||||||||
| 293 | 53 | 53 | 1 | 78 | my $self = shift; | ||||||||||||||||||||||||||||
| 294 | 53 | 100 | my $rm = shift; | ||||||||||||||||||||||||||||||
| 295 | |||||||||||||||||||||||||||||||||
| 296 | # Nothing to prerun, yet! | ||||||||||||||||||||||||||||||||
| 297 | } | ||||||||||||||||||||||||||||||||
| 298 | |||||||||||||||||||||||||||||||||
| 299 | |||||||||||||||||||||||||||||||||
| 300 | sub cgiapp_postrun { | ||||||||||||||||||||||||||||||||
| 301 | 51 | 51 | 1 | 75 | my $self = shift; | ||||||||||||||||||||||||||||
| 302 | 51 | 89 | my $bodyref = shift; | ||||||||||||||||||||||||||||||
| 303 | |||||||||||||||||||||||||||||||||
| 304 | # Nothing to postrun, yet! | ||||||||||||||||||||||||||||||||
| 305 | } | ||||||||||||||||||||||||||||||||
| 306 | |||||||||||||||||||||||||||||||||
| 307 | |||||||||||||||||||||||||||||||||
| 308 | sub setup { | ||||||||||||||||||||||||||||||||
| 309 | 11 | 11 | 1 | 17 | my $self = shift; | ||||||||||||||||||||||||||||
| 310 | } | ||||||||||||||||||||||||||||||||
| 311 | |||||||||||||||||||||||||||||||||
| 312 | |||||||||||||||||||||||||||||||||
| 313 | sub teardown { | ||||||||||||||||||||||||||||||||
| 314 | 39 | 39 | 1 | 113 | my $self = shift; | ||||||||||||||||||||||||||||
| 315 | |||||||||||||||||||||||||||||||||
| 316 | # Nothing to shut down, yet! | ||||||||||||||||||||||||||||||||
| 317 | } | ||||||||||||||||||||||||||||||||
| 318 | |||||||||||||||||||||||||||||||||
| 319 | |||||||||||||||||||||||||||||||||
| 320 | |||||||||||||||||||||||||||||||||
| 321 | |||||||||||||||||||||||||||||||||
| 322 | ###################################### | ||||||||||||||||||||||||||||||||
| 323 | #### APPLICATION MODULE METHODS #### | ||||||||||||||||||||||||||||||||
| 324 | ###################################### | ||||||||||||||||||||||||||||||||
| 325 | |||||||||||||||||||||||||||||||||
| 326 | sub dump { | ||||||||||||||||||||||||||||||||
| 327 | 2 | 2 | 1 | 5 | my $self = shift; | ||||||||||||||||||||||||||||
| 328 | 2 | 4 | my $output = ''; | ||||||||||||||||||||||||||||||
| 329 | |||||||||||||||||||||||||||||||||
| 330 | # Dump run mode | ||||||||||||||||||||||||||||||||
| 331 | 2 | 4 | my $current_runmode = $self->get_current_runmode(); | ||||||||||||||||||||||||||||||
| 332 | 2 | 100 | 6 | $current_runmode = "" unless (defined($current_runmode)); | |||||||||||||||||||||||||||||
| 333 | 2 | 7 | $output .= "Current Run mode: '$current_runmode'\n"; | ||||||||||||||||||||||||||||||
| 334 | |||||||||||||||||||||||||||||||||
| 335 | # Dump Params | ||||||||||||||||||||||||||||||||
| 336 | # updated ->param to ->multi_param to silence CGI.pm warning | ||||||||||||||||||||||||||||||||
| 337 | 2 | 4 | $output .= "\nQuery Parameters:\n"; | ||||||||||||||||||||||||||||||
| 338 | 2 | 4 | my @params = $self->query->multi_param(); | ||||||||||||||||||||||||||||||
| 339 | 2 | 38 | foreach my $p (sort(@params)) { | ||||||||||||||||||||||||||||||
| 340 | 1 | 3 | my @data = $self->query->multi_param($p); | ||||||||||||||||||||||||||||||
| 341 | 1 | 53 | my $data_str = "'".join("', '", @data)."'"; | ||||||||||||||||||||||||||||||
| 342 | 1 | 5 | $output .= "\t$p => $data_str\n"; | ||||||||||||||||||||||||||||||
| 343 | } | ||||||||||||||||||||||||||||||||
| 344 | |||||||||||||||||||||||||||||||||
| 345 | # Dump ENV | ||||||||||||||||||||||||||||||||
| 346 | 2 | 5 | $output .= "\nQuery Environment:\n"; | ||||||||||||||||||||||||||||||
| 347 | 2 | 29 | foreach my $ek (sort(keys(%ENV))) { | ||||||||||||||||||||||||||||||
| 348 | 58 | 95 | $output .= "\t$ek => '".$ENV{$ek}."'\n"; | ||||||||||||||||||||||||||||||
| 349 | } | ||||||||||||||||||||||||||||||||
| 350 | |||||||||||||||||||||||||||||||||
| 351 | 2 | 9 | return $output; | ||||||||||||||||||||||||||||||
| 352 | } | ||||||||||||||||||||||||||||||||
| 353 | |||||||||||||||||||||||||||||||||
| 354 | |||||||||||||||||||||||||||||||||
| 355 | sub dump_html { | ||||||||||||||||||||||||||||||||
| 356 | 1 | 1 | 1 | 2 | my $self = shift; | ||||||||||||||||||||||||||||
| 357 | 1 | 3 | my $query = $self->query(); | ||||||||||||||||||||||||||||||
| 358 | 1 | 3 | my $output = ''; | ||||||||||||||||||||||||||||||
| 359 | |||||||||||||||||||||||||||||||||
| 360 | # Dump run-mode | ||||||||||||||||||||||||||||||||
| 361 | 1 | 3 | my $current_runmode = $self->get_current_runmode(); | ||||||||||||||||||||||||||||||
| 362 | 1 | 5 | $output .= " Current Run-mode: |
||||||||||||||||||||||||||||||
| 363 | '$current_runmode'\n"; | ||||||||||||||||||||||||||||||||
| 364 | |||||||||||||||||||||||||||||||||
| 365 | # Dump Params | ||||||||||||||||||||||||||||||||
| 366 | 1 | 2 | $output .= " Query Parameters: \n"; |
||||||||||||||||||||||||||||||
| 367 | 1 | 20 | $output .= $query->Dump; | ||||||||||||||||||||||||||||||
| 368 | |||||||||||||||||||||||||||||||||
| 369 | # Dump ENV | ||||||||||||||||||||||||||||||||
| 370 | 1 | 201 | $output .= " Query Environment: \n
|
||||||||||||||||||||||||||||||
| 371 | 1 | 16 | foreach my $ek ( sort( keys( %ENV ) ) ) { | ||||||||||||||||||||||||||||||
| 372 | $output .= sprintf( | ||||||||||||||||||||||||||||||||
| 373 | " |
||||||||||||||||||||||||||||||||
| 374 | $query->escapeHTML( $ek ), | ||||||||||||||||||||||||||||||||
| 375 | 29 | 2182 | $query->escapeHTML( $ENV{$ek} ) | ||||||||||||||||||||||||||||||
| 376 | ); | ||||||||||||||||||||||||||||||||
| 377 | } | ||||||||||||||||||||||||||||||||
| 378 | 1 | 82 | $output .= "\n"; | ||||||||||||||||||||||||||||||
| 379 | |||||||||||||||||||||||||||||||||
| 380 | 1 | 4 | return $output; | ||||||||||||||||||||||||||||||
| 381 | } | ||||||||||||||||||||||||||||||||
| 382 | |||||||||||||||||||||||||||||||||
| 383 | |||||||||||||||||||||||||||||||||
| 384 | sub no_runmodes { | ||||||||||||||||||||||||||||||||
| 385 | |||||||||||||||||||||||||||||||||
| 386 | 9 | 9 | 0 | 14 | my $self = shift; | ||||||||||||||||||||||||||||
| 387 | 9 | 20 | my $query = $self->query(); | ||||||||||||||||||||||||||||||
| 388 | 9 | 28 | my $output = $query->start_html; | ||||||||||||||||||||||||||||||
| 389 | |||||||||||||||||||||||||||||||||
| 390 | # If no runmodes specified by app return error message | ||||||||||||||||||||||||||||||||
| 391 | 9 | 18346 | my $current_runmode = $self->get_current_runmode(); | ||||||||||||||||||||||||||||||
| 392 | 9 | 26 | my $query_params = $query->Dump; | ||||||||||||||||||||||||||||||
| 393 | |||||||||||||||||||||||||||||||||
| 394 | 9 | 410 | $output .= qq{ | ||||||||||||||||||||||||||||||
| 395 | Error - No runmodes specified. |
||||||||||||||||||||||||||||||||
| 396 | Runmode called: $current_runmode" |
||||||||||||||||||||||||||||||||
| 397 | Query paramaters: $query_params |
||||||||||||||||||||||||||||||||
| 398 | Your application has not specified any runmodes. |
||||||||||||||||||||||||||||||||
| 399 | |||||||||||||||||||||||||||||||||
| 400 | CGI::Application documentation. | ||||||||||||||||||||||||||||||||
| 401 | }; | ||||||||||||||||||||||||||||||||
| 402 | |||||||||||||||||||||||||||||||||
| 403 | 9 | 27 | $output .= $query->end_html(); | ||||||||||||||||||||||||||||||
| 404 | 9 | 39 | return $output; | ||||||||||||||||||||||||||||||
| 405 | } | ||||||||||||||||||||||||||||||||
| 406 | |||||||||||||||||||||||||||||||||
| 407 | |||||||||||||||||||||||||||||||||
| 408 | sub header_add { | ||||||||||||||||||||||||||||||||
| 409 | 5 | 5 | 1 | 488 | my $self = shift; | ||||||||||||||||||||||||||||
| 410 | 5 | 14 | return $self->_header_props_update(\@_,add=>1); | ||||||||||||||||||||||||||||||
| 411 | } | ||||||||||||||||||||||||||||||||
| 412 | |||||||||||||||||||||||||||||||||
| 413 | sub header_props { | ||||||||||||||||||||||||||||||||
| 414 | 67 | 67 | 1 | 48289 | my $self = shift; | ||||||||||||||||||||||||||||
| 415 | 67 | 195 | return $self->_header_props_update(\@_,add=>0); | ||||||||||||||||||||||||||||||
| 416 | } | ||||||||||||||||||||||||||||||||
| 417 | |||||||||||||||||||||||||||||||||
| 418 | # used by header_props and header_add to update the headers | ||||||||||||||||||||||||||||||||
| 419 | sub _header_props_update { | ||||||||||||||||||||||||||||||||
| 420 | 72 | 72 | 144 | my $self = shift; | |||||||||||||||||||||||||||||
| 421 | 72 | 128 | my $data_ref = shift; | ||||||||||||||||||||||||||||||
| 422 | 72 | 184 | my %in = @_; | ||||||||||||||||||||||||||||||
| 423 | |||||||||||||||||||||||||||||||||
| 424 | 72 | 125 | my @data = @$data_ref; | ||||||||||||||||||||||||||||||
| 425 | |||||||||||||||||||||||||||||||||
| 426 | # First use? Create new __HEADER_PROPS! | ||||||||||||||||||||||||||||||||
| 427 | 72 | 100 | 199 | $self->{__HEADER_PROPS} = {} unless (exists($self->{__HEADER_PROPS})); | |||||||||||||||||||||||||||||
| 428 | |||||||||||||||||||||||||||||||||
| 429 | 72 | 117 | my $props; | ||||||||||||||||||||||||||||||
| 430 | |||||||||||||||||||||||||||||||||
| 431 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
| 432 | 72 | 100 | 153 | if (scalar(@data)) { | |||||||||||||||||||||||||||||
| 433 | 19 | 100 | 33 | if ($self->header_type eq 'none') { | |||||||||||||||||||||||||||||
| 434 | 1 | 14 | warn "header_props called while header_type set to 'none', headers will NOT be sent!" | ||||||||||||||||||||||||||||||
| 435 | } | ||||||||||||||||||||||||||||||||
| 436 | # Is it a hash, or hash-ref? | ||||||||||||||||||||||||||||||||
| 437 | 19 | 100 | 64 | if (ref($data[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 438 | # Make a copy | ||||||||||||||||||||||||||||||||
| 439 | 4 | 4 | %$props = %{$data[0]}; | ||||||||||||||||||||||||||||||
| 4 | 12 | ||||||||||||||||||||||||||||||||
| 440 | } elsif ((scalar(@data) % 2) == 0) { | ||||||||||||||||||||||||||||||||
| 441 | # It appears to be a possible hash (even # of elements) | ||||||||||||||||||||||||||||||||
| 442 | 13 | 32 | %$props = @data; | ||||||||||||||||||||||||||||||
| 443 | } else { | ||||||||||||||||||||||||||||||||
| 444 | 2 | 100 | 5 | my $meth = $in{add} ? 'add' : 'props'; | |||||||||||||||||||||||||||||
| 445 | 2 | 251 | croak("Odd number of elements passed to header_$meth(). Not a valid hash") | ||||||||||||||||||||||||||||||
| 446 | } | ||||||||||||||||||||||||||||||||
| 447 | |||||||||||||||||||||||||||||||||
| 448 | # merge in new headers, appending new values passed as array refs | ||||||||||||||||||||||||||||||||
| 449 | 17 | 100 | 37 | if ($in{add}) { | |||||||||||||||||||||||||||||
| 450 | 4 | 13 | for my $key_set_to_aref (grep { ref $props->{$_} eq 'ARRAY'} keys %$props) { | ||||||||||||||||||||||||||||||
| 4 | 13 | ||||||||||||||||||||||||||||||||
| 451 | 2 | 4 | my $existing_val = $self->{__HEADER_PROPS}->{$key_set_to_aref}; | ||||||||||||||||||||||||||||||
| 452 | 2 | 100 | 6 | next unless defined $existing_val; | |||||||||||||||||||||||||||||
| 453 | 1 | 50 | 4 | my @existing_val_array = (ref $existing_val eq 'ARRAY') ? @$existing_val : ($existing_val); | |||||||||||||||||||||||||||||
| 454 | 1 | 2 | $props->{$key_set_to_aref} = [ @existing_val_array, @{ $props->{$key_set_to_aref} } ]; | ||||||||||||||||||||||||||||||
| 1 | 3 | ||||||||||||||||||||||||||||||||
| 455 | } | ||||||||||||||||||||||||||||||||
| 456 | 4 | 7 | $self->{__HEADER_PROPS} = { %{ $self->{__HEADER_PROPS} }, %$props }; | ||||||||||||||||||||||||||||||
| 4 | 13 | ||||||||||||||||||||||||||||||||
| 457 | } | ||||||||||||||||||||||||||||||||
| 458 | # Set new headers, clobbering existing values | ||||||||||||||||||||||||||||||||
| 459 | else { | ||||||||||||||||||||||||||||||||
| 460 | 13 | 27 | $self->{__HEADER_PROPS} = $props; | ||||||||||||||||||||||||||||||
| 461 | } | ||||||||||||||||||||||||||||||||
| 462 | |||||||||||||||||||||||||||||||||
| 463 | } | ||||||||||||||||||||||||||||||||
| 464 | |||||||||||||||||||||||||||||||||
| 465 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
| 466 | 70 | 114 | return (%{ $self->{__HEADER_PROPS}}); | ||||||||||||||||||||||||||||||
| 70 | 336 | ||||||||||||||||||||||||||||||||
| 467 | } | ||||||||||||||||||||||||||||||||
| 468 | |||||||||||||||||||||||||||||||||
| 469 | |||||||||||||||||||||||||||||||||
| 470 | sub header_type { | ||||||||||||||||||||||||||||||||
| 471 | 157 | 157 | 1 | 253 | my $self = shift; | ||||||||||||||||||||||||||||
| 472 | 157 | 250 | my ($header_type) = @_; | ||||||||||||||||||||||||||||||
| 473 | |||||||||||||||||||||||||||||||||
| 474 | 157 | 332 | my @allowed_header_types = qw(header redirect none); | ||||||||||||||||||||||||||||||
| 475 | |||||||||||||||||||||||||||||||||
| 476 | # First use? Create new __HEADER_TYPE! | ||||||||||||||||||||||||||||||||
| 477 | 157 | 100 | 430 | $self->{__HEADER_TYPE} = 'header' unless (exists($self->{__HEADER_TYPE})); | |||||||||||||||||||||||||||||
| 478 | |||||||||||||||||||||||||||||||||
| 479 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
| 480 | 157 | 100 | 310 | if (defined($header_type)) { | |||||||||||||||||||||||||||||
| 481 | 80 | 175 | $header_type = lc($header_type); | ||||||||||||||||||||||||||||||
| 482 | croak("Invalid header_type '$header_type'") | ||||||||||||||||||||||||||||||||
| 483 | 80 | 50 | 155 | unless(grep { $_ eq $header_type } @allowed_header_types); | |||||||||||||||||||||||||||||
| 240 | 529 | ||||||||||||||||||||||||||||||||
| 484 | 80 | 166 | $self->{__HEADER_TYPE} = $header_type; | ||||||||||||||||||||||||||||||
| 485 | } | ||||||||||||||||||||||||||||||||
| 486 | |||||||||||||||||||||||||||||||||
| 487 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
| 488 | 157 | 303 | return $self->{__HEADER_TYPE}; | ||||||||||||||||||||||||||||||
| 489 | } | ||||||||||||||||||||||||||||||||
| 490 | |||||||||||||||||||||||||||||||||
| 491 | |||||||||||||||||||||||||||||||||
| 492 | sub param { | ||||||||||||||||||||||||||||||||
| 493 | 106 | 106 | 1 | 19577 | my $self = shift; | ||||||||||||||||||||||||||||
| 494 | 106 | 225 | my (@data) = (@_); | ||||||||||||||||||||||||||||||
| 495 | |||||||||||||||||||||||||||||||||
| 496 | # First use? Create new __PARAMS! | ||||||||||||||||||||||||||||||||
| 497 | 106 | 100 | 253 | $self->{__PARAMS} = {} unless (exists($self->{__PARAMS})); | |||||||||||||||||||||||||||||
| 498 | |||||||||||||||||||||||||||||||||
| 499 | 106 | 157 | my $rp = $self->{__PARAMS}; | ||||||||||||||||||||||||||||||
| 500 | |||||||||||||||||||||||||||||||||
| 501 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
| 502 | 106 | 100 | 227 | if (scalar(@data)) { | |||||||||||||||||||||||||||||
| 503 | # Is it a hash, or hash-ref? | ||||||||||||||||||||||||||||||||
| 504 | 98 | 100 | 295 | if (ref($data[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 50 | |||||||||||||||||||||||||||||||||
| 505 | # Make a copy, which augments the existing contents (if any) | ||||||||||||||||||||||||||||||||
| 506 | 1 | 4 | %$rp = (%$rp, %{$data[0]}); | ||||||||||||||||||||||||||||||
| 1 | 8 | ||||||||||||||||||||||||||||||||
| 507 | } elsif ((scalar(@data) % 2) == 0) { | ||||||||||||||||||||||||||||||||
| 508 | # It appears to be a possible hash (even # of elements) | ||||||||||||||||||||||||||||||||
| 509 | 62 | 198 | %$rp = (%$rp, @data); | ||||||||||||||||||||||||||||||
| 510 | } elsif (scalar(@data) > 1) { | ||||||||||||||||||||||||||||||||
| 511 | 0 | 0 | croak("Odd number of elements passed to param(). Not a valid hash"); | ||||||||||||||||||||||||||||||
| 512 | } | ||||||||||||||||||||||||||||||||
| 513 | } else { | ||||||||||||||||||||||||||||||||
| 514 | # Return the list of param keys if no param is specified. | ||||||||||||||||||||||||||||||||
| 515 | 8 | 106 | return (keys(%$rp)); | ||||||||||||||||||||||||||||||
| 516 | } | ||||||||||||||||||||||||||||||||
| 517 | |||||||||||||||||||||||||||||||||
| 518 | # If exactly one parameter was sent to param(), return the value | ||||||||||||||||||||||||||||||||
| 519 | 98 | 100 | 224 | if (scalar(@data) <= 2) { | |||||||||||||||||||||||||||||
| 520 | 96 | 148 | my $param = $data[0]; | ||||||||||||||||||||||||||||||
| 521 | 96 | 323 | return $rp->{$param}; | ||||||||||||||||||||||||||||||
| 522 | } | ||||||||||||||||||||||||||||||||
| 523 | 2 | 6 | return; # Otherwise, return undef | ||||||||||||||||||||||||||||||
| 524 | } | ||||||||||||||||||||||||||||||||
| 525 | |||||||||||||||||||||||||||||||||
| 526 | |||||||||||||||||||||||||||||||||
| 527 | sub delete { | ||||||||||||||||||||||||||||||||
| 528 | 3 | 3 | 1 | 12 | my $self = shift; | ||||||||||||||||||||||||||||
| 529 | 3 | 6 | my ($param) = @_; | ||||||||||||||||||||||||||||||
| 530 | |||||||||||||||||||||||||||||||||
| 531 | # return undef it the param name isn't given | ||||||||||||||||||||||||||||||||
| 532 | 3 | 100 | 10 | return undef unless defined $param; | |||||||||||||||||||||||||||||
| 533 | |||||||||||||||||||||||||||||||||
| 534 | #simply delete this param from $self->{__PARAMS} | ||||||||||||||||||||||||||||||||
| 535 | 2 | 7 | delete $self->{__PARAMS}->{$param}; | ||||||||||||||||||||||||||||||
| 536 | } | ||||||||||||||||||||||||||||||||
| 537 | |||||||||||||||||||||||||||||||||
| 538 | |||||||||||||||||||||||||||||||||
| 539 | sub query { | ||||||||||||||||||||||||||||||||
| 540 | 247 | 247 | 1 | 8431 | my $self = shift; | ||||||||||||||||||||||||||||
| 541 | 247 | 390 | my ($query) = @_; | ||||||||||||||||||||||||||||||
| 542 | |||||||||||||||||||||||||||||||||
| 543 | # If data is provided, set it! Otherwise, create a new one. | ||||||||||||||||||||||||||||||||
| 544 | 247 | 100 | 381 | if (defined($query)) { | |||||||||||||||||||||||||||||
| 545 | 44 | 98 | $self->{__QUERY_OBJ} = $query; | ||||||||||||||||||||||||||||||
| 546 | } else { | ||||||||||||||||||||||||||||||||
| 547 | # We're only allowed to create a new query object if one does not yet exist! | ||||||||||||||||||||||||||||||||
| 548 | 203 | 100 | 402 | unless (exists($self->{__QUERY_OBJ})) { | |||||||||||||||||||||||||||||
| 549 | 15 | 71 | $self->{__QUERY_OBJ} = $self->cgiapp_get_query(); | ||||||||||||||||||||||||||||||
| 550 | } | ||||||||||||||||||||||||||||||||
| 551 | } | ||||||||||||||||||||||||||||||||
| 552 | |||||||||||||||||||||||||||||||||
| 553 | 247 | 28195 | return $self->{__QUERY_OBJ}; | ||||||||||||||||||||||||||||||
| 554 | } | ||||||||||||||||||||||||||||||||
| 555 | |||||||||||||||||||||||||||||||||
| 556 | |||||||||||||||||||||||||||||||||
| 557 | sub run_modes { | ||||||||||||||||||||||||||||||||
| 558 | 131 | 131 | 1 | 419 | my $self = shift; | ||||||||||||||||||||||||||||
| 559 | 131 | 241 | my (@data) = (@_); | ||||||||||||||||||||||||||||||
| 560 | |||||||||||||||||||||||||||||||||
| 561 | # First use? Create new __RUN_MODES! | ||||||||||||||||||||||||||||||||
| 562 | 131 | 100 | 389 | $self->{__RUN_MODES} = { 'start' => 'no_runmodes' } unless (exists($self->{__RUN_MODES})); | |||||||||||||||||||||||||||||
| 563 | |||||||||||||||||||||||||||||||||
| 564 | 131 | 213 | my $rr_m = $self->{__RUN_MODES}; | ||||||||||||||||||||||||||||||
| 565 | |||||||||||||||||||||||||||||||||
| 566 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
| 567 | 131 | 100 | 288 | if (scalar(@data)) { | |||||||||||||||||||||||||||||
| 568 | # Is it a hash, hash-ref, or array-ref? | ||||||||||||||||||||||||||||||||
| 569 | 70 | 100 | 267 | if (ref($data[0]) eq 'HASH') { | |||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 570 | # Make a copy, which augments the existing contents (if any) | ||||||||||||||||||||||||||||||||
| 571 | 1 | 4 | %$rr_m = (%$rr_m, %{$data[0]}); | ||||||||||||||||||||||||||||||
| 1 | 4 | ||||||||||||||||||||||||||||||||
| 572 | } elsif (ref($data[0]) eq 'ARRAY') { | ||||||||||||||||||||||||||||||||
| 573 | # Convert array-ref into hash table | ||||||||||||||||||||||||||||||||
| 574 | 12 | 19 | foreach my $rm (@{$data[0]}) { | ||||||||||||||||||||||||||||||
| 12 | 28 | ||||||||||||||||||||||||||||||||
| 575 | 26 | 46 | $rr_m->{$rm} = $rm; | ||||||||||||||||||||||||||||||
| 576 | } | ||||||||||||||||||||||||||||||||
| 577 | } elsif ((scalar(@data) % 2) == 0) { | ||||||||||||||||||||||||||||||||
| 578 | # It appears to be a possible hash (even # of elements) | ||||||||||||||||||||||||||||||||
| 579 | 56 | 283 | %$rr_m = (%$rr_m, @data); | ||||||||||||||||||||||||||||||
| 580 | } else { | ||||||||||||||||||||||||||||||||
| 581 | 1 | 128 | croak("Odd number of elements passed to run_modes(). Not a valid hash"); | ||||||||||||||||||||||||||||||
| 582 | } | ||||||||||||||||||||||||||||||||
| 583 | } | ||||||||||||||||||||||||||||||||
| 584 | |||||||||||||||||||||||||||||||||
| 585 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
| 586 | 130 | 462 | return (%$rr_m); | ||||||||||||||||||||||||||||||
| 587 | } | ||||||||||||||||||||||||||||||||
| 588 | |||||||||||||||||||||||||||||||||
| 589 | |||||||||||||||||||||||||||||||||
| 590 | sub start_mode { | ||||||||||||||||||||||||||||||||
| 591 | 145 | 145 | 1 | 320 | my $self = shift; | ||||||||||||||||||||||||||||
| 592 | 145 | 259 | my ($start_mode) = @_; | ||||||||||||||||||||||||||||||
| 593 | |||||||||||||||||||||||||||||||||
| 594 | # First use? Create new __START_MODE | ||||||||||||||||||||||||||||||||
| 595 | 145 | 100 | 331 | $self->{__START_MODE} = 'start' unless (exists($self->{__START_MODE})); | |||||||||||||||||||||||||||||
| 596 | |||||||||||||||||||||||||||||||||
| 597 | # If data is provided, set it | ||||||||||||||||||||||||||||||||
| 598 | 145 | 100 | 304 | if (defined($start_mode)) { | |||||||||||||||||||||||||||||
| 599 | 119 | 191 | $self->{__START_MODE} = $start_mode; | ||||||||||||||||||||||||||||||
| 600 | } | ||||||||||||||||||||||||||||||||
| 601 | |||||||||||||||||||||||||||||||||
| 602 | 145 | 233 | return $self->{__START_MODE}; | ||||||||||||||||||||||||||||||
| 603 | } | ||||||||||||||||||||||||||||||||
| 604 | |||||||||||||||||||||||||||||||||
| 605 | |||||||||||||||||||||||||||||||||
| 606 | sub error_mode { | ||||||||||||||||||||||||||||||||
| 607 | 5 | 5 | 1 | 27 | my $self = shift; | ||||||||||||||||||||||||||||
| 608 | 5 | 13 | my ($error_mode) = @_; | ||||||||||||||||||||||||||||||
| 609 | |||||||||||||||||||||||||||||||||
| 610 | # First use? Create new __ERROR_MODE | ||||||||||||||||||||||||||||||||
| 611 | 5 | 100 | 17 | $self->{__ERROR_MODE} = undef unless (exists($self->{__ERROR_MODE})); | |||||||||||||||||||||||||||||
| 612 | |||||||||||||||||||||||||||||||||
| 613 | # If data is provided, set it. | ||||||||||||||||||||||||||||||||
| 614 | 5 | 100 | 13 | if (defined($error_mode)) { | |||||||||||||||||||||||||||||
| 615 | 2 | 10 | $self->{__ERROR_MODE} = $error_mode; | ||||||||||||||||||||||||||||||
| 616 | } | ||||||||||||||||||||||||||||||||
| 617 | |||||||||||||||||||||||||||||||||
| 618 | 5 | 85 | return $self->{__ERROR_MODE}; | ||||||||||||||||||||||||||||||
| 619 | } | ||||||||||||||||||||||||||||||||
| 620 | |||||||||||||||||||||||||||||||||
| 621 | |||||||||||||||||||||||||||||||||
| 622 | sub tmpl_path { | ||||||||||||||||||||||||||||||||
| 623 | 13 | 13 | 1 | 32 | my $self = shift; | ||||||||||||||||||||||||||||
| 624 | 13 | 20 | my ($tmpl_path) = @_; | ||||||||||||||||||||||||||||||
| 625 | |||||||||||||||||||||||||||||||||
| 626 | # First use? Create new __TMPL_PATH! | ||||||||||||||||||||||||||||||||
| 627 | 13 | 100 | 32 | $self->{__TMPL_PATH} = '' unless (exists($self->{__TMPL_PATH})); | |||||||||||||||||||||||||||||
| 628 | |||||||||||||||||||||||||||||||||
| 629 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
| 630 | 13 | 100 | 28 | if (defined($tmpl_path)) { | |||||||||||||||||||||||||||||
| 631 | 5 | 9 | $self->{__TMPL_PATH} = $tmpl_path; | ||||||||||||||||||||||||||||||
| 632 | } | ||||||||||||||||||||||||||||||||
| 633 | |||||||||||||||||||||||||||||||||
| 634 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
| 635 | 13 | 30 | return $self->{__TMPL_PATH}; | ||||||||||||||||||||||||||||||
| 636 | } | ||||||||||||||||||||||||||||||||
| 637 | |||||||||||||||||||||||||||||||||
| 638 | |||||||||||||||||||||||||||||||||
| 639 | sub prerun_mode { | ||||||||||||||||||||||||||||||||
| 640 | 64 | 64 | 1 | 108 | my $self = shift; | ||||||||||||||||||||||||||||
| 641 | 64 | 110 | my ($prerun_mode) = @_; | ||||||||||||||||||||||||||||||
| 642 | |||||||||||||||||||||||||||||||||
| 643 | # First use? Create new __PRERUN_MODE | ||||||||||||||||||||||||||||||||
| 644 | 64 | 100 | 187 | $self->{__PRERUN_MODE} = '' unless (exists($self->{__PRERUN_MODE})); | |||||||||||||||||||||||||||||
| 645 | |||||||||||||||||||||||||||||||||
| 646 | # Was data provided? | ||||||||||||||||||||||||||||||||
| 647 | 64 | 100 | 137 | if (defined($prerun_mode)) { | |||||||||||||||||||||||||||||
| 648 | # Are we allowed to set prerun_mode? | ||||||||||||||||||||||||||||||||
| 649 | 3 | 100 | 9 | if (exists($self->{__PRERUN_MODE_LOCKED})) { | |||||||||||||||||||||||||||||
| 650 | # Not allowed! Throw an exception. | ||||||||||||||||||||||||||||||||
| 651 | 2 | 408 | croak("prerun_mode() can only be called within cgiapp_prerun()! Error"); | ||||||||||||||||||||||||||||||
| 652 | } else { | ||||||||||||||||||||||||||||||||
| 653 | # If data is provided, set it! | ||||||||||||||||||||||||||||||||
| 654 | 1 | 4 | $self->{__PRERUN_MODE} = $prerun_mode; | ||||||||||||||||||||||||||||||
| 655 | } | ||||||||||||||||||||||||||||||||
| 656 | } | ||||||||||||||||||||||||||||||||
| 657 | |||||||||||||||||||||||||||||||||
| 658 | # If we've gotten this far, return the value! | ||||||||||||||||||||||||||||||||
| 659 | 62 | 121 | return $self->{__PRERUN_MODE}; | ||||||||||||||||||||||||||||||
| 660 | } | ||||||||||||||||||||||||||||||||
| 661 | |||||||||||||||||||||||||||||||||
| 662 | |||||||||||||||||||||||||||||||||
| 663 | sub get_current_runmode { | ||||||||||||||||||||||||||||||||
| 664 | 22 | 22 | 1 | 1527 | my $self = shift; | ||||||||||||||||||||||||||||
| 665 | |||||||||||||||||||||||||||||||||
| 666 | # It's OK if we return undef if this method is called too early | ||||||||||||||||||||||||||||||||
| 667 | 22 | 57 | return $self->{__CURRENT_RUNMODE}; | ||||||||||||||||||||||||||||||
| 668 | } | ||||||||||||||||||||||||||||||||
| 669 | |||||||||||||||||||||||||||||||||
| 670 | |||||||||||||||||||||||||||||||||
| 671 | |||||||||||||||||||||||||||||||||
| 672 | |||||||||||||||||||||||||||||||||
| 673 | |||||||||||||||||||||||||||||||||
| 674 | ########################### | ||||||||||||||||||||||||||||||||
| 675 | #### PRIVATE METHODS #### | ||||||||||||||||||||||||||||||||
| 676 | ########################### | ||||||||||||||||||||||||||||||||
| 677 | |||||||||||||||||||||||||||||||||
| 678 | |||||||||||||||||||||||||||||||||
| 679 | # return headers as a string | ||||||||||||||||||||||||||||||||
| 680 | sub _send_headers { | ||||||||||||||||||||||||||||||||
| 681 | 57 | 57 | 148 | my $self = shift; | |||||||||||||||||||||||||||||
| 682 | 57 | 147 | my $q = $self->query; | ||||||||||||||||||||||||||||||
| 683 | 57 | 154 | my $type = $self->header_type; | ||||||||||||||||||||||||||||||
| 684 | |||||||||||||||||||||||||||||||||
| 685 | return | ||||||||||||||||||||||||||||||||
| 686 | 57 | 50 | 289 | $type eq 'redirect' ? $q->redirect( $self->header_props ) | |||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 100 | |||||||||||||||||||||||||||||||||
| 687 | : $type eq 'header' ? $q->header ( $self->header_props ) | ||||||||||||||||||||||||||||||||
| 688 | : $type eq 'none' ? '' | ||||||||||||||||||||||||||||||||
| 689 | : croak "Invalid header_type '$type'" | ||||||||||||||||||||||||||||||||
| 690 | } | ||||||||||||||||||||||||||||||||
| 691 | |||||||||||||||||||||||||||||||||
| 692 | # return a 2 element array modeling the first PSGI redirect values: status code and arrayref of header pairs | ||||||||||||||||||||||||||||||||
| 693 | sub _send_psgi_headers { | ||||||||||||||||||||||||||||||||
| 694 | 1 | 1 | 7 | my $self = shift; | |||||||||||||||||||||||||||||
| 695 | 1 | 6 | my $q = $self->query; | ||||||||||||||||||||||||||||||
| 696 | 1 | 2 | my $type = $self->header_type; | ||||||||||||||||||||||||||||||
| 697 | |||||||||||||||||||||||||||||||||
| 698 | return | ||||||||||||||||||||||||||||||||
| 699 | 1 | 0 | 23 | $type eq 'redirect' ? $q->psgi_redirect( $self->header_props ) | |||||||||||||||||||||||||||||
| 50 | |||||||||||||||||||||||||||||||||
| 50 | |||||||||||||||||||||||||||||||||
| 700 | : $type eq 'header' ? $q->psgi_header ( $self->header_props ) | ||||||||||||||||||||||||||||||||
| 701 | : $type eq 'none' ? '' | ||||||||||||||||||||||||||||||||
| 702 | : croak "Invalid header_type '$type'" | ||||||||||||||||||||||||||||||||
| 703 | |||||||||||||||||||||||||||||||||
| 704 | } | ||||||||||||||||||||||||||||||||
| 705 | |||||||||||||||||||||||||||||||||
| 706 | |||||||||||||||||||||||||||||||||
| 707 | # Make all hash keys CAPITAL | ||||||||||||||||||||||||||||||||
| 708 | # although this method is internal, some other extensions | ||||||||||||||||||||||||||||||||
| 709 | # have come to rely on it, so any changes here should be | ||||||||||||||||||||||||||||||||
| 710 | # made with great care or avoided. | ||||||||||||||||||||||||||||||||
| 711 | sub _cap_hash { | ||||||||||||||||||||||||||||||||
| 712 | 69 | 69 | 112 | my $self = shift; | |||||||||||||||||||||||||||||
| 713 | 69 | 93 | my $rhash = shift; | ||||||||||||||||||||||||||||||
| 714 | my %hash = map { | ||||||||||||||||||||||||||||||||
| 715 | 26 | 52 | my $k = $_; | ||||||||||||||||||||||||||||||
| 716 | 26 | 46 | my $v = $rhash->{$k}; | ||||||||||||||||||||||||||||||
| 717 | 26 | 59 | $k =~ tr/a-z/A-Z/; | ||||||||||||||||||||||||||||||
| 718 | 26 | 89 | $k => $v; | ||||||||||||||||||||||||||||||
| 719 | 69 | 89 | } keys(%{$rhash}); | ||||||||||||||||||||||||||||||
| 69 | 184 | ||||||||||||||||||||||||||||||||
| 720 | 69 | 164 | return \%hash; | ||||||||||||||||||||||||||||||
| 721 | } | ||||||||||||||||||||||||||||||||
| 722 | |||||||||||||||||||||||||||||||||
| 723 | |||||||||||||||||||||||||||||||||
| 724 | |||||||||||||||||||||||||||||||||
| 725 | 1; | ||||||||||||||||||||||||||||||||
| 726 | |||||||||||||||||||||||||||||||||
| 727 | |||||||||||||||||||||||||||||||||
| 728 | |||||||||||||||||||||||||||||||||
| 729 | |||||||||||||||||||||||||||||||||
| 730 | =pod | ||||||||||||||||||||||||||||||||
| 731 | |||||||||||||||||||||||||||||||||
| 732 | =head1 NAME | ||||||||||||||||||||||||||||||||
| 733 | |||||||||||||||||||||||||||||||||
| 734 | CGI::Application - Framework for building reusable web-applications | ||||||||||||||||||||||||||||||||
| 735 | |||||||||||||||||||||||||||||||||
| 736 | =head1 SYNOPSIS | ||||||||||||||||||||||||||||||||
| 737 | |||||||||||||||||||||||||||||||||
| 738 | # In "WebApp.pm"... | ||||||||||||||||||||||||||||||||
| 739 | package WebApp; | ||||||||||||||||||||||||||||||||
| 740 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
| 741 | |||||||||||||||||||||||||||||||||
| 742 | # ( setup() can even be skipped for common cases. See docs below. ) | ||||||||||||||||||||||||||||||||
| 743 | sub setup { | ||||||||||||||||||||||||||||||||
| 744 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 745 | $self->start_mode('mode1'); | ||||||||||||||||||||||||||||||||
| 746 | $self->mode_param('rm'); | ||||||||||||||||||||||||||||||||
| 747 | $self->run_modes( | ||||||||||||||||||||||||||||||||
| 748 | 'mode1' => 'do_stuff', | ||||||||||||||||||||||||||||||||
| 749 | 'mode2' => 'do_more_stuff', | ||||||||||||||||||||||||||||||||
| 750 | 'mode3' => 'do_something_else' | ||||||||||||||||||||||||||||||||
| 751 | ); | ||||||||||||||||||||||||||||||||
| 752 | } | ||||||||||||||||||||||||||||||||
| 753 | sub do_stuff { ... } | ||||||||||||||||||||||||||||||||
| 754 | sub do_more_stuff { ... } | ||||||||||||||||||||||||||||||||
| 755 | sub do_something_else { ... } | ||||||||||||||||||||||||||||||||
| 756 | 1; | ||||||||||||||||||||||||||||||||
| 757 | |||||||||||||||||||||||||||||||||
| 758 | |||||||||||||||||||||||||||||||||
| 759 | ### In "webapp.cgi"... | ||||||||||||||||||||||||||||||||
| 760 | use WebApp; | ||||||||||||||||||||||||||||||||
| 761 | my $webapp = WebApp->new(); | ||||||||||||||||||||||||||||||||
| 762 | $webapp->run(); | ||||||||||||||||||||||||||||||||
| 763 | |||||||||||||||||||||||||||||||||
| 764 | ### Or, in a PSGI file, webapp.psgi | ||||||||||||||||||||||||||||||||
| 765 | use WebApp; | ||||||||||||||||||||||||||||||||
| 766 | WebApp->psgi_app(); | ||||||||||||||||||||||||||||||||
| 767 | |||||||||||||||||||||||||||||||||
| 768 | =head1 INTRODUCTION | ||||||||||||||||||||||||||||||||
| 769 | |||||||||||||||||||||||||||||||||
| 770 | CGI::Application makes it easier to create sophisticated, high-performance, | ||||||||||||||||||||||||||||||||
| 771 | reusable web-based applications. CGI::Application helps makes your web | ||||||||||||||||||||||||||||||||
| 772 | applications easier to design, write, and evolve. | ||||||||||||||||||||||||||||||||
| 773 | |||||||||||||||||||||||||||||||||
| 774 | CGI::Application judiciously avoids employing technologies and techniques which | ||||||||||||||||||||||||||||||||
| 775 | would bind a developer to any one set of tools, operating system or web server. | ||||||||||||||||||||||||||||||||
| 776 | |||||||||||||||||||||||||||||||||
| 777 | It is lightweight in terms of memory usage, making it suitable for common CGI | ||||||||||||||||||||||||||||||||
| 778 | environments, and a high performance choice in persistent environments like | ||||||||||||||||||||||||||||||||
| 779 | FastCGI or mod_perl. | ||||||||||||||||||||||||||||||||
| 780 | |||||||||||||||||||||||||||||||||
| 781 | By adding L |
||||||||||||||||||||||||||||||||
| 782 | features when you need them. | ||||||||||||||||||||||||||||||||
| 783 | |||||||||||||||||||||||||||||||||
| 784 | First released in 2000 and used and expanded by a number of professional | ||||||||||||||||||||||||||||||||
| 785 | website developers, CGI::Application is a stable, reliable choice. | ||||||||||||||||||||||||||||||||
| 786 | |||||||||||||||||||||||||||||||||
| 787 | =head1 USAGE EXAMPLE | ||||||||||||||||||||||||||||||||
| 788 | |||||||||||||||||||||||||||||||||
| 789 | Imagine you have to write an application to search through a database | ||||||||||||||||||||||||||||||||
| 790 | of widgets. Your application has three screens: | ||||||||||||||||||||||||||||||||
| 791 | |||||||||||||||||||||||||||||||||
| 792 | 1. Search form | ||||||||||||||||||||||||||||||||
| 793 | 2. List of results | ||||||||||||||||||||||||||||||||
| 794 | 3. Detail of a single record | ||||||||||||||||||||||||||||||||
| 795 | |||||||||||||||||||||||||||||||||
| 796 | To write this application using CGI::Application you will create two files: | ||||||||||||||||||||||||||||||||
| 797 | |||||||||||||||||||||||||||||||||
| 798 | 1. WidgetView.pm -- Your "Application Module" | ||||||||||||||||||||||||||||||||
| 799 | 2. widgetview.cgi -- Your "Instance Script" | ||||||||||||||||||||||||||||||||
| 800 | |||||||||||||||||||||||||||||||||
| 801 | The Application Module contains all the code specific to your | ||||||||||||||||||||||||||||||||
| 802 | application functionality, and it exists outside of your web server's | ||||||||||||||||||||||||||||||||
| 803 | document root, somewhere in the Perl library search path. | ||||||||||||||||||||||||||||||||
| 804 | |||||||||||||||||||||||||||||||||
| 805 | The Instance Script is what is actually called by your web server. It is | ||||||||||||||||||||||||||||||||
| 806 | a very small, simple file which simply creates an instance of your | ||||||||||||||||||||||||||||||||
| 807 | application and calls an inherited method, run(). Following is the | ||||||||||||||||||||||||||||||||
| 808 | entirety of "widgetview.cgi": | ||||||||||||||||||||||||||||||||
| 809 | |||||||||||||||||||||||||||||||||
| 810 | #!/usr/bin/perl -w | ||||||||||||||||||||||||||||||||
| 811 | use WidgetView; | ||||||||||||||||||||||||||||||||
| 812 | my $webapp = WidgetView->new(); | ||||||||||||||||||||||||||||||||
| 813 | $webapp->run(); | ||||||||||||||||||||||||||||||||
| 814 | |||||||||||||||||||||||||||||||||
| 815 | As you can see, widgetview.cgi simply "uses" your Application module | ||||||||||||||||||||||||||||||||
| 816 | (which implements a Perl package called "WidgetView"). Your Application Module, | ||||||||||||||||||||||||||||||||
| 817 | "WidgetView.pm", is somewhat more lengthy: | ||||||||||||||||||||||||||||||||
| 818 | |||||||||||||||||||||||||||||||||
| 819 | package WidgetView; | ||||||||||||||||||||||||||||||||
| 820 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
| 821 | use strict; | ||||||||||||||||||||||||||||||||
| 822 | |||||||||||||||||||||||||||||||||
| 823 | # Needed for our database connection | ||||||||||||||||||||||||||||||||
| 824 | use CGI::Application::Plugin::DBH; | ||||||||||||||||||||||||||||||||
| 825 | |||||||||||||||||||||||||||||||||
| 826 | sub setup { | ||||||||||||||||||||||||||||||||
| 827 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 828 | $self->start_mode('mode1'); | ||||||||||||||||||||||||||||||||
| 829 | $self->run_modes( | ||||||||||||||||||||||||||||||||
| 830 | 'mode1' => 'showform', | ||||||||||||||||||||||||||||||||
| 831 | 'mode2' => 'showlist', | ||||||||||||||||||||||||||||||||
| 832 | 'mode3' => 'showdetail' | ||||||||||||||||||||||||||||||||
| 833 | ); | ||||||||||||||||||||||||||||||||
| 834 | |||||||||||||||||||||||||||||||||
| 835 | # Connect to DBI database, with the same args as DBI->connect(); | ||||||||||||||||||||||||||||||||
| 836 | $self->dbh_config(); | ||||||||||||||||||||||||||||||||
| 837 | } | ||||||||||||||||||||||||||||||||
| 838 | |||||||||||||||||||||||||||||||||
| 839 | sub teardown { | ||||||||||||||||||||||||||||||||
| 840 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 841 | |||||||||||||||||||||||||||||||||
| 842 | # Disconnect when we're done, (Although DBI usually does this automatically) | ||||||||||||||||||||||||||||||||
| 843 | $self->dbh->disconnect(); | ||||||||||||||||||||||||||||||||
| 844 | } | ||||||||||||||||||||||||||||||||
| 845 | |||||||||||||||||||||||||||||||||
| 846 | sub showform { | ||||||||||||||||||||||||||||||||
| 847 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 848 | |||||||||||||||||||||||||||||||||
| 849 | # Get CGI query object | ||||||||||||||||||||||||||||||||
| 850 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
| 851 | |||||||||||||||||||||||||||||||||
| 852 | my $output = ''; | ||||||||||||||||||||||||||||||||
| 853 | $output .= $q->start_html(-title => 'Widget Search Form'); | ||||||||||||||||||||||||||||||||
| 854 | $output .= $q->start_form(); | ||||||||||||||||||||||||||||||||
| 855 | $output .= $q->textfield(-name => 'widgetcode'); | ||||||||||||||||||||||||||||||||
| 856 | $output .= $q->hidden(-name => 'rm', -value => 'mode2'); | ||||||||||||||||||||||||||||||||
| 857 | $output .= $q->submit(); | ||||||||||||||||||||||||||||||||
| 858 | $output .= $q->end_form(); | ||||||||||||||||||||||||||||||||
| 859 | $output .= $q->end_html(); | ||||||||||||||||||||||||||||||||
| 860 | |||||||||||||||||||||||||||||||||
| 861 | return $output; | ||||||||||||||||||||||||||||||||
| 862 | } | ||||||||||||||||||||||||||||||||
| 863 | |||||||||||||||||||||||||||||||||
| 864 | sub showlist { | ||||||||||||||||||||||||||||||||
| 865 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 866 | |||||||||||||||||||||||||||||||||
| 867 | # Get our database connection | ||||||||||||||||||||||||||||||||
| 868 | my $dbh = $self->dbh(); | ||||||||||||||||||||||||||||||||
| 869 | |||||||||||||||||||||||||||||||||
| 870 | # Get CGI query object | ||||||||||||||||||||||||||||||||
| 871 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
| 872 | my $widgetcode = $q->param("widgetcode"); | ||||||||||||||||||||||||||||||||
| 873 | |||||||||||||||||||||||||||||||||
| 874 | my $output = ''; | ||||||||||||||||||||||||||||||||
| 875 | $output .= $q->start_html(-title => 'List of Matching Widgets'); | ||||||||||||||||||||||||||||||||
| 876 | |||||||||||||||||||||||||||||||||
| 877 | ## Do a bunch of stuff to select "widgets" from a DBI-connected | ||||||||||||||||||||||||||||||||
| 878 | ## database which match the user-supplied value of "widgetcode" | ||||||||||||||||||||||||||||||||
| 879 | ## which has been supplied from the previous HTML form via a | ||||||||||||||||||||||||||||||||
| 880 | ## CGI.pm query object. | ||||||||||||||||||||||||||||||||
| 881 | ## | ||||||||||||||||||||||||||||||||
| 882 | ## Each row will contain a link to a "Widget Detail" which | ||||||||||||||||||||||||||||||||
| 883 | ## provides an anchor tag, as follows: | ||||||||||||||||||||||||||||||||
| 884 | ## | ||||||||||||||||||||||||||||||||
| 885 | ## "widgetview.cgi?rm=mode3&widgetid=XXX" | ||||||||||||||||||||||||||||||||
| 886 | ## | ||||||||||||||||||||||||||||||||
| 887 | ## ...Where "XXX" is a unique value referencing the ID of | ||||||||||||||||||||||||||||||||
| 888 | ## the particular "widget" upon which the user has clicked. | ||||||||||||||||||||||||||||||||
| 889 | |||||||||||||||||||||||||||||||||
| 890 | $output .= $q->end_html(); | ||||||||||||||||||||||||||||||||
| 891 | |||||||||||||||||||||||||||||||||
| 892 | return $output; | ||||||||||||||||||||||||||||||||
| 893 | } | ||||||||||||||||||||||||||||||||
| 894 | |||||||||||||||||||||||||||||||||
| 895 | sub showdetail { | ||||||||||||||||||||||||||||||||
| 896 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 897 | |||||||||||||||||||||||||||||||||
| 898 | # Get our database connection | ||||||||||||||||||||||||||||||||
| 899 | my $dbh = $self->dbh(); | ||||||||||||||||||||||||||||||||
| 900 | |||||||||||||||||||||||||||||||||
| 901 | # Get CGI query object | ||||||||||||||||||||||||||||||||
| 902 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
| 903 | my $widgetid = $q->param("widgetid"); | ||||||||||||||||||||||||||||||||
| 904 | |||||||||||||||||||||||||||||||||
| 905 | my $output = ''; | ||||||||||||||||||||||||||||||||
| 906 | $output .= $q->start_html(-title => 'Widget Detail'); | ||||||||||||||||||||||||||||||||
| 907 | |||||||||||||||||||||||||||||||||
| 908 | ## Do a bunch of things to select all the properties of | ||||||||||||||||||||||||||||||||
| 909 | ## the particular "widget" upon which the user has | ||||||||||||||||||||||||||||||||
| 910 | ## clicked. The key id value of this widget is provided | ||||||||||||||||||||||||||||||||
| 911 | ## via the "widgetid" property, accessed via the CGI.pm | ||||||||||||||||||||||||||||||||
| 912 | ## query object. | ||||||||||||||||||||||||||||||||
| 913 | |||||||||||||||||||||||||||||||||
| 914 | $output .= $q->end_html(); | ||||||||||||||||||||||||||||||||
| 915 | |||||||||||||||||||||||||||||||||
| 916 | return $output; | ||||||||||||||||||||||||||||||||
| 917 | } | ||||||||||||||||||||||||||||||||
| 918 | |||||||||||||||||||||||||||||||||
| 919 | 1; # Perl requires this at the end of all modules | ||||||||||||||||||||||||||||||||
| 920 | |||||||||||||||||||||||||||||||||
| 921 | |||||||||||||||||||||||||||||||||
| 922 | CGI::Application takes care of implementing the new() and the run() | ||||||||||||||||||||||||||||||||
| 923 | methods. Notice that at no point do you call print() to send any | ||||||||||||||||||||||||||||||||
| 924 | output to STDOUT. Instead, all output is returned as a scalar. | ||||||||||||||||||||||||||||||||
| 925 | |||||||||||||||||||||||||||||||||
| 926 | CGI::Application's most significant contribution is in managing | ||||||||||||||||||||||||||||||||
| 927 | the application state. Notice that all which is needed to push | ||||||||||||||||||||||||||||||||
| 928 | the application forward is to set the value of a HTML form | ||||||||||||||||||||||||||||||||
| 929 | parameter 'rm' to the value of the "run mode" you wish to handle | ||||||||||||||||||||||||||||||||
| 930 | the form submission. This is the key to CGI::Application. | ||||||||||||||||||||||||||||||||
| 931 | |||||||||||||||||||||||||||||||||
| 932 | |||||||||||||||||||||||||||||||||
| 933 | =head1 ABSTRACT | ||||||||||||||||||||||||||||||||
| 934 | |||||||||||||||||||||||||||||||||
| 935 | The guiding philosophy behind CGI::Application is that a web-based | ||||||||||||||||||||||||||||||||
| 936 | application can be organized into a specific set of "Run Modes." | ||||||||||||||||||||||||||||||||
| 937 | Each Run Mode is roughly analogous to a single screen (a form, some | ||||||||||||||||||||||||||||||||
| 938 | output, etc.). All the Run Modes are managed by a single "Application | ||||||||||||||||||||||||||||||||
| 939 | Module" which is a Perl module. In your web server's document space | ||||||||||||||||||||||||||||||||
| 940 | there is an "Instance Script" which is called by the web server as a | ||||||||||||||||||||||||||||||||
| 941 | CGI (or an Apache::Registry script if you're using Apache + mod_perl). | ||||||||||||||||||||||||||||||||
| 942 | |||||||||||||||||||||||||||||||||
| 943 | This methodology is an inversion of the "Embedded" philosophy (ASP, JSP, | ||||||||||||||||||||||||||||||||
| 944 | EmbPerl, Mason, etc.) in which there are "pages" for each state of the | ||||||||||||||||||||||||||||||||
| 945 | application, and the page drives functionality. In CGI::Application, | ||||||||||||||||||||||||||||||||
| 946 | form follows function -- the Application Module drives pages, and the | ||||||||||||||||||||||||||||||||
| 947 | code for a single application is in one place; not spread out over | ||||||||||||||||||||||||||||||||
| 948 | multiple "pages". If you feel that Embedded architectures are | ||||||||||||||||||||||||||||||||
| 949 | confusing, unorganized, difficult to design and difficult to manage, | ||||||||||||||||||||||||||||||||
| 950 | CGI::Application is the methodology for you! | ||||||||||||||||||||||||||||||||
| 951 | |||||||||||||||||||||||||||||||||
| 952 | Apache is NOT a requirement for CGI::Application. Web applications based on | ||||||||||||||||||||||||||||||||
| 953 | CGI::Application will run equally well on NT/IIS or any other | ||||||||||||||||||||||||||||||||
| 954 | CGI-compatible environment. CGI::Application-based projects | ||||||||||||||||||||||||||||||||
| 955 | are, however, ripe for use on Apache/mod_perl servers, as they | ||||||||||||||||||||||||||||||||
| 956 | naturally encourage Good Programming Practices and will often work | ||||||||||||||||||||||||||||||||
| 957 | in persistent environments without modification. | ||||||||||||||||||||||||||||||||
| 958 | |||||||||||||||||||||||||||||||||
| 959 | For more information on using CGI::Application with mod_perl, please see our | ||||||||||||||||||||||||||||||||
| 960 | website at http://www.cgi-app.org/, as well as | ||||||||||||||||||||||||||||||||
| 961 | L |
||||||||||||||||||||||||||||||||
| 962 | |||||||||||||||||||||||||||||||||
| 963 | =head1 DESCRIPTION | ||||||||||||||||||||||||||||||||
| 964 | |||||||||||||||||||||||||||||||||
| 965 | It is intended that your Application Module will be implemented as a sub-class | ||||||||||||||||||||||||||||||||
| 966 | of CGI::Application. This is done simply as follows: | ||||||||||||||||||||||||||||||||
| 967 | |||||||||||||||||||||||||||||||||
| 968 | package My::App; | ||||||||||||||||||||||||||||||||
| 969 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
| 970 | |||||||||||||||||||||||||||||||||
| 971 | B |
||||||||||||||||||||||||||||||||
| 972 | |||||||||||||||||||||||||||||||||
| 973 | For the purpose of this document, we will refer to the | ||||||||||||||||||||||||||||||||
| 974 | following conventions: | ||||||||||||||||||||||||||||||||
| 975 | |||||||||||||||||||||||||||||||||
| 976 | WebApp.pm The Perl module which implements your Application Module class. | ||||||||||||||||||||||||||||||||
| 977 | WebApp Your Application Module class; a sub-class of CGI::Application. | ||||||||||||||||||||||||||||||||
| 978 | webapp.cgi The Instance Script which implements your Application Module. | ||||||||||||||||||||||||||||||||
| 979 | $webapp An instance (object) of your Application Module class. | ||||||||||||||||||||||||||||||||
| 980 | $c Same as $webapp, used in instance methods to pass around the | ||||||||||||||||||||||||||||||||
| 981 | current object. (Sometimes referred as "$self" in other code) | ||||||||||||||||||||||||||||||||
| 982 | |||||||||||||||||||||||||||||||||
| 983 | |||||||||||||||||||||||||||||||||
| 984 | |||||||||||||||||||||||||||||||||
| 985 | |||||||||||||||||||||||||||||||||
| 986 | =head2 Instance Script Methods | ||||||||||||||||||||||||||||||||
| 987 | |||||||||||||||||||||||||||||||||
| 988 | By inheriting from CGI::Application you have access to a | ||||||||||||||||||||||||||||||||
| 989 | number of built-in methods. The following are those which | ||||||||||||||||||||||||||||||||
| 990 | are expected to be called from your Instance Script. | ||||||||||||||||||||||||||||||||
| 991 | |||||||||||||||||||||||||||||||||
| 992 | =head3 new() | ||||||||||||||||||||||||||||||||
| 993 | |||||||||||||||||||||||||||||||||
| 994 | The new() method is the constructor for a CGI::Application. It returns | ||||||||||||||||||||||||||||||||
| 995 | a blessed reference to your Application Module package (class). Optionally, | ||||||||||||||||||||||||||||||||
| 996 | new() may take a set of parameters as key => value pairs: | ||||||||||||||||||||||||||||||||
| 997 | |||||||||||||||||||||||||||||||||
| 998 | my $webapp = WebApp->new( | ||||||||||||||||||||||||||||||||
| 999 | TMPL_PATH => 'App/', | ||||||||||||||||||||||||||||||||
| 1000 | PARAMS => { | ||||||||||||||||||||||||||||||||
| 1001 | 'custom_thing_1' => 'some val', | ||||||||||||||||||||||||||||||||
| 1002 | 'another_custom_thing' => [qw/123 456/] | ||||||||||||||||||||||||||||||||
| 1003 | } | ||||||||||||||||||||||||||||||||
| 1004 | ); | ||||||||||||||||||||||||||||||||
| 1005 | |||||||||||||||||||||||||||||||||
| 1006 | This method may take some specific parameters: | ||||||||||||||||||||||||||||||||
| 1007 | |||||||||||||||||||||||||||||||||
| 1008 | B |
||||||||||||||||||||||||||||||||
| 1009 | This is used by the load_tmpl() method (specified below), and may also be used | ||||||||||||||||||||||||||||||||
| 1010 | for the same purpose by other template plugins. This run-time parameter allows | ||||||||||||||||||||||||||||||||
| 1011 | you to further encapsulate instantiating templates, providing potential for | ||||||||||||||||||||||||||||||||
| 1012 | more re-usability. It can be either a scalar or an array reference of multiple | ||||||||||||||||||||||||||||||||
| 1013 | paths. | ||||||||||||||||||||||||||||||||
| 1014 | |||||||||||||||||||||||||||||||||
| 1015 | B |
||||||||||||||||||||||||||||||||
| 1016 | already-created CGI.pm query object. Under normal use, | ||||||||||||||||||||||||||||||||
| 1017 | CGI::Application will instantiate its own CGI.pm query object. | ||||||||||||||||||||||||||||||||
| 1018 | Under certain conditions, it might be useful to be able to use | ||||||||||||||||||||||||||||||||
| 1019 | one which has already been created. | ||||||||||||||||||||||||||||||||
| 1020 | |||||||||||||||||||||||||||||||||
| 1021 | B |
||||||||||||||||||||||||||||||||
| 1022 | of custom parameters at run-time. By passing in different | ||||||||||||||||||||||||||||||||
| 1023 | values in different instance scripts which use the same application | ||||||||||||||||||||||||||||||||
| 1024 | module you can achieve a higher level of re-usability. For instance, | ||||||||||||||||||||||||||||||||
| 1025 | imagine an application module, "Mailform.pm". The application takes | ||||||||||||||||||||||||||||||||
| 1026 | the contents of a HTML form and emails it to a specified recipient. | ||||||||||||||||||||||||||||||||
| 1027 | You could have multiple instance scripts throughout your site which | ||||||||||||||||||||||||||||||||
| 1028 | all use this "Mailform.pm" module, but which set different recipients | ||||||||||||||||||||||||||||||||
| 1029 | or different forms. | ||||||||||||||||||||||||||||||||
| 1030 | |||||||||||||||||||||||||||||||||
| 1031 | One common use of instance scripts is to provide a path to a config file. This | ||||||||||||||||||||||||||||||||
| 1032 | design allows you to define project wide configuration objects used by many | ||||||||||||||||||||||||||||||||
| 1033 | several instance scripts. There are several plugins which simplify the syntax | ||||||||||||||||||||||||||||||||
| 1034 | for this and provide lazy loading. Here's an example using | ||||||||||||||||||||||||||||||||
| 1035 | L |
||||||||||||||||||||||||||||||||
| 1036 | many configuration file formats. | ||||||||||||||||||||||||||||||||
| 1037 | |||||||||||||||||||||||||||||||||
| 1038 | my $app = WebApp->new(PARAMS => { cfg_file => 'config.pl' }); | ||||||||||||||||||||||||||||||||
| 1039 | |||||||||||||||||||||||||||||||||
| 1040 | # Later in your app: | ||||||||||||||||||||||||||||||||
| 1041 | my %cfg = $self->cfg() | ||||||||||||||||||||||||||||||||
| 1042 | # or ... $self->cfg('HTML_ROOT_DIR'); | ||||||||||||||||||||||||||||||||
| 1043 | |||||||||||||||||||||||||||||||||
| 1044 | See the list of plugins below for more config file integration solutions. | ||||||||||||||||||||||||||||||||
| 1045 | |||||||||||||||||||||||||||||||||
| 1046 | =head3 run() | ||||||||||||||||||||||||||||||||
| 1047 | |||||||||||||||||||||||||||||||||
| 1048 | The run() method is called upon your Application Module object, from | ||||||||||||||||||||||||||||||||
| 1049 | your Instance Script. When called, it executes the functionality | ||||||||||||||||||||||||||||||||
| 1050 | in your Application Module. | ||||||||||||||||||||||||||||||||
| 1051 | |||||||||||||||||||||||||||||||||
| 1052 | my $webapp = WebApp->new(); | ||||||||||||||||||||||||||||||||
| 1053 | $webapp->run(); | ||||||||||||||||||||||||||||||||
| 1054 | |||||||||||||||||||||||||||||||||
| 1055 | This method first determines the application state by looking at the | ||||||||||||||||||||||||||||||||
| 1056 | value of the CGI parameter specified by mode_param() (defaults to | ||||||||||||||||||||||||||||||||
| 1057 | 'rm' for "Run Mode"), which is expected to contain the name of the mode of | ||||||||||||||||||||||||||||||||
| 1058 | operation. If not specified, the state defaults to the value | ||||||||||||||||||||||||||||||||
| 1059 | of start_mode(). | ||||||||||||||||||||||||||||||||
| 1060 | |||||||||||||||||||||||||||||||||
| 1061 | Once the mode has been determined, run() looks at the dispatch | ||||||||||||||||||||||||||||||||
| 1062 | table stored in run_modes() and finds the function pointer which | ||||||||||||||||||||||||||||||||
| 1063 | is keyed from the mode name. If found, the function is called and the | ||||||||||||||||||||||||||||||||
| 1064 | data returned is print()'ed to STDOUT and to the browser. If | ||||||||||||||||||||||||||||||||
| 1065 | the specified mode is not found in the run_modes() table, run() will | ||||||||||||||||||||||||||||||||
| 1066 | croak(). | ||||||||||||||||||||||||||||||||
| 1067 | |||||||||||||||||||||||||||||||||
| 1068 | =head2 PSGI support | ||||||||||||||||||||||||||||||||
| 1069 | |||||||||||||||||||||||||||||||||
| 1070 | CGI::Application offers native L |
||||||||||||||||||||||||||||||||
| 1071 | for this is L |
||||||||||||||||||||||||||||||||
| 1072 | support to it. | ||||||||||||||||||||||||||||||||
| 1073 | |||||||||||||||||||||||||||||||||
| 1074 | =head3 psgi_app() | ||||||||||||||||||||||||||||||||
| 1075 | |||||||||||||||||||||||||||||||||
| 1076 | $psgi_coderef = WebApp->psgi_app({ ... args to new() ... }); | ||||||||||||||||||||||||||||||||
| 1077 | |||||||||||||||||||||||||||||||||
| 1078 | The simplest way to create and return a PSGI-compatible coderef. Pass in | ||||||||||||||||||||||||||||||||
| 1079 | arguments to a hashref just as would to new. This returns a PSGI-compatible | ||||||||||||||||||||||||||||||||
| 1080 | coderef, using L |
||||||||||||||||||||||||||||||||
| 1081 | object, construct your own object using C<< run_as_psgi() >>, as shown below. | ||||||||||||||||||||||||||||||||
| 1082 | |||||||||||||||||||||||||||||||||
| 1083 | It's possible that we'll change from CGI::PSGI to a different-but-compatible | ||||||||||||||||||||||||||||||||
| 1084 | query object for PSGI support in the future, perhaps if CGI.pm adds native | ||||||||||||||||||||||||||||||||
| 1085 | PSGI support. | ||||||||||||||||||||||||||||||||
| 1086 | |||||||||||||||||||||||||||||||||
| 1087 | =head3 run_as_psgi() | ||||||||||||||||||||||||||||||||
| 1088 | |||||||||||||||||||||||||||||||||
| 1089 | my $psgi_aref = $webapp->run_as_psgi; | ||||||||||||||||||||||||||||||||
| 1090 | |||||||||||||||||||||||||||||||||
| 1091 | Just like C<< run >>, but prints no output and returns the data structure | ||||||||||||||||||||||||||||||||
| 1092 | required by the L |
||||||||||||||||||||||||||||||||
| 1093 | application on top of a PSGI-compatible handler, such as L |
||||||||||||||||||||||||||||||||
| 1094 | |||||||||||||||||||||||||||||||||
| 1095 | If you are just getting started, just use C<< run() >>. It's easy to switch to using | ||||||||||||||||||||||||||||||||
| 1096 | C<< run_as_psgi >> later. | ||||||||||||||||||||||||||||||||
| 1097 | |||||||||||||||||||||||||||||||||
| 1098 | Why use C<< run_as_psgi() >>? There are already solutions to run | ||||||||||||||||||||||||||||||||
| 1099 | CGI::Application-based projects on several web servers with dozens of plugins. | ||||||||||||||||||||||||||||||||
| 1100 | Running as a PSGI-compatible application provides the ability to run on | ||||||||||||||||||||||||||||||||
| 1101 | additional PSGI-compatible servers, as well as providing access to all of the | ||||||||||||||||||||||||||||||||
| 1102 | "Middleware" solutions available through the L |
||||||||||||||||||||||||||||||||
| 1103 | |||||||||||||||||||||||||||||||||
| 1104 | The structure returned is an arrayref, containing the status code, an arrayref | ||||||||||||||||||||||||||||||||
| 1105 | of header key/values and an arrayref containing the body. | ||||||||||||||||||||||||||||||||
| 1106 | |||||||||||||||||||||||||||||||||
| 1107 | [ 200, [ 'Content-Type' => 'text/html' ], [ $body ] ] | ||||||||||||||||||||||||||||||||
| 1108 | |||||||||||||||||||||||||||||||||
| 1109 | By default the body is a single scalar, but plugins may modify this to return | ||||||||||||||||||||||||||||||||
| 1110 | other value PSGI values. See L |
||||||||||||||||||||||||||||||||
| 1111 | response format. | ||||||||||||||||||||||||||||||||
| 1112 | |||||||||||||||||||||||||||||||||
| 1113 | Note that calling C<< run_as_psgi >> only handles the I | ||||||||||||||||||||||||||||||||
| 1114 | PSGI spec. to handle the input, you need to use a CGI.pm-like query object that | ||||||||||||||||||||||||||||||||
| 1115 | is PSGI-compliant, such as L |
||||||||||||||||||||||||||||||||
| 1116 | and L |
||||||||||||||||||||||||||||||||
| 1117 | |||||||||||||||||||||||||||||||||
| 1118 | The final result might look like this: | ||||||||||||||||||||||||||||||||
| 1119 | |||||||||||||||||||||||||||||||||
| 1120 | use WebApp; | ||||||||||||||||||||||||||||||||
| 1121 | use CGI::PSGI; | ||||||||||||||||||||||||||||||||
| 1122 | |||||||||||||||||||||||||||||||||
| 1123 | my $handler = sub { | ||||||||||||||||||||||||||||||||
| 1124 | my $env = shift; | ||||||||||||||||||||||||||||||||
| 1125 | my $webapp = WebApp->new({ QUERY => CGI::PSGI->new($env) }); | ||||||||||||||||||||||||||||||||
| 1126 | $webapp->run_as_psgi; | ||||||||||||||||||||||||||||||||
| 1127 | }; | ||||||||||||||||||||||||||||||||
| 1128 | |||||||||||||||||||||||||||||||||
| 1129 | =head2 Additional PSGI Return Values | ||||||||||||||||||||||||||||||||
| 1130 | |||||||||||||||||||||||||||||||||
| 1131 | 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: | ||||||||||||||||||||||||||||||||
| 1132 | |||||||||||||||||||||||||||||||||
| 1133 | sub returning_a_file_handle { | ||||||||||||||||||||||||||||||||
| 1134 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1135 | |||||||||||||||||||||||||||||||||
| 1136 | $self->header_props(-type => 'text/plain'); | ||||||||||||||||||||||||||||||||
| 1137 | |||||||||||||||||||||||||||||||||
| 1138 | open my $fh, "<", 'test_file.txt' or die "OOPS! $!"; | ||||||||||||||||||||||||||||||||
| 1139 | |||||||||||||||||||||||||||||||||
| 1140 | return $fh; | ||||||||||||||||||||||||||||||||
| 1141 | } | ||||||||||||||||||||||||||||||||
| 1142 | |||||||||||||||||||||||||||||||||
| 1143 | sub returning_a_subref { | ||||||||||||||||||||||||||||||||
| 1144 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1145 | |||||||||||||||||||||||||||||||||
| 1146 | $self->header_props(-type => 'text/plain'); | ||||||||||||||||||||||||||||||||
| 1147 | return sub { | ||||||||||||||||||||||||||||||||
| 1148 | my $writer = shift; | ||||||||||||||||||||||||||||||||
| 1149 | foreach my $i (1..10) { | ||||||||||||||||||||||||||||||||
| 1150 | #sleep 1; | ||||||||||||||||||||||||||||||||
| 1151 | $writer->write("check $i: " . time . "\n"); | ||||||||||||||||||||||||||||||||
| 1152 | } | ||||||||||||||||||||||||||||||||
| 1153 | }; | ||||||||||||||||||||||||||||||||
| 1154 | } | ||||||||||||||||||||||||||||||||
| 1155 | |||||||||||||||||||||||||||||||||
| 1156 | =head2 Methods to possibly override | ||||||||||||||||||||||||||||||||
| 1157 | |||||||||||||||||||||||||||||||||
| 1158 | CGI::Application implements some methods which are expected to be overridden | ||||||||||||||||||||||||||||||||
| 1159 | by implementing them in your sub-class module. These methods are as follows: | ||||||||||||||||||||||||||||||||
| 1160 | |||||||||||||||||||||||||||||||||
| 1161 | =head3 setup() | ||||||||||||||||||||||||||||||||
| 1162 | |||||||||||||||||||||||||||||||||
| 1163 | This method is called by the inherited new() constructor method. The | ||||||||||||||||||||||||||||||||
| 1164 | setup() method should be used to define the following property/methods: | ||||||||||||||||||||||||||||||||
| 1165 | |||||||||||||||||||||||||||||||||
| 1166 | mode_param() - set the name of the run mode CGI param. | ||||||||||||||||||||||||||||||||
| 1167 | start_mode() - text scalar containing the default run mode. | ||||||||||||||||||||||||||||||||
| 1168 | error_mode() - text scalar containing the error mode. | ||||||||||||||||||||||||||||||||
| 1169 | run_modes() - hash table containing mode => function mappings. | ||||||||||||||||||||||||||||||||
| 1170 | tmpl_path() - text scalar or array reference containing path(s) to template files. | ||||||||||||||||||||||||||||||||
| 1171 | |||||||||||||||||||||||||||||||||
| 1172 | Your setup() method may call any of the instance methods of your application. | ||||||||||||||||||||||||||||||||
| 1173 | This function is a good place to define properties specific to your application | ||||||||||||||||||||||||||||||||
| 1174 | via the $webapp->param() method. | ||||||||||||||||||||||||||||||||
| 1175 | |||||||||||||||||||||||||||||||||
| 1176 | Your setup() method might be implemented something like this: | ||||||||||||||||||||||||||||||||
| 1177 | |||||||||||||||||||||||||||||||||
| 1178 | sub setup { | ||||||||||||||||||||||||||||||||
| 1179 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1180 | $self->tmpl_path('/path/to/my/templates/'); | ||||||||||||||||||||||||||||||||
| 1181 | $self->start_mode('putform'); | ||||||||||||||||||||||||||||||||
| 1182 | $self->error_mode('my_error_rm'); | ||||||||||||||||||||||||||||||||
| 1183 | $self->run_modes({ | ||||||||||||||||||||||||||||||||
| 1184 | 'putform' => 'my_putform_func', | ||||||||||||||||||||||||||||||||
| 1185 | 'postdata' => 'my_data_func' | ||||||||||||||||||||||||||||||||
| 1186 | }); | ||||||||||||||||||||||||||||||||
| 1187 | $self->param('myprop1'); | ||||||||||||||||||||||||||||||||
| 1188 | $self->param('myprop2', 'prop2value'); | ||||||||||||||||||||||||||||||||
| 1189 | $self->param('myprop3', ['p3v1', 'p3v2', 'p3v3']); | ||||||||||||||||||||||||||||||||
| 1190 | } | ||||||||||||||||||||||||||||||||
| 1191 | |||||||||||||||||||||||||||||||||
| 1192 | However, often times all that needs to be in setup() is defining your run modes | ||||||||||||||||||||||||||||||||
| 1193 | and your start mode. L |
||||||||||||||||||||||||||||||||
| 1194 | this with a simple syntax, using run mode attributes: | ||||||||||||||||||||||||||||||||
| 1195 | |||||||||||||||||||||||||||||||||
| 1196 | use CGI::Application::Plugin::AutoRunmode; | ||||||||||||||||||||||||||||||||
| 1197 | |||||||||||||||||||||||||||||||||
| 1198 | sub show_first : StartRunmode { ... }; | ||||||||||||||||||||||||||||||||
| 1199 | sub do_next : Runmode { ... } | ||||||||||||||||||||||||||||||||
| 1200 | |||||||||||||||||||||||||||||||||
| 1201 | =head3 teardown() | ||||||||||||||||||||||||||||||||
| 1202 | |||||||||||||||||||||||||||||||||
| 1203 | If implemented, this method is called automatically after your application runs. It | ||||||||||||||||||||||||||||||||
| 1204 | can be used to clean up after your operations. A typical use of the | ||||||||||||||||||||||||||||||||
| 1205 | teardown() function is to disconnect a database connection which was | ||||||||||||||||||||||||||||||||
| 1206 | established in the setup() function. You could also use the teardown() | ||||||||||||||||||||||||||||||||
| 1207 | method to store state information about the application to the server. | ||||||||||||||||||||||||||||||||
| 1208 | |||||||||||||||||||||||||||||||||
| 1209 | |||||||||||||||||||||||||||||||||
| 1210 | =head3 cgiapp_init() | ||||||||||||||||||||||||||||||||
| 1211 | |||||||||||||||||||||||||||||||||
| 1212 | If implemented, this method is called automatically right before the | ||||||||||||||||||||||||||||||||
| 1213 | setup() method is called. This method provides an optional initialization | ||||||||||||||||||||||||||||||||
| 1214 | hook, which improves the object-oriented characteristics of | ||||||||||||||||||||||||||||||||
| 1215 | CGI::Application. The cgiapp_init() method receives, as its parameters, | ||||||||||||||||||||||||||||||||
| 1216 | all the arguments which were sent to the new() method. | ||||||||||||||||||||||||||||||||
| 1217 | |||||||||||||||||||||||||||||||||
| 1218 | An example of the benefits provided by utilizing this hook is | ||||||||||||||||||||||||||||||||
| 1219 | creating a custom "application super-class" from which all | ||||||||||||||||||||||||||||||||
| 1220 | your web applications would inherit, instead of CGI::Application. | ||||||||||||||||||||||||||||||||
| 1221 | |||||||||||||||||||||||||||||||||
| 1222 | Consider the following: | ||||||||||||||||||||||||||||||||
| 1223 | |||||||||||||||||||||||||||||||||
| 1224 | # In MySuperclass.pm: | ||||||||||||||||||||||||||||||||
| 1225 | package MySuperclass; | ||||||||||||||||||||||||||||||||
| 1226 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
| 1227 | sub cgiapp_init { | ||||||||||||||||||||||||||||||||
| 1228 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1229 | # Perform some project-specific init behavior | ||||||||||||||||||||||||||||||||
| 1230 | # such as to load settings from a database or file. | ||||||||||||||||||||||||||||||||
| 1231 | } | ||||||||||||||||||||||||||||||||
| 1232 | |||||||||||||||||||||||||||||||||
| 1233 | |||||||||||||||||||||||||||||||||
| 1234 | # In MyApplication.pm: | ||||||||||||||||||||||||||||||||
| 1235 | package MyApplication; | ||||||||||||||||||||||||||||||||
| 1236 | use base 'MySuperclass'; | ||||||||||||||||||||||||||||||||
| 1237 | sub setup { ... } | ||||||||||||||||||||||||||||||||
| 1238 | sub teardown { ... } | ||||||||||||||||||||||||||||||||
| 1239 | # The rest of your CGI::Application-based follows... | ||||||||||||||||||||||||||||||||
| 1240 | |||||||||||||||||||||||||||||||||
| 1241 | |||||||||||||||||||||||||||||||||
| 1242 | By using CGI::Application and the cgiapp_init() method as illustrated, | ||||||||||||||||||||||||||||||||
| 1243 | a suite of applications could be designed to share certain | ||||||||||||||||||||||||||||||||
| 1244 | characteristics. This has the potential for much cleaner code | ||||||||||||||||||||||||||||||||
| 1245 | built on object-oriented inheritance. | ||||||||||||||||||||||||||||||||
| 1246 | |||||||||||||||||||||||||||||||||
| 1247 | |||||||||||||||||||||||||||||||||
| 1248 | =head3 cgiapp_prerun() | ||||||||||||||||||||||||||||||||
| 1249 | |||||||||||||||||||||||||||||||||
| 1250 | If implemented, this method is called automatically right before the | ||||||||||||||||||||||||||||||||
| 1251 | selected run mode method is called. This method provides an optional | ||||||||||||||||||||||||||||||||
| 1252 | pre-runmode hook, which permits functionality to be added at the point | ||||||||||||||||||||||||||||||||
| 1253 | right before the run mode method is called. To further leverage this | ||||||||||||||||||||||||||||||||
| 1254 | hook, the value of the run mode is passed into cgiapp_prerun(). | ||||||||||||||||||||||||||||||||
| 1255 | |||||||||||||||||||||||||||||||||
| 1256 | Another benefit provided by utilizing this hook is | ||||||||||||||||||||||||||||||||
| 1257 | creating a custom "application super-class" from which all | ||||||||||||||||||||||||||||||||
| 1258 | your web applications would inherit, instead of CGI::Application. | ||||||||||||||||||||||||||||||||
| 1259 | |||||||||||||||||||||||||||||||||
| 1260 | Consider the following: | ||||||||||||||||||||||||||||||||
| 1261 | |||||||||||||||||||||||||||||||||
| 1262 | # In MySuperclass.pm: | ||||||||||||||||||||||||||||||||
| 1263 | package MySuperclass; | ||||||||||||||||||||||||||||||||
| 1264 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
| 1265 | sub cgiapp_prerun { | ||||||||||||||||||||||||||||||||
| 1266 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1267 | # Perform some project-specific init behavior | ||||||||||||||||||||||||||||||||
| 1268 | # such as to implement run mode specific | ||||||||||||||||||||||||||||||||
| 1269 | # authorization functions. | ||||||||||||||||||||||||||||||||
| 1270 | } | ||||||||||||||||||||||||||||||||
| 1271 | |||||||||||||||||||||||||||||||||
| 1272 | |||||||||||||||||||||||||||||||||
| 1273 | # In MyApplication.pm: | ||||||||||||||||||||||||||||||||
| 1274 | package MyApplication; | ||||||||||||||||||||||||||||||||
| 1275 | use base 'MySuperclass'; | ||||||||||||||||||||||||||||||||
| 1276 | sub setup { ... } | ||||||||||||||||||||||||||||||||
| 1277 | sub teardown { ... } | ||||||||||||||||||||||||||||||||
| 1278 | # The rest of your CGI::Application-based follows... | ||||||||||||||||||||||||||||||||
| 1279 | |||||||||||||||||||||||||||||||||
| 1280 | |||||||||||||||||||||||||||||||||
| 1281 | By using CGI::Application and the cgiapp_prerun() method as illustrated, | ||||||||||||||||||||||||||||||||
| 1282 | a suite of applications could be designed to share certain | ||||||||||||||||||||||||||||||||
| 1283 | characteristics. This has the potential for much cleaner code | ||||||||||||||||||||||||||||||||
| 1284 | built on object-oriented inheritance. | ||||||||||||||||||||||||||||||||
| 1285 | |||||||||||||||||||||||||||||||||
| 1286 | It is also possible, within your cgiapp_prerun() method, to change the | ||||||||||||||||||||||||||||||||
| 1287 | run mode of your application. This can be done via the prerun_mode() | ||||||||||||||||||||||||||||||||
| 1288 | method, which is discussed elsewhere in this POD. | ||||||||||||||||||||||||||||||||
| 1289 | |||||||||||||||||||||||||||||||||
| 1290 | =head3 cgiapp_postrun() | ||||||||||||||||||||||||||||||||
| 1291 | |||||||||||||||||||||||||||||||||
| 1292 | If implemented, this hook will be called after the run mode method | ||||||||||||||||||||||||||||||||
| 1293 | has returned its output, but before HTTP headers are generated. This | ||||||||||||||||||||||||||||||||
| 1294 | will give you an opportunity to modify the body and headers before they | ||||||||||||||||||||||||||||||||
| 1295 | are returned to the web browser. | ||||||||||||||||||||||||||||||||
| 1296 | |||||||||||||||||||||||||||||||||
| 1297 | A typical use for this hook is pipelining the output of a CGI-Application | ||||||||||||||||||||||||||||||||
| 1298 | through a series of "filter" processors. For example: | ||||||||||||||||||||||||||||||||
| 1299 | |||||||||||||||||||||||||||||||||
| 1300 | * You want to enclose the output of all your CGI-Applications in | ||||||||||||||||||||||||||||||||
| 1301 | an HTML table in a larger page. | ||||||||||||||||||||||||||||||||
| 1302 | |||||||||||||||||||||||||||||||||
| 1303 | * Your run modes return structured data (such as XML), which you | ||||||||||||||||||||||||||||||||
| 1304 | want to transform using a standard mechanism (such as XSLT). | ||||||||||||||||||||||||||||||||
| 1305 | |||||||||||||||||||||||||||||||||
| 1306 | * You want to post-process CGI-App output through another system, | ||||||||||||||||||||||||||||||||
| 1307 | such as HTML::Mason. | ||||||||||||||||||||||||||||||||
| 1308 | |||||||||||||||||||||||||||||||||
| 1309 | * You want to modify HTTP headers in a particular way across all | ||||||||||||||||||||||||||||||||
| 1310 | run modes, based on particular criteria. | ||||||||||||||||||||||||||||||||
| 1311 | |||||||||||||||||||||||||||||||||
| 1312 | The cgiapp_postrun() hook receives a reference to the output from | ||||||||||||||||||||||||||||||||
| 1313 | your run mode method, in addition to the CGI-App object. A typical | ||||||||||||||||||||||||||||||||
| 1314 | cgiapp_postrun() method might be implemented as follows: | ||||||||||||||||||||||||||||||||
| 1315 | |||||||||||||||||||||||||||||||||
| 1316 | sub cgiapp_postrun { | ||||||||||||||||||||||||||||||||
| 1317 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1318 | my $output_ref = shift; | ||||||||||||||||||||||||||||||||
| 1319 | |||||||||||||||||||||||||||||||||
| 1320 | # Enclose output HTML table | ||||||||||||||||||||||||||||||||
| 1321 | my $new_output = "
|
||||||||||||||||||||||||||||||||
| 1325 | |||||||||||||||||||||||||||||||||
| 1326 | # Replace old output with new output | ||||||||||||||||||||||||||||||||
| 1327 | $$output_ref = $new_output; | ||||||||||||||||||||||||||||||||
| 1328 | } | ||||||||||||||||||||||||||||||||
| 1329 | |||||||||||||||||||||||||||||||||
| 1330 | |||||||||||||||||||||||||||||||||
| 1331 | Obviously, with access to the CGI-App object you have full access to use all | ||||||||||||||||||||||||||||||||
| 1332 | the methods normally available in a run mode. You could, for example, use | ||||||||||||||||||||||||||||||||
| 1333 | C |
||||||||||||||||||||||||||||||||
| 1334 | You could change the HTTP headers (via C |
||||||||||||||||||||||||||||||||
| 1335 | methods) to set up a redirect. You could also use the objects properties | ||||||||||||||||||||||||||||||||
| 1336 | to apply changes only under certain circumstance, such as a in only certain run | ||||||||||||||||||||||||||||||||
| 1337 | modes, and when a C is a particular value. | ||||||||||||||||||||||||||||||||
| 1338 | |||||||||||||||||||||||||||||||||
| 1339 | |||||||||||||||||||||||||||||||||
| 1340 | =head3 cgiapp_get_query() | ||||||||||||||||||||||||||||||||
| 1341 | |||||||||||||||||||||||||||||||||
| 1342 | my $q = $webapp->cgiapp_get_query; | ||||||||||||||||||||||||||||||||
| 1343 | |||||||||||||||||||||||||||||||||
| 1344 | Override this method to retrieve the query object if you wish to use a | ||||||||||||||||||||||||||||||||
| 1345 | different query interface instead of CGI.pm. | ||||||||||||||||||||||||||||||||
| 1346 | |||||||||||||||||||||||||||||||||
| 1347 | CGI.pm is only loaded if it is used on a given request. | ||||||||||||||||||||||||||||||||
| 1348 | |||||||||||||||||||||||||||||||||
| 1349 | If you can use an alternative to CGI.pm, it needs to have some compatibility | ||||||||||||||||||||||||||||||||
| 1350 | with the CGI.pm API. For normal use, just having a compatible C method | ||||||||||||||||||||||||||||||||
| 1351 | should be sufficient. | ||||||||||||||||||||||||||||||||
| 1352 | |||||||||||||||||||||||||||||||||
| 1353 | If you use the C |
||||||||||||||||||||||||||||||||
| 1354 | the C |
||||||||||||||||||||||||||||||||
| 1355 | |||||||||||||||||||||||||||||||||
| 1356 | If you use the C |
||||||||||||||||||||||||||||||||
| 1357 | C |
||||||||||||||||||||||||||||||||
| 1358 | |||||||||||||||||||||||||||||||||
| 1359 | =head2 Essential Application Methods | ||||||||||||||||||||||||||||||||
| 1360 | |||||||||||||||||||||||||||||||||
| 1361 | The following methods are inherited from CGI::Application, and are | ||||||||||||||||||||||||||||||||
| 1362 | available to be called by your application within your Application | ||||||||||||||||||||||||||||||||
| 1363 | Module. They are called essential because you will use all are most | ||||||||||||||||||||||||||||||||
| 1364 | of them to get any application up and running. These functions are listed in alphabetical order. | ||||||||||||||||||||||||||||||||
| 1365 | |||||||||||||||||||||||||||||||||
| 1366 | =head3 load_tmpl() | ||||||||||||||||||||||||||||||||
| 1367 | |||||||||||||||||||||||||||||||||
| 1368 | my $tmpl_obj = $webapp->load_tmpl; | ||||||||||||||||||||||||||||||||
| 1369 | my $tmpl_obj = $webapp->load_tmpl('some.html'); | ||||||||||||||||||||||||||||||||
| 1370 | my $tmpl_obj = $webapp->load_tmpl( \$template_content ); | ||||||||||||||||||||||||||||||||
| 1371 | my $tmpl_obj = $webapp->load_tmpl( FILEHANDLE ); | ||||||||||||||||||||||||||||||||
| 1372 | |||||||||||||||||||||||||||||||||
| 1373 | This method takes the name of a template file, a reference to template data | ||||||||||||||||||||||||||||||||
| 1374 | 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". | ||||||||||||||||||||||||||||||||
| 1375 | |||||||||||||||||||||||||||||||||
| 1376 | If you use the default template naming system, you should also use | ||||||||||||||||||||||||||||||||
| 1377 | L |
||||||||||||||||||||||||||||||||
| 1378 | name accurate when you pass control from one run mode to another. | ||||||||||||||||||||||||||||||||
| 1379 | |||||||||||||||||||||||||||||||||
| 1380 | ( For integration with other template systems | ||||||||||||||||||||||||||||||||
| 1381 | and automated template names, see "Alternatives to load_tmpl() below. ) | ||||||||||||||||||||||||||||||||
| 1382 | |||||||||||||||||||||||||||||||||
| 1383 | When you pass in a filename, the HTML::Template->new_file() constructor | ||||||||||||||||||||||||||||||||
| 1384 | is used for create the object. When you pass in a reference to the template | ||||||||||||||||||||||||||||||||
| 1385 | content, the HTML::Template->new_scalar_ref() constructor is used and | ||||||||||||||||||||||||||||||||
| 1386 | when you pass in a filehandle, the HTML::Template->new_filehandle() | ||||||||||||||||||||||||||||||||
| 1387 | constructor is used. | ||||||||||||||||||||||||||||||||
| 1388 | |||||||||||||||||||||||||||||||||
| 1389 | Refer to L |
||||||||||||||||||||||||||||||||
| 1390 | |||||||||||||||||||||||||||||||||
| 1391 | If tmpl_path() has been specified, load_tmpl() will set the | ||||||||||||||||||||||||||||||||
| 1392 | HTML::Template C |
||||||||||||||||||||||||||||||||
| 1393 | assists in encapsulating template usage. | ||||||||||||||||||||||||||||||||
| 1394 | |||||||||||||||||||||||||||||||||
| 1395 | The load_tmpl() method will pass any extra parameters sent to it directly to | ||||||||||||||||||||||||||||||||
| 1396 | HTML::Template->new_file() (or new_scalar_ref() or new_filehandle()). | ||||||||||||||||||||||||||||||||
| 1397 | This will allow the HTML::Template object to be further customized: | ||||||||||||||||||||||||||||||||
| 1398 | |||||||||||||||||||||||||||||||||
| 1399 | my $tmpl_obj = $webapp->load_tmpl('some_other.html', | ||||||||||||||||||||||||||||||||
| 1400 | die_on_bad_params => 0, | ||||||||||||||||||||||||||||||||
| 1401 | cache => 1 | ||||||||||||||||||||||||||||||||
| 1402 | ); | ||||||||||||||||||||||||||||||||
| 1403 | |||||||||||||||||||||||||||||||||
| 1404 | Note that if you want to pass extra arguments but use the default template | ||||||||||||||||||||||||||||||||
| 1405 | name, you still need to provide a name of C |
||||||||||||||||||||||||||||||||
| 1406 | |||||||||||||||||||||||||||||||||
| 1407 | my $tmpl_obj = $webapp->load_tmpl(undef, | ||||||||||||||||||||||||||||||||
| 1408 | die_on_bad_params => 0, | ||||||||||||||||||||||||||||||||
| 1409 | cache => 1 | ||||||||||||||||||||||||||||||||
| 1410 | ); | ||||||||||||||||||||||||||||||||
| 1411 | |||||||||||||||||||||||||||||||||
| 1412 | B |
||||||||||||||||||||||||||||||||
| 1413 | |||||||||||||||||||||||||||||||||
| 1414 | If your application requires more specialized behavior than this, you can | ||||||||||||||||||||||||||||||||
| 1415 | always replace it by overriding load_tmpl() by implementing your own | ||||||||||||||||||||||||||||||||
| 1416 | load_tmpl() in your CGI::Application sub-class application module. | ||||||||||||||||||||||||||||||||
| 1417 | |||||||||||||||||||||||||||||||||
| 1418 | First, you may want to check out the template related plugins. | ||||||||||||||||||||||||||||||||
| 1419 | |||||||||||||||||||||||||||||||||
| 1420 | L |
||||||||||||||||||||||||||||||||
| 1421 | and features pre-and-post features, singleton support and more. | ||||||||||||||||||||||||||||||||
| 1422 | |||||||||||||||||||||||||||||||||
| 1423 | L |
||||||||||||||||||||||||||||||||
| 1424 | not a file. It features a simple syntax and MIME-type detection. | ||||||||||||||||||||||||||||||||
| 1425 | |||||||||||||||||||||||||||||||||
| 1426 | B |
||||||||||||||||||||||||||||||||
| 1427 | |||||||||||||||||||||||||||||||||
| 1428 | You may specify an API-compatible alternative to L |
||||||||||||||||||||||||||||||||
| 1429 | a new C |
||||||||||||||||||||||||||||||||
| 1430 | |||||||||||||||||||||||||||||||||
| 1431 | $self->html_tmpl_class('HTML::Template::Dumper'); | ||||||||||||||||||||||||||||||||
| 1432 | |||||||||||||||||||||||||||||||||
| 1433 | The default is "HTML::Template". The alternate class should | ||||||||||||||||||||||||||||||||
| 1434 | provide at least the following parts of the HTML::Template API: | ||||||||||||||||||||||||||||||||
| 1435 | |||||||||||||||||||||||||||||||||
| 1436 | $t = $class->new( scalarref => ... ); # If you use scalarref templates | ||||||||||||||||||||||||||||||||
| 1437 | $t = $class->new( filehandle => ... ); # If you use filehandle templates | ||||||||||||||||||||||||||||||||
| 1438 | $t = $class->new( filename => ... ); | ||||||||||||||||||||||||||||||||
| 1439 | $t->param(...); | ||||||||||||||||||||||||||||||||
| 1440 | |||||||||||||||||||||||||||||||||
| 1441 | Here's an example case allowing you to precisely test what's sent to your | ||||||||||||||||||||||||||||||||
| 1442 | templates: | ||||||||||||||||||||||||||||||||
| 1443 | |||||||||||||||||||||||||||||||||
| 1444 | $ENV{CGI_APP_RETURN_ONLY} = 1; | ||||||||||||||||||||||||||||||||
| 1445 | my $webapp = WebApp->new; | ||||||||||||||||||||||||||||||||
| 1446 | $webapp->html_tmpl_class('HTML::Template::Dumper'); | ||||||||||||||||||||||||||||||||
| 1447 | my $out_str = $webapp->run; | ||||||||||||||||||||||||||||||||
| 1448 | my $tmpl_href = eval "$out_str"; | ||||||||||||||||||||||||||||||||
| 1449 | |||||||||||||||||||||||||||||||||
| 1450 | # Now Precisely test what would be set to the template | ||||||||||||||||||||||||||||||||
| 1451 | is ($tmpl_href->{pet_name}, 'Daisy', "Daisy is sent template"); | ||||||||||||||||||||||||||||||||
| 1452 | |||||||||||||||||||||||||||||||||
| 1453 | This is a powerful technique because HTML::Template::Dumper loads and considers | ||||||||||||||||||||||||||||||||
| 1454 | the template file that would actually be used. If the 'pet_name' token was missing | ||||||||||||||||||||||||||||||||
| 1455 | in the template, the above test would fail. So, you are testing both your code | ||||||||||||||||||||||||||||||||
| 1456 | and your templates in a much more precise way than using simple regular | ||||||||||||||||||||||||||||||||
| 1457 | expressions to see if the string "Daisy" appeared somewhere on the page. | ||||||||||||||||||||||||||||||||
| 1458 | |||||||||||||||||||||||||||||||||
| 1459 | B |
||||||||||||||||||||||||||||||||
| 1460 | |||||||||||||||||||||||||||||||||
| 1461 | Plugin authors will be interested to know that you can register a callback that | ||||||||||||||||||||||||||||||||
| 1462 | will be executed just before load_tmpl() returns: | ||||||||||||||||||||||||||||||||
| 1463 | |||||||||||||||||||||||||||||||||
| 1464 | $self->add_callback('load_tmpl',\&your_method); | ||||||||||||||||||||||||||||||||
| 1465 | |||||||||||||||||||||||||||||||||
| 1466 | When C |
||||||||||||||||||||||||||||||||
| 1467 | |||||||||||||||||||||||||||||||||
| 1468 | 1. A hash reference of the extra params passed into C |
||||||||||||||||||||||||||||||||
| 1469 | 2. Followed by a hash reference to template parameters. | ||||||||||||||||||||||||||||||||
| 1470 | With both of these, you can modify them by reference to affect | ||||||||||||||||||||||||||||||||
| 1471 | values that are actually passed to the new() and param() methods of the | ||||||||||||||||||||||||||||||||
| 1472 | template object. | ||||||||||||||||||||||||||||||||
| 1473 | 3. The name of the template file. | ||||||||||||||||||||||||||||||||
| 1474 | |||||||||||||||||||||||||||||||||
| 1475 | Here's an example stub for a load_tmpl() callback: | ||||||||||||||||||||||||||||||||
| 1476 | |||||||||||||||||||||||||||||||||
| 1477 | sub my_load_tmpl_callback { | ||||||||||||||||||||||||||||||||
| 1478 | my ($c, $ht_params, $tmpl_params, $tmpl_file) = @_ | ||||||||||||||||||||||||||||||||
| 1479 | # modify $ht_params or $tmpl_params by reference... | ||||||||||||||||||||||||||||||||
| 1480 | } | ||||||||||||||||||||||||||||||||
| 1481 | |||||||||||||||||||||||||||||||||
| 1482 | =head3 param() | ||||||||||||||||||||||||||||||||
| 1483 | |||||||||||||||||||||||||||||||||
| 1484 | $webapp->param('pname', $somevalue); | ||||||||||||||||||||||||||||||||
| 1485 | |||||||||||||||||||||||||||||||||
| 1486 | The param() method provides a facility through which you may set | ||||||||||||||||||||||||||||||||
| 1487 | application instance properties which are accessible throughout | ||||||||||||||||||||||||||||||||
| 1488 | your application. | ||||||||||||||||||||||||||||||||
| 1489 | |||||||||||||||||||||||||||||||||
| 1490 | The param() method may be used in two basic ways. First, you may use it | ||||||||||||||||||||||||||||||||
| 1491 | to get or set the value of a parameter: | ||||||||||||||||||||||||||||||||
| 1492 | |||||||||||||||||||||||||||||||||
| 1493 | $webapp->param('scalar_param', '123'); | ||||||||||||||||||||||||||||||||
| 1494 | my $scalar_param_values = $webapp->param('some_param'); | ||||||||||||||||||||||||||||||||
| 1495 | |||||||||||||||||||||||||||||||||
| 1496 | Second, when called in the context of an array, with no parameter name | ||||||||||||||||||||||||||||||||
| 1497 | specified, param() returns an array containing all the parameters which | ||||||||||||||||||||||||||||||||
| 1498 | currently exist: | ||||||||||||||||||||||||||||||||
| 1499 | |||||||||||||||||||||||||||||||||
| 1500 | my @all_params = $webapp->param(); | ||||||||||||||||||||||||||||||||
| 1501 | |||||||||||||||||||||||||||||||||
| 1502 | The param() method also allows you to set a bunch of parameters at once | ||||||||||||||||||||||||||||||||
| 1503 | by passing in a hash (or hashref): | ||||||||||||||||||||||||||||||||
| 1504 | |||||||||||||||||||||||||||||||||
| 1505 | $webapp->param( | ||||||||||||||||||||||||||||||||
| 1506 | 'key1' => 'val1', | ||||||||||||||||||||||||||||||||
| 1507 | 'key2' => 'val2', | ||||||||||||||||||||||||||||||||
| 1508 | 'key3' => 'val3', | ||||||||||||||||||||||||||||||||
| 1509 | ); | ||||||||||||||||||||||||||||||||
| 1510 | |||||||||||||||||||||||||||||||||
| 1511 | The param() method enables a very valuable system for | ||||||||||||||||||||||||||||||||
| 1512 | customizing your applications on a per-instance basis. | ||||||||||||||||||||||||||||||||
| 1513 | One Application Module might be instantiated by different | ||||||||||||||||||||||||||||||||
| 1514 | Instance Scripts. Each Instance Script might set different values for a | ||||||||||||||||||||||||||||||||
| 1515 | set of parameters. This allows similar applications to share a common | ||||||||||||||||||||||||||||||||
| 1516 | code-base, but behave differently. For example, imagine a mail form | ||||||||||||||||||||||||||||||||
| 1517 | application with a single Application Module, but multiple Instance | ||||||||||||||||||||||||||||||||
| 1518 | Scripts. Each Instance Script might specify a different recipient. | ||||||||||||||||||||||||||||||||
| 1519 | Another example would be a web bulletin boards system. There could be | ||||||||||||||||||||||||||||||||
| 1520 | multiple boards, each with a different topic and set of administrators. | ||||||||||||||||||||||||||||||||
| 1521 | |||||||||||||||||||||||||||||||||
| 1522 | The new() method provides a shortcut for specifying a number of run-time | ||||||||||||||||||||||||||||||||
| 1523 | parameters at once. Internally, CGI::Application calls the param() | ||||||||||||||||||||||||||||||||
| 1524 | method to set these properties. The param() method is a powerful tool for | ||||||||||||||||||||||||||||||||
| 1525 | greatly increasing your application's re-usability. | ||||||||||||||||||||||||||||||||
| 1526 | |||||||||||||||||||||||||||||||||
| 1527 | =head3 query() | ||||||||||||||||||||||||||||||||
| 1528 | |||||||||||||||||||||||||||||||||
| 1529 | my $q = $webapp->query(); | ||||||||||||||||||||||||||||||||
| 1530 | my $remote_user = $q->remote_user(); | ||||||||||||||||||||||||||||||||
| 1531 | |||||||||||||||||||||||||||||||||
| 1532 | This method retrieves the CGI.pm query object which has been created | ||||||||||||||||||||||||||||||||
| 1533 | by instantiating your Application Module. For details on usage of this | ||||||||||||||||||||||||||||||||
| 1534 | query object, refer to L |
||||||||||||||||||||||||||||||||
| 1535 | module. Generally speaking, you will want to become very familiar | ||||||||||||||||||||||||||||||||
| 1536 | with CGI.pm, as you will use the query object whenever you want to | ||||||||||||||||||||||||||||||||
| 1537 | interact with form data. | ||||||||||||||||||||||||||||||||
| 1538 | |||||||||||||||||||||||||||||||||
| 1539 | When the new() method is called, a CGI query object is automatically created. | ||||||||||||||||||||||||||||||||
| 1540 | If, for some reason, you want to use your own CGI query object, the new() | ||||||||||||||||||||||||||||||||
| 1541 | method supports passing in your existing query object on construction using | ||||||||||||||||||||||||||||||||
| 1542 | the QUERY attribute. | ||||||||||||||||||||||||||||||||
| 1543 | |||||||||||||||||||||||||||||||||
| 1544 | There are a few rare situations where you want your own query object to be | ||||||||||||||||||||||||||||||||
| 1545 | used after your Application Module has already been constructed. In that case | ||||||||||||||||||||||||||||||||
| 1546 | you can pass it to c |
||||||||||||||||||||||||||||||||
| 1547 | |||||||||||||||||||||||||||||||||
| 1548 | $webapp->query($new_query_object); | ||||||||||||||||||||||||||||||||
| 1549 | my $q = $webapp->query(); # now uses $new_query_object | ||||||||||||||||||||||||||||||||
| 1550 | |||||||||||||||||||||||||||||||||
| 1551 | =head3 run_modes() | ||||||||||||||||||||||||||||||||
| 1552 | |||||||||||||||||||||||||||||||||
| 1553 | # The common usage: an arrayref of run mode names that exactly match subroutine names | ||||||||||||||||||||||||||||||||
| 1554 | $webapp->run_modes([qw/ | ||||||||||||||||||||||||||||||||
| 1555 | form_display | ||||||||||||||||||||||||||||||||
| 1556 | form_process | ||||||||||||||||||||||||||||||||
| 1557 | /]); | ||||||||||||||||||||||||||||||||
| 1558 | |||||||||||||||||||||||||||||||||
| 1559 | # With a hashref, use a different name or a code ref | ||||||||||||||||||||||||||||||||
| 1560 | $webapp->run_modes( | ||||||||||||||||||||||||||||||||
| 1561 | 'mode1' => 'some_sub_by_name', | ||||||||||||||||||||||||||||||||
| 1562 | 'mode2' => \&some_other_sub_by_ref | ||||||||||||||||||||||||||||||||
| 1563 | ); | ||||||||||||||||||||||||||||||||
| 1564 | |||||||||||||||||||||||||||||||||
| 1565 | This accessor/mutator specifies the dispatch table for the | ||||||||||||||||||||||||||||||||
| 1566 | application states, using the syntax examples above. It returns | ||||||||||||||||||||||||||||||||
| 1567 | the dispatch table as a hash. | ||||||||||||||||||||||||||||||||
| 1568 | |||||||||||||||||||||||||||||||||
| 1569 | The run_modes() method may be called more than once. Additional values passed | ||||||||||||||||||||||||||||||||
| 1570 | into run_modes() will be added to the run modes table. In the case that an | ||||||||||||||||||||||||||||||||
| 1571 | existing run mode is re-defined, the new value will override the existing value. | ||||||||||||||||||||||||||||||||
| 1572 | This behavior might be useful for applications which are created via inheritance | ||||||||||||||||||||||||||||||||
| 1573 | from another application, or some advanced application which modifies its | ||||||||||||||||||||||||||||||||
| 1574 | own capabilities based on user input. | ||||||||||||||||||||||||||||||||
| 1575 | |||||||||||||||||||||||||||||||||
| 1576 | The run() method uses the data in this table to send the application to the | ||||||||||||||||||||||||||||||||
| 1577 | correct function as determined by reading the CGI parameter specified by | ||||||||||||||||||||||||||||||||
| 1578 | mode_param() (defaults to 'rm' for "Run Mode"). These functions are referred | ||||||||||||||||||||||||||||||||
| 1579 | to as "run mode methods". | ||||||||||||||||||||||||||||||||
| 1580 | |||||||||||||||||||||||||||||||||
| 1581 | The hash table set by this method is expected to contain the mode | ||||||||||||||||||||||||||||||||
| 1582 | name as a key. The value should be either a hard reference (a subref) | ||||||||||||||||||||||||||||||||
| 1583 | to the run mode method which you want to be called when the application enters | ||||||||||||||||||||||||||||||||
| 1584 | the specified run mode, or the name of the run mode method to be called: | ||||||||||||||||||||||||||||||||
| 1585 | |||||||||||||||||||||||||||||||||
| 1586 | 'mode_name_by_ref' => \&mode_function | ||||||||||||||||||||||||||||||||
| 1587 | 'mode_name_by_name' => 'mode_function' | ||||||||||||||||||||||||||||||||
| 1588 | |||||||||||||||||||||||||||||||||
| 1589 | The run mode method specified is expected to return a block of text (e.g.: | ||||||||||||||||||||||||||||||||
| 1590 | HTML) which will eventually be sent back to the web browser. The run mode | ||||||||||||||||||||||||||||||||
| 1591 | method may return its block of text as a scalar or a scalar-ref. | ||||||||||||||||||||||||||||||||
| 1592 | |||||||||||||||||||||||||||||||||
| 1593 | An advantage of specifying your run mode methods by name instead of | ||||||||||||||||||||||||||||||||
| 1594 | by reference is that you can more easily create derivative applications | ||||||||||||||||||||||||||||||||
| 1595 | using inheritance. For instance, if you have a new application which is | ||||||||||||||||||||||||||||||||
| 1596 | exactly the same as an existing application with the exception of one | ||||||||||||||||||||||||||||||||
| 1597 | run mode, you could simply inherit from that other application and override | ||||||||||||||||||||||||||||||||
| 1598 | the run mode method which is different. If you specified your run mode | ||||||||||||||||||||||||||||||||
| 1599 | method by reference, your child class would still use the function | ||||||||||||||||||||||||||||||||
| 1600 | from the parent class. | ||||||||||||||||||||||||||||||||
| 1601 | |||||||||||||||||||||||||||||||||
| 1602 | An advantage of specifying your run mode methods by reference instead of by name | ||||||||||||||||||||||||||||||||
| 1603 | is performance. Dereferencing a subref is faster than eval()-ing | ||||||||||||||||||||||||||||||||
| 1604 | a code block. If run-time performance is a critical issue, specify | ||||||||||||||||||||||||||||||||
| 1605 | your run mode methods by reference and not by name. The speed differences | ||||||||||||||||||||||||||||||||
| 1606 | are generally small, however, so specifying by name is preferred. | ||||||||||||||||||||||||||||||||
| 1607 | |||||||||||||||||||||||||||||||||
| 1608 | Specifying the run modes by array reference: | ||||||||||||||||||||||||||||||||
| 1609 | |||||||||||||||||||||||||||||||||
| 1610 | $webapp->run_modes([ 'mode1', 'mode2', 'mode3' ]); | ||||||||||||||||||||||||||||||||
| 1611 | |||||||||||||||||||||||||||||||||
| 1612 | This is the same as using a hash, with keys equal to values | ||||||||||||||||||||||||||||||||
| 1613 | |||||||||||||||||||||||||||||||||
| 1614 | $webapp->run_modes( | ||||||||||||||||||||||||||||||||
| 1615 | 'mode1' => 'mode1', | ||||||||||||||||||||||||||||||||
| 1616 | 'mode2' => 'mode2', | ||||||||||||||||||||||||||||||||
| 1617 | 'mode3' => 'mode3' | ||||||||||||||||||||||||||||||||
| 1618 | ); | ||||||||||||||||||||||||||||||||
| 1619 | |||||||||||||||||||||||||||||||||
| 1620 | Often, it makes good organizational sense to have your run modes map to | ||||||||||||||||||||||||||||||||
| 1621 | methods of the same name. The array-ref interface provides a shortcut | ||||||||||||||||||||||||||||||||
| 1622 | to that behavior while reducing verbosity of your code. | ||||||||||||||||||||||||||||||||
| 1623 | |||||||||||||||||||||||||||||||||
| 1624 | Note that another importance of specifying your run modes in either a | ||||||||||||||||||||||||||||||||
| 1625 | hash or array-ref is to assure that only those Perl methods which are | ||||||||||||||||||||||||||||||||
| 1626 | specifically designated may be called via your application. Application | ||||||||||||||||||||||||||||||||
| 1627 | environments which don't specify allowed methods and disallow all others | ||||||||||||||||||||||||||||||||
| 1628 | are insecure, potentially opening the door to allowing execution of | ||||||||||||||||||||||||||||||||
| 1629 | arbitrary code. CGI::Application maintains a strict "default-deny" stance | ||||||||||||||||||||||||||||||||
| 1630 | on all method invocation, thereby allowing secure applications | ||||||||||||||||||||||||||||||||
| 1631 | to be built upon it. | ||||||||||||||||||||||||||||||||
| 1632 | |||||||||||||||||||||||||||||||||
| 1633 | B |
||||||||||||||||||||||||||||||||
| 1634 | |||||||||||||||||||||||||||||||||
| 1635 | Your application should *NEVER* print() to STDOUT. | ||||||||||||||||||||||||||||||||
| 1636 | Using print() to send output to STDOUT (including HTTP headers) is | ||||||||||||||||||||||||||||||||
| 1637 | exclusively the domain of the inherited run() method. Breaking this | ||||||||||||||||||||||||||||||||
| 1638 | rule is a common source of errors. If your program is erroneously | ||||||||||||||||||||||||||||||||
| 1639 | sending content before your HTTP header, you are probably breaking this rule. | ||||||||||||||||||||||||||||||||
| 1640 | |||||||||||||||||||||||||||||||||
| 1641 | |||||||||||||||||||||||||||||||||
| 1642 | B |
||||||||||||||||||||||||||||||||
| 1643 | |||||||||||||||||||||||||||||||||
| 1644 | If CGI::Application is asked to go to a run mode which doesn't exist | ||||||||||||||||||||||||||||||||
| 1645 | it will usually croak() with errors. If this is not your desired | ||||||||||||||||||||||||||||||||
| 1646 | behavior, it is possible to catch this exception by implementing | ||||||||||||||||||||||||||||||||
| 1647 | a run mode with the reserved name "AUTOLOAD": | ||||||||||||||||||||||||||||||||
| 1648 | |||||||||||||||||||||||||||||||||
| 1649 | $self->run_modes( | ||||||||||||||||||||||||||||||||
| 1650 | "AUTOLOAD" => \&catch_my_exception | ||||||||||||||||||||||||||||||||
| 1651 | ); | ||||||||||||||||||||||||||||||||
| 1652 | |||||||||||||||||||||||||||||||||
| 1653 | Before CGI::Application calls croak() it will check for the existence | ||||||||||||||||||||||||||||||||
| 1654 | of a run mode called "AUTOLOAD". If specified, this run mode will in | ||||||||||||||||||||||||||||||||
| 1655 | invoked just like a regular run mode, with one exception: It will | ||||||||||||||||||||||||||||||||
| 1656 | receive, as an argument, the name of the run mode which invoked it: | ||||||||||||||||||||||||||||||||
| 1657 | |||||||||||||||||||||||||||||||||
| 1658 | sub catch_my_exception { | ||||||||||||||||||||||||||||||||
| 1659 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1660 | my $intended_runmode = shift; | ||||||||||||||||||||||||||||||||
| 1661 | |||||||||||||||||||||||||||||||||
| 1662 | my $output = "Looking for '$intended_runmode', but found 'AUTOLOAD' instead"; | ||||||||||||||||||||||||||||||||
| 1663 | return $output; | ||||||||||||||||||||||||||||||||
| 1664 | } | ||||||||||||||||||||||||||||||||
| 1665 | |||||||||||||||||||||||||||||||||
| 1666 | This functionality could be used for a simple human-readable error | ||||||||||||||||||||||||||||||||
| 1667 | screen, or for more sophisticated application behaviors. | ||||||||||||||||||||||||||||||||
| 1668 | |||||||||||||||||||||||||||||||||
| 1669 | |||||||||||||||||||||||||||||||||
| 1670 | =head3 start_mode() | ||||||||||||||||||||||||||||||||
| 1671 | |||||||||||||||||||||||||||||||||
| 1672 | $webapp->start_mode('mode1'); | ||||||||||||||||||||||||||||||||
| 1673 | |||||||||||||||||||||||||||||||||
| 1674 | The start_mode contains the name of the mode as specified in the run_modes() | ||||||||||||||||||||||||||||||||
| 1675 | table. Default mode is "start". The mode key specified here will be used | ||||||||||||||||||||||||||||||||
| 1676 | whenever the value of the CGI form parameter specified by mode_param() is | ||||||||||||||||||||||||||||||||
| 1677 | not defined. Generally, this is the first time your application is executed. | ||||||||||||||||||||||||||||||||
| 1678 | |||||||||||||||||||||||||||||||||
| 1679 | =head3 tmpl_path() | ||||||||||||||||||||||||||||||||
| 1680 | |||||||||||||||||||||||||||||||||
| 1681 | $webapp->tmpl_path('/path/to/some/templates/'); | ||||||||||||||||||||||||||||||||
| 1682 | |||||||||||||||||||||||||||||||||
| 1683 | This access/mutator method sets the file path to the directory (or directories) | ||||||||||||||||||||||||||||||||
| 1684 | where the templates are stored. It is used by load_tmpl() to find the template | ||||||||||||||||||||||||||||||||
| 1685 | files, using HTML::Template's C |
||||||||||||||||||||||||||||||||
| 1686 | pass in a text scalar or an array reference of multiple paths. | ||||||||||||||||||||||||||||||||
| 1687 | |||||||||||||||||||||||||||||||||
| 1688 | |||||||||||||||||||||||||||||||||
| 1689 | |||||||||||||||||||||||||||||||||
| 1690 | =head2 More Application Methods | ||||||||||||||||||||||||||||||||
| 1691 | |||||||||||||||||||||||||||||||||
| 1692 | You can skip this section if you are just getting started. | ||||||||||||||||||||||||||||||||
| 1693 | |||||||||||||||||||||||||||||||||
| 1694 | The following additional methods are inherited from CGI::Application, and are | ||||||||||||||||||||||||||||||||
| 1695 | available to be called by your application within your Application Module. | ||||||||||||||||||||||||||||||||
| 1696 | These functions are listed in alphabetical order. | ||||||||||||||||||||||||||||||||
| 1697 | |||||||||||||||||||||||||||||||||
| 1698 | =head3 delete() | ||||||||||||||||||||||||||||||||
| 1699 | |||||||||||||||||||||||||||||||||
| 1700 | $webapp->delete('my_param'); | ||||||||||||||||||||||||||||||||
| 1701 | |||||||||||||||||||||||||||||||||
| 1702 | The delete() method is used to delete a parameter that was previously | ||||||||||||||||||||||||||||||||
| 1703 | stored inside of your application either by using the PARAMS hash that | ||||||||||||||||||||||||||||||||
| 1704 | was passed in your call to new() or by a call to the param() method. | ||||||||||||||||||||||||||||||||
| 1705 | This is similar to the delete() method of CGI.pm. It is useful if your | ||||||||||||||||||||||||||||||||
| 1706 | application makes decisions based on the existence of certain params that | ||||||||||||||||||||||||||||||||
| 1707 | may have been removed in previous sections of your app or simply to | ||||||||||||||||||||||||||||||||
| 1708 | clean-up your param()s. | ||||||||||||||||||||||||||||||||
| 1709 | |||||||||||||||||||||||||||||||||
| 1710 | |||||||||||||||||||||||||||||||||
| 1711 | =head3 dump() | ||||||||||||||||||||||||||||||||
| 1712 | |||||||||||||||||||||||||||||||||
| 1713 | print STDERR $webapp->dump(); | ||||||||||||||||||||||||||||||||
| 1714 | |||||||||||||||||||||||||||||||||
| 1715 | The dump() method is a debugging function which will return a | ||||||||||||||||||||||||||||||||
| 1716 | chunk of text which contains all the environment and web form | ||||||||||||||||||||||||||||||||
| 1717 | data of the request, formatted nicely for human readability. | ||||||||||||||||||||||||||||||||
| 1718 | Useful for outputting to STDERR. | ||||||||||||||||||||||||||||||||
| 1719 | |||||||||||||||||||||||||||||||||
| 1720 | |||||||||||||||||||||||||||||||||
| 1721 | =head3 dump_html() | ||||||||||||||||||||||||||||||||
| 1722 | |||||||||||||||||||||||||||||||||
| 1723 | my $output = $webapp->dump_html(); | ||||||||||||||||||||||||||||||||
| 1724 | |||||||||||||||||||||||||||||||||
| 1725 | The dump_html() method is a debugging function which will return | ||||||||||||||||||||||||||||||||
| 1726 | a chunk of text which contains all the environment and web form | ||||||||||||||||||||||||||||||||
| 1727 | data of the request, formatted nicely for human readability via | ||||||||||||||||||||||||||||||||
| 1728 | a web browser. Useful for outputting to a browser. Please consider | ||||||||||||||||||||||||||||||||
| 1729 | the security implications of using this in production code. | ||||||||||||||||||||||||||||||||
| 1730 | |||||||||||||||||||||||||||||||||
| 1731 | =head3 error_mode() | ||||||||||||||||||||||||||||||||
| 1732 | |||||||||||||||||||||||||||||||||
| 1733 | $webapp->error_mode('my_error_rm'); | ||||||||||||||||||||||||||||||||
| 1734 | |||||||||||||||||||||||||||||||||
| 1735 | If the runmode dies for whatever reason, C |
||||||||||||||||||||||||||||||||
| 1736 | value for C |
||||||||||||||||||||||||||||||||
| 1737 | as a run mode, passing $@ as the only parameter. | ||||||||||||||||||||||||||||||||
| 1738 | |||||||||||||||||||||||||||||||||
| 1739 | Plugins authors will be interested to know that just before C |
||||||||||||||||||||||||||||||||
| 1740 | called, the C |
||||||||||||||||||||||||||||||||
| 1741 | the only parameter. | ||||||||||||||||||||||||||||||||
| 1742 | |||||||||||||||||||||||||||||||||
| 1743 | No C |
||||||||||||||||||||||||||||||||
| 1744 | mode is not trapped, so you can also use it to die in your own special way. | ||||||||||||||||||||||||||||||||
| 1745 | |||||||||||||||||||||||||||||||||
| 1746 | For a complete integrated logging solution, check out L |
||||||||||||||||||||||||||||||||
| 1747 | |||||||||||||||||||||||||||||||||
| 1748 | =head3 get_current_runmode() | ||||||||||||||||||||||||||||||||
| 1749 | |||||||||||||||||||||||||||||||||
| 1750 | $webapp->get_current_runmode(); | ||||||||||||||||||||||||||||||||
| 1751 | |||||||||||||||||||||||||||||||||
| 1752 | The C |
||||||||||||||||||||||||||||||||
| 1753 | the name of the run mode which is currently being executed. If the | ||||||||||||||||||||||||||||||||
| 1754 | run mode has not yet been determined, such as during setup(), this method | ||||||||||||||||||||||||||||||||
| 1755 | will return undef. | ||||||||||||||||||||||||||||||||
| 1756 | |||||||||||||||||||||||||||||||||
| 1757 | =head3 header_add() | ||||||||||||||||||||||||||||||||
| 1758 | |||||||||||||||||||||||||||||||||
| 1759 | # add or replace the 'type' header | ||||||||||||||||||||||||||||||||
| 1760 | $webapp->header_add( -type => 'image/png' ); | ||||||||||||||||||||||||||||||||
| 1761 | |||||||||||||||||||||||||||||||||
| 1762 | - or - | ||||||||||||||||||||||||||||||||
| 1763 | |||||||||||||||||||||||||||||||||
| 1764 | # add an additional cookie | ||||||||||||||||||||||||||||||||
| 1765 | $webapp->header_add(-cookie=>[$extra_cookie]); | ||||||||||||||||||||||||||||||||
| 1766 | |||||||||||||||||||||||||||||||||
| 1767 | The C |
||||||||||||||||||||||||||||||||
| 1768 | response headers. The parameters will eventually be passed on to the CGI.pm | ||||||||||||||||||||||||||||||||
| 1769 | header() method, so refer to the L |
||||||||||||||||||||||||||||||||
| 1770 | |||||||||||||||||||||||||||||||||
| 1771 | Unlike calling C |
||||||||||||||||||||||||||||||||
| 1772 | headers. If a scalar value is passed to C |
||||||||||||||||||||||||||||||||
| 1773 | the existing value for that key. | ||||||||||||||||||||||||||||||||
| 1774 | |||||||||||||||||||||||||||||||||
| 1775 | If an array reference is passed as a value to C |
||||||||||||||||||||||||||||||||
| 1776 | that array ref will be appended to any existing values for that key. | ||||||||||||||||||||||||||||||||
| 1777 | This is primarily useful for setting an additional cookie after one has already | ||||||||||||||||||||||||||||||||
| 1778 | been set. | ||||||||||||||||||||||||||||||||
| 1779 | |||||||||||||||||||||||||||||||||
| 1780 | =head3 header_props() | ||||||||||||||||||||||||||||||||
| 1781 | |||||||||||||||||||||||||||||||||
| 1782 | # Set a complete set of headers | ||||||||||||||||||||||||||||||||
| 1783 | %set_headers = $webapp->header_props(-type=>'image/gif',-expires=>'+3d'); | ||||||||||||||||||||||||||||||||
| 1784 | |||||||||||||||||||||||||||||||||
| 1785 | # clobber / reset all headers | ||||||||||||||||||||||||||||||||
| 1786 | %set_headers = $webapp->header_props({}); | ||||||||||||||||||||||||||||||||
| 1787 | |||||||||||||||||||||||||||||||||
| 1788 | # Just retrieve the headers | ||||||||||||||||||||||||||||||||
| 1789 | %set_headers = $webapp->header_props(); | ||||||||||||||||||||||||||||||||
| 1790 | |||||||||||||||||||||||||||||||||
| 1791 | The C |
||||||||||||||||||||||||||||||||
| 1792 | HTTP header properties. These properties will be passed directly | ||||||||||||||||||||||||||||||||
| 1793 | to the C |
||||||||||||||||||||||||||||||||
| 1794 | to the docs of your query object for details. (Be default, it's L |
||||||||||||||||||||||||||||||||
| 1795 | |||||||||||||||||||||||||||||||||
| 1796 | Calling header_props with an empty hashref clobber any existing headers that have | ||||||||||||||||||||||||||||||||
| 1797 | previously set. | ||||||||||||||||||||||||||||||||
| 1798 | |||||||||||||||||||||||||||||||||
| 1799 | C |
||||||||||||||||||||||||||||||||
| 1800 | set. It can be called with no arguments just to get the hash current headers | ||||||||||||||||||||||||||||||||
| 1801 | back. | ||||||||||||||||||||||||||||||||
| 1802 | |||||||||||||||||||||||||||||||||
| 1803 | To add additional headers later without clobbering the old ones, | ||||||||||||||||||||||||||||||||
| 1804 | see C |
||||||||||||||||||||||||||||||||
| 1805 | |||||||||||||||||||||||||||||||||
| 1806 | B |
||||||||||||||||||||||||||||||||
| 1807 | |||||||||||||||||||||||||||||||||
| 1808 | It is through the C |
||||||||||||||||||||||||||||||||
| 1809 | HTTP headers. This is necessary when you want to set a cookie, set the mime | ||||||||||||||||||||||||||||||||
| 1810 | type to something other than "text/html", or perform a redirect. The | ||||||||||||||||||||||||||||||||
| 1811 | header_props() method works in conjunction with the header_type() method. | ||||||||||||||||||||||||||||||||
| 1812 | The value contained in header_type() determines if we use CGI::header() or | ||||||||||||||||||||||||||||||||
| 1813 | CGI::redirect(). The content of header_props() is passed as an argument to | ||||||||||||||||||||||||||||||||
| 1814 | whichever CGI.pm function is called. | ||||||||||||||||||||||||||||||||
| 1815 | |||||||||||||||||||||||||||||||||
| 1816 | Understanding this relationship is important if you wish to manipulate | ||||||||||||||||||||||||||||||||
| 1817 | the HTTP header properly. | ||||||||||||||||||||||||||||||||
| 1818 | |||||||||||||||||||||||||||||||||
| 1819 | =head3 header_type() | ||||||||||||||||||||||||||||||||
| 1820 | |||||||||||||||||||||||||||||||||
| 1821 | $webapp->header_type('redirect'); | ||||||||||||||||||||||||||||||||
| 1822 | $webapp->header_type('none'); | ||||||||||||||||||||||||||||||||
| 1823 | |||||||||||||||||||||||||||||||||
| 1824 | This method used to declare that you are setting a redirection header, | ||||||||||||||||||||||||||||||||
| 1825 | or that you want no header to be returned by the framework. | ||||||||||||||||||||||||||||||||
| 1826 | |||||||||||||||||||||||||||||||||
| 1827 | The value of 'header' is almost never used, as it is the default. | ||||||||||||||||||||||||||||||||
| 1828 | |||||||||||||||||||||||||||||||||
| 1829 | B |
||||||||||||||||||||||||||||||||
| 1830 | |||||||||||||||||||||||||||||||||
| 1831 | sub some_redirect_mode { | ||||||||||||||||||||||||||||||||
| 1832 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1833 | # do stuff here.... | ||||||||||||||||||||||||||||||||
| 1834 | $self->header_type('redirect'); | ||||||||||||||||||||||||||||||||
| 1835 | $self->header_props(-url=> "http://site/path/doc.html" ); | ||||||||||||||||||||||||||||||||
| 1836 | } | ||||||||||||||||||||||||||||||||
| 1837 | |||||||||||||||||||||||||||||||||
| 1838 | To simplify that further, use L |
||||||||||||||||||||||||||||||||
| 1839 | |||||||||||||||||||||||||||||||||
| 1840 | return $self->redirect('http://www.example.com/'); | ||||||||||||||||||||||||||||||||
| 1841 | |||||||||||||||||||||||||||||||||
| 1842 | Setting the header to 'none' may be useful if you are streaming content. | ||||||||||||||||||||||||||||||||
| 1843 | In other contexts, it may be more useful to set C<$ENV{CGI_APP_RETURN_ONLY} = 1;>, | ||||||||||||||||||||||||||||||||
| 1844 | which suppresses all printing, including headers, and returns the output instead. | ||||||||||||||||||||||||||||||||
| 1845 | |||||||||||||||||||||||||||||||||
| 1846 | That's commonly used for testing, or when using L |
||||||||||||||||||||||||||||||||
| 1847 | for a cron script! | ||||||||||||||||||||||||||||||||
| 1848 | |||||||||||||||||||||||||||||||||
| 1849 | =cut | ||||||||||||||||||||||||||||||||
| 1850 | |||||||||||||||||||||||||||||||||
| 1851 | sub html_tmpl_class { | ||||||||||||||||||||||||||||||||
| 1852 | 7 | 7 | 0 | 14 | my $self = shift; | ||||||||||||||||||||||||||||
| 1853 | 7 | 10 | my $tmpl_class = shift; | ||||||||||||||||||||||||||||||
| 1854 | |||||||||||||||||||||||||||||||||
| 1855 | # First use? Create new __ERROR_MODE | ||||||||||||||||||||||||||||||||
| 1856 | 7 | 100 | 22 | $self->{__HTML_TMPL_CLASS} = 'HTML::Template' unless (exists($self->{__HTML_TMPL_CLASS})); | |||||||||||||||||||||||||||||
| 1857 | |||||||||||||||||||||||||||||||||
| 1858 | 7 | 50 | 15 | if (defined $tmpl_class) { | |||||||||||||||||||||||||||||
| 1859 | 0 | 0 | $self->{__HTML_TMPL_CLASS} = $tmpl_class; | ||||||||||||||||||||||||||||||
| 1860 | } | ||||||||||||||||||||||||||||||||
| 1861 | |||||||||||||||||||||||||||||||||
| 1862 | 7 | 13 | return $self->{__HTML_TMPL_CLASS}; | ||||||||||||||||||||||||||||||
| 1863 | } | ||||||||||||||||||||||||||||||||
| 1864 | |||||||||||||||||||||||||||||||||
| 1865 | sub load_tmpl { | ||||||||||||||||||||||||||||||||
| 1866 | 7 | 7 | 1 | 1091 | my $self = shift; | ||||||||||||||||||||||||||||
| 1867 | 7 | 17 | my ($tmpl_file, @extra_params) = @_; | ||||||||||||||||||||||||||||||
| 1868 | |||||||||||||||||||||||||||||||||
| 1869 | # add tmpl_path to path array if one is set, otherwise add a path arg | ||||||||||||||||||||||||||||||||
| 1870 | 7 | 100 | 26 | if (my $tmpl_path = $self->tmpl_path) { | |||||||||||||||||||||||||||||
| 1871 | 6 | 100 | 20 | my @tmpl_paths = (ref $tmpl_path eq 'ARRAY') ? @$tmpl_path : $tmpl_path; | |||||||||||||||||||||||||||||
| 1872 | 6 | 12 | my $found = 0; | ||||||||||||||||||||||||||||||
| 1873 | 6 | 19 | for( my $x = 0; $x < @extra_params; $x += 2 ) { | ||||||||||||||||||||||||||||||
| 1874 | 2 | 50 | 33 | 12 | if ($extra_params[$x] eq 'path' and | ||||||||||||||||||||||||||||
| 1875 | ref $extra_params[$x+1] eq 'ARRAY') { | ||||||||||||||||||||||||||||||||
| 1876 | 0 | 0 | unshift @{$extra_params[$x+1]}, @tmpl_paths; | ||||||||||||||||||||||||||||||
| 0 | 0 | ||||||||||||||||||||||||||||||||
| 1877 | 0 | 0 | $found = 1; | ||||||||||||||||||||||||||||||
| 1878 | 0 | 0 | last; | ||||||||||||||||||||||||||||||
| 1879 | } | ||||||||||||||||||||||||||||||||
| 1880 | } | ||||||||||||||||||||||||||||||||
| 1881 | 6 | 50 | 29 | push(@extra_params, path => [ @tmpl_paths ]) unless $found; | |||||||||||||||||||||||||||||
| 1882 | } | ||||||||||||||||||||||||||||||||
| 1883 | |||||||||||||||||||||||||||||||||
| 1884 | 7 | 15 | my %tmpl_params = (); | ||||||||||||||||||||||||||||||
| 1885 | 7 | 16 | my %ht_params = @extra_params; | ||||||||||||||||||||||||||||||
| 1886 | 7 | 100 | 20 | %ht_params = () unless keys %ht_params; | |||||||||||||||||||||||||||||
| 1887 | |||||||||||||||||||||||||||||||||
| 1888 | # Define our extension if doesn't already exist; | ||||||||||||||||||||||||||||||||
| 1889 | 7 | 100 | 26 | $self->{__CURRENT_TMPL_EXTENSION} = '.html' unless defined $self->{__CURRENT_TMPL_EXTENSION}; | |||||||||||||||||||||||||||||
| 1890 | |||||||||||||||||||||||||||||||||
| 1891 | # Define a default template name based on the current run mode | ||||||||||||||||||||||||||||||||
| 1892 | 7 | 50 | 39 | unless (defined $tmpl_file) { | |||||||||||||||||||||||||||||
| 1893 | 0 | 0 | $tmpl_file = $self->get_current_runmode . $self->{__CURRENT_TMPL_EXTENSION}; | ||||||||||||||||||||||||||||||
| 1894 | } | ||||||||||||||||||||||||||||||||
| 1895 | |||||||||||||||||||||||||||||||||
| 1896 | 7 | 23 | $self->call_hook('load_tmpl', \%ht_params, \%tmpl_params, $tmpl_file); | ||||||||||||||||||||||||||||||
| 1897 | |||||||||||||||||||||||||||||||||
| 1898 | 7 | 25 | my $ht_class = $self->html_tmpl_class; | ||||||||||||||||||||||||||||||
| 1899 | 7 | 50 | 374 | eval "require $ht_class;" || die "require $ht_class failed: $@"; | |||||||||||||||||||||||||||||
| 1900 | |||||||||||||||||||||||||||||||||
| 1901 | # let's check $tmpl_file and see what kind of parameter it is - we | ||||||||||||||||||||||||||||||||
| 1902 | # now support 3 options: scalar (filename), ref to scalar (the | ||||||||||||||||||||||||||||||||
| 1903 | # actual html/template content) and reference to FILEHANDLE | ||||||||||||||||||||||||||||||||
| 1904 | 7 | 35214 | my $t = undef; | ||||||||||||||||||||||||||||||
| 1905 | 7 | 50 | 34 | if ( ref $tmpl_file eq 'SCALAR' ) { | |||||||||||||||||||||||||||||
| 50 | |||||||||||||||||||||||||||||||||
| 1906 | 0 | 0 | $t = $ht_class->new( scalarref => $tmpl_file, %ht_params ); | ||||||||||||||||||||||||||||||
| 1907 | } elsif ( ref $tmpl_file eq 'GLOB' ) { | ||||||||||||||||||||||||||||||||
| 1908 | 0 | 0 | $t = $ht_class->new( filehandle => $tmpl_file, %ht_params ); | ||||||||||||||||||||||||||||||
| 1909 | } else { | ||||||||||||||||||||||||||||||||
| 1910 | 7 | 69 | $t = $ht_class->new( filename => $tmpl_file, %ht_params); | ||||||||||||||||||||||||||||||
| 1911 | } | ||||||||||||||||||||||||||||||||
| 1912 | |||||||||||||||||||||||||||||||||
| 1913 | 7 | 100 | 3208 | if (keys %tmpl_params) { | |||||||||||||||||||||||||||||
| 1914 | 1 | 5 | $t->param(%tmpl_params); | ||||||||||||||||||||||||||||||
| 1915 | } | ||||||||||||||||||||||||||||||||
| 1916 | |||||||||||||||||||||||||||||||||
| 1917 | 7 | 57 | return $t; | ||||||||||||||||||||||||||||||
| 1918 | } | ||||||||||||||||||||||||||||||||
| 1919 | |||||||||||||||||||||||||||||||||
| 1920 | =pod | ||||||||||||||||||||||||||||||||
| 1921 | |||||||||||||||||||||||||||||||||
| 1922 | =head3 mode_param() | ||||||||||||||||||||||||||||||||
| 1923 | |||||||||||||||||||||||||||||||||
| 1924 | # Name the CGI form parameter that contains the run mode name. | ||||||||||||||||||||||||||||||||
| 1925 | # This is the default behavior, and is often sufficient. | ||||||||||||||||||||||||||||||||
| 1926 | $webapp->mode_param('rm'); | ||||||||||||||||||||||||||||||||
| 1927 | |||||||||||||||||||||||||||||||||
| 1928 | # Set the run mode name directly from a code ref | ||||||||||||||||||||||||||||||||
| 1929 | $webapp->mode_param(\&some_method); | ||||||||||||||||||||||||||||||||
| 1930 | |||||||||||||||||||||||||||||||||
| 1931 | # Alternate interface, which allows you to set the run | ||||||||||||||||||||||||||||||||
| 1932 | # mode name directly from $ENV{PATH_INFO}. | ||||||||||||||||||||||||||||||||
| 1933 | $webapp->mode_param( | ||||||||||||||||||||||||||||||||
| 1934 | path_info=> 1, | ||||||||||||||||||||||||||||||||
| 1935 | param =>'rm' | ||||||||||||||||||||||||||||||||
| 1936 | ); | ||||||||||||||||||||||||||||||||
| 1937 | |||||||||||||||||||||||||||||||||
| 1938 | This accessor/mutator method is generally called in the setup() method. | ||||||||||||||||||||||||||||||||
| 1939 | It is used to help determine the run mode to call. There are three options for calling it. | ||||||||||||||||||||||||||||||||
| 1940 | |||||||||||||||||||||||||||||||||
| 1941 | $webapp->mode_param('rm'); | ||||||||||||||||||||||||||||||||
| 1942 | |||||||||||||||||||||||||||||||||
| 1943 | Here, a CGI form parameter is named that will contain the name of the run mode | ||||||||||||||||||||||||||||||||
| 1944 | to use. This is the default behavior, with 'rm' being the parameter named used. | ||||||||||||||||||||||||||||||||
| 1945 | |||||||||||||||||||||||||||||||||
| 1946 | $webapp->mode_param(\&some_method); | ||||||||||||||||||||||||||||||||
| 1947 | |||||||||||||||||||||||||||||||||
| 1948 | Here a code reference is provided. It will return the name of the run mode | ||||||||||||||||||||||||||||||||
| 1949 | to use directly. Example: | ||||||||||||||||||||||||||||||||
| 1950 | |||||||||||||||||||||||||||||||||
| 1951 | sub some_method { | ||||||||||||||||||||||||||||||||
| 1952 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 1953 | return 'run_mode_x'; | ||||||||||||||||||||||||||||||||
| 1954 | } | ||||||||||||||||||||||||||||||||
| 1955 | |||||||||||||||||||||||||||||||||
| 1956 | This would allow you to programmatically set the run mode based on arbitrary logic. | ||||||||||||||||||||||||||||||||
| 1957 | |||||||||||||||||||||||||||||||||
| 1958 | $webapp->mode_param( | ||||||||||||||||||||||||||||||||
| 1959 | path_info=> 1, | ||||||||||||||||||||||||||||||||
| 1960 | param =>'rm' | ||||||||||||||||||||||||||||||||
| 1961 | ); | ||||||||||||||||||||||||||||||||
| 1962 | |||||||||||||||||||||||||||||||||
| 1963 | This syntax allows you to easily set the run mode from $ENV{PATH_INFO}. It | ||||||||||||||||||||||||||||||||
| 1964 | will try to set the run mode from the first part of $ENV{PATH_INFO} (before the | ||||||||||||||||||||||||||||||||
| 1965 | first "/"). To specify that you would rather get the run mode name from the 2nd | ||||||||||||||||||||||||||||||||
| 1966 | part of $ENV{PATH_INFO}: | ||||||||||||||||||||||||||||||||
| 1967 | |||||||||||||||||||||||||||||||||
| 1968 | $webapp->mode_param( path_info=> 2 ); | ||||||||||||||||||||||||||||||||
| 1969 | |||||||||||||||||||||||||||||||||
| 1970 | This also demonstrates that you don't need to pass in the C hash key. It will | ||||||||||||||||||||||||||||||||
| 1971 | still default to C |
||||||||||||||||||||||||||||||||
| 1972 | |||||||||||||||||||||||||||||||||
| 1973 | You can also set C |
||||||||||||||||||||||||||||||||
| 1974 | list index: if it is -1 the run mode name will be taken from the last part of | ||||||||||||||||||||||||||||||||
| 1975 | $ENV{PATH_INFO}, if it is -2, the one before that, and so on. | ||||||||||||||||||||||||||||||||
| 1976 | |||||||||||||||||||||||||||||||||
| 1977 | |||||||||||||||||||||||||||||||||
| 1978 | If no run mode is found in $ENV{PATH_INFO}, it will fall back to looking in the | ||||||||||||||||||||||||||||||||
| 1979 | value of a the CGI form field defined with 'param', as described above. This | ||||||||||||||||||||||||||||||||
| 1980 | allows you to use the convenient $ENV{PATH_INFO} trick most of the time, but | ||||||||||||||||||||||||||||||||
| 1981 | also supports the edge cases, such as when you don't know what the run mode | ||||||||||||||||||||||||||||||||
| 1982 | will be ahead of time and want to define it with JavaScript. | ||||||||||||||||||||||||||||||||
| 1983 | |||||||||||||||||||||||||||||||||
| 1984 | B |
||||||||||||||||||||||||||||||||
| 1985 | |||||||||||||||||||||||||||||||||
| 1986 | Using $ENV{PATH_INFO} to name your run mode creates a clean separation between | ||||||||||||||||||||||||||||||||
| 1987 | the form variables you submit and how you determine the processing run mode. It | ||||||||||||||||||||||||||||||||
| 1988 | also creates URLs that are more search engine friendly. Let's look at an | ||||||||||||||||||||||||||||||||
| 1989 | example form submission using this syntax: | ||||||||||||||||||||||||||||||||
| 1990 | |||||||||||||||||||||||||||||||||
| 1991 | |||||||||||||||||||||||||||||||||
| 1992 | |||||||||||||||||||||||||||||||||
| 1993 | |||||||||||||||||||||||||||||||||
| 1994 | Here the run mode would be set to "edit_form". Here's another example with a | ||||||||||||||||||||||||||||||||
| 1995 | query string: | ||||||||||||||||||||||||||||||||
| 1996 | |||||||||||||||||||||||||||||||||
| 1997 | /cgi-bin/instance.cgi/edit_form?breed_id=2 | ||||||||||||||||||||||||||||||||
| 1998 | |||||||||||||||||||||||||||||||||
| 1999 | This demonstrates that you can use $ENV{PATH_INFO} and a query string together | ||||||||||||||||||||||||||||||||
| 2000 | without problems. $ENV{PATH_INFO} is defined as part of the CGI specification | ||||||||||||||||||||||||||||||||
| 2001 | should be supported by any web server that supports CGI scripts. | ||||||||||||||||||||||||||||||||
| 2002 | |||||||||||||||||||||||||||||||||
| 2003 | =cut | ||||||||||||||||||||||||||||||||
| 2004 | |||||||||||||||||||||||||||||||||
| 2005 | sub mode_param { | ||||||||||||||||||||||||||||||||
| 2006 | 172 | 172 | 1 | 332 | my $self = shift; | ||||||||||||||||||||||||||||
| 2007 | 172 | 234 | my $mode_param; | ||||||||||||||||||||||||||||||
| 2008 | |||||||||||||||||||||||||||||||||
| 2009 | # First use? Create new __MODE_PARAM | ||||||||||||||||||||||||||||||||
| 2010 | 172 | 100 | 392 | $self->{__MODE_PARAM} = 'rm' unless (exists($self->{__MODE_PARAM})); | |||||||||||||||||||||||||||||
| 2011 | |||||||||||||||||||||||||||||||||
| 2012 | 172 | 247 | my %p; | ||||||||||||||||||||||||||||||
| 2013 | # expecting a scalar or code ref | ||||||||||||||||||||||||||||||||
| 2014 | 172 | 100 | 391 | if ((scalar @_) == 1) { | |||||||||||||||||||||||||||||
| 2015 | 104 | 305 | $mode_param = $_[0]; | ||||||||||||||||||||||||||||||
| 2016 | } | ||||||||||||||||||||||||||||||||
| 2017 | # expecting hash style params | ||||||||||||||||||||||||||||||||
| 2018 | else { | ||||||||||||||||||||||||||||||||
| 2019 | 68 | 50 | 184 | croak("CGI::Application->mode_param() : You gave me an odd number of parameters to mode_param()!") | |||||||||||||||||||||||||||||
| 2020 | unless ((@_ % 2) == 0); | ||||||||||||||||||||||||||||||||
| 2021 | 68 | 125 | %p = @_; | ||||||||||||||||||||||||||||||
| 2022 | 68 | 112 | $mode_param = $p{param}; | ||||||||||||||||||||||||||||||
| 2023 | |||||||||||||||||||||||||||||||||
| 2024 | 68 | 100 | 100 | 214 | if ( $p{path_info} && $self->query->path_info() ) { | ||||||||||||||||||||||||||||
| 2025 | 4 | 202 | my $pi = $self->query->path_info(); | ||||||||||||||||||||||||||||||
| 2026 | |||||||||||||||||||||||||||||||||
| 2027 | 4 | 38 | my $idx = $p{path_info}; | ||||||||||||||||||||||||||||||
| 2028 | # two cases: negative or positive index | ||||||||||||||||||||||||||||||||
| 2029 | # negative index counts from the end of path_info | ||||||||||||||||||||||||||||||||
| 2030 | # positive index needs to be fixed because | ||||||||||||||||||||||||||||||||
| 2031 | # computer scientists like to start counting from zero. | ||||||||||||||||||||||||||||||||
| 2032 | 4 | 100 | 15 | $idx -= 1 if ($idx > 0) ; | |||||||||||||||||||||||||||||
| 2033 | |||||||||||||||||||||||||||||||||
| 2034 | # remove the leading slash | ||||||||||||||||||||||||||||||||
| 2035 | 4 | 17 | $pi =~ s!^/!!; | ||||||||||||||||||||||||||||||
| 2036 | |||||||||||||||||||||||||||||||||
| 2037 | # grab the requested field location | ||||||||||||||||||||||||||||||||
| 2038 | 4 | 50 | 15 | $pi = (split q'/', $pi)[$idx] || ''; | |||||||||||||||||||||||||||||
| 2039 | |||||||||||||||||||||||||||||||||
| 2040 | 4 | 50 | 14 | $mode_param = (length $pi) ? { run_mode => $pi } : $mode_param; | |||||||||||||||||||||||||||||
| 2041 | } | ||||||||||||||||||||||||||||||||
| 2042 | |||||||||||||||||||||||||||||||||
| 2043 | } | ||||||||||||||||||||||||||||||||
| 2044 | |||||||||||||||||||||||||||||||||
| 2045 | # If data is provided, set it | ||||||||||||||||||||||||||||||||
| 2046 | 172 | 100 | 66 | 638 | if (defined $mode_param and length $mode_param) { | ||||||||||||||||||||||||||||
| 2047 | 109 | 172 | $self->{__MODE_PARAM} = $mode_param; | ||||||||||||||||||||||||||||||
| 2048 | } | ||||||||||||||||||||||||||||||||
| 2049 | |||||||||||||||||||||||||||||||||
| 2050 | 172 | 337 | return $self->{__MODE_PARAM}; | ||||||||||||||||||||||||||||||
| 2051 | } | ||||||||||||||||||||||||||||||||
| 2052 | |||||||||||||||||||||||||||||||||
| 2053 | |||||||||||||||||||||||||||||||||
| 2054 | =head3 prerun_mode() | ||||||||||||||||||||||||||||||||
| 2055 | |||||||||||||||||||||||||||||||||
| 2056 | $webapp->prerun_mode('new_run_mode'); | ||||||||||||||||||||||||||||||||
| 2057 | |||||||||||||||||||||||||||||||||
| 2058 | The prerun_mode() method is an accessor/mutator which can be used within | ||||||||||||||||||||||||||||||||
| 2059 | your cgiapp_prerun() method to change the run mode which is about to be executed. | ||||||||||||||||||||||||||||||||
| 2060 | For example, consider: | ||||||||||||||||||||||||||||||||
| 2061 | |||||||||||||||||||||||||||||||||
| 2062 | # In WebApp.pm: | ||||||||||||||||||||||||||||||||
| 2063 | package WebApp; | ||||||||||||||||||||||||||||||||
| 2064 | use base 'CGI::Application'; | ||||||||||||||||||||||||||||||||
| 2065 | sub cgiapp_prerun { | ||||||||||||||||||||||||||||||||
| 2066 | my $self = shift; | ||||||||||||||||||||||||||||||||
| 2067 | |||||||||||||||||||||||||||||||||
| 2068 | # Get the web user name, if any | ||||||||||||||||||||||||||||||||
| 2069 | my $q = $self->query(); | ||||||||||||||||||||||||||||||||
| 2070 | my $user = $q->remote_user(); | ||||||||||||||||||||||||||||||||
| 2071 | |||||||||||||||||||||||||||||||||
| 2072 | # Redirect to login, if necessary | ||||||||||||||||||||||||||||||||
| 2073 | unless ($user) { | ||||||||||||||||||||||||||||||||
| 2074 | $self->prerun_mode('login'); | ||||||||||||||||||||||||||||||||
| 2075 | } | ||||||||||||||||||||||||||||||||
| 2076 | } | ||||||||||||||||||||||||||||||||
| 2077 | |||||||||||||||||||||||||||||||||
| 2078 | |||||||||||||||||||||||||||||||||
| 2079 | In this example, the web user will be forced into the "login" run mode | ||||||||||||||||||||||||||||||||
| 2080 | unless they have already logged in. The prerun_mode() method permits | ||||||||||||||||||||||||||||||||
| 2081 | a scalar text string to be set which overrides whatever the run mode | ||||||||||||||||||||||||||||||||
| 2082 | would otherwise be. | ||||||||||||||||||||||||||||||||
| 2083 | |||||||||||||||||||||||||||||||||
| 2084 | The use of prerun_mode() within cgiapp_prerun() differs from setting | ||||||||||||||||||||||||||||||||
| 2085 | mode_param() to use a call-back via subroutine reference. It differs | ||||||||||||||||||||||||||||||||
| 2086 | because cgiapp_prerun() allows you to selectively set the run mode based | ||||||||||||||||||||||||||||||||
| 2087 | on some logic in your cgiapp_prerun() method. The call-back facility of | ||||||||||||||||||||||||||||||||
| 2088 | mode_param() forces you to entirely replace CGI::Application's mechanism | ||||||||||||||||||||||||||||||||
| 2089 | for determining the run mode with your own method. The prerun_mode() | ||||||||||||||||||||||||||||||||
| 2090 | method should be used in cases where you want to use CGI::Application's | ||||||||||||||||||||||||||||||||
| 2091 | normal run mode switching facility, but you want to make selective | ||||||||||||||||||||||||||||||||
| 2092 | changes to the mode under specific conditions. | ||||||||||||||||||||||||||||||||
| 2093 | |||||||||||||||||||||||||||||||||
| 2094 | B |
||||||||||||||||||||||||||||||||
| 2095 | a cgiapp_prerun() method. Your application will die() if you call | ||||||||||||||||||||||||||||||||
| 2096 | prerun_mode() elsewhere, such as in setup() or a run mode method. | ||||||||||||||||||||||||||||||||
| 2097 | |||||||||||||||||||||||||||||||||
| 2098 | =head2 Dispatching Clean URIs to run modes | ||||||||||||||||||||||||||||||||
| 2099 | |||||||||||||||||||||||||||||||||
| 2100 | Modern web frameworks dispense with cruft in URIs, providing in clean | ||||||||||||||||||||||||||||||||
| 2101 | URIs instead. Instead of: | ||||||||||||||||||||||||||||||||
| 2102 | |||||||||||||||||||||||||||||||||
| 2103 | /cgi-bin/item.cgi?rm=view&id=15 | ||||||||||||||||||||||||||||||||
| 2104 | |||||||||||||||||||||||||||||||||
| 2105 | A clean URI to describe the same resource might be: | ||||||||||||||||||||||||||||||||
| 2106 | |||||||||||||||||||||||||||||||||
| 2107 | /item/15/view | ||||||||||||||||||||||||||||||||
| 2108 | |||||||||||||||||||||||||||||||||
| 2109 | The process of mapping these URIs to run modes is called dispatching and is | ||||||||||||||||||||||||||||||||
| 2110 | handled by L |
||||||||||||||||||||||||||||||||
| 2111 | layer you can fairly easily add to an application later. | ||||||||||||||||||||||||||||||||
| 2112 | |||||||||||||||||||||||||||||||||
| 2113 | =head2 Offline website development | ||||||||||||||||||||||||||||||||
| 2114 | |||||||||||||||||||||||||||||||||
| 2115 | You can work on your CGI::Application project on your desktop or laptop without | ||||||||||||||||||||||||||||||||
| 2116 | installing a full-featured web-server like Apache. Instead, install | ||||||||||||||||||||||||||||||||
| 2117 | L |
||||||||||||||||||||||||||||||||
| 2118 | have your own private application server up and running. | ||||||||||||||||||||||||||||||||
| 2119 | |||||||||||||||||||||||||||||||||
| 2120 | =head2 Automated Testing | ||||||||||||||||||||||||||||||||
| 2121 | |||||||||||||||||||||||||||||||||
| 2122 | L |
||||||||||||||||||||||||||||||||
| 2123 | without starting a web server. L |
||||||||||||||||||||||||||||||||
| 2124 | through a real web server. | ||||||||||||||||||||||||||||||||
| 2125 | |||||||||||||||||||||||||||||||||
| 2126 | Direct testing is also easy. CGI::Application will normally print the output of it's | ||||||||||||||||||||||||||||||||
| 2127 | run modes directly to STDOUT. This can be suppressed with an environment variable, | ||||||||||||||||||||||||||||||||
| 2128 | CGI_APP_RETURN_ONLY. For example: | ||||||||||||||||||||||||||||||||
| 2129 | |||||||||||||||||||||||||||||||||
| 2130 | $ENV{CGI_APP_RETURN_ONLY} = 1; | ||||||||||||||||||||||||||||||||
| 2131 | $output = $webapp->run(); | ||||||||||||||||||||||||||||||||
| 2132 | like($output, qr/good/, "output is good"); | ||||||||||||||||||||||||||||||||
| 2133 | |||||||||||||||||||||||||||||||||
| 2134 | Examples of this style can be seen in our own test suite. | ||||||||||||||||||||||||||||||||
| 2135 | |||||||||||||||||||||||||||||||||
| 2136 | =head1 PLUG-INS | ||||||||||||||||||||||||||||||||
| 2137 | |||||||||||||||||||||||||||||||||
| 2138 | CGI::Application has a plug-in architecture that is easy to use and easy | ||||||||||||||||||||||||||||||||
| 2139 | to develop new plug-ins for. | ||||||||||||||||||||||||||||||||
| 2140 | |||||||||||||||||||||||||||||||||
| 2141 | =head2 Recommended Plug-ins | ||||||||||||||||||||||||||||||||
| 2142 | |||||||||||||||||||||||||||||||||
| 2143 | The following plugins are recommended for general purpose web/db development: | ||||||||||||||||||||||||||||||||
| 2144 | |||||||||||||||||||||||||||||||||
| 2145 | =over 4 | ||||||||||||||||||||||||||||||||
| 2146 | |||||||||||||||||||||||||||||||||
| 2147 | =item * | ||||||||||||||||||||||||||||||||
| 2148 | |||||||||||||||||||||||||||||||||
| 2149 | L |
||||||||||||||||||||||||||||||||
| 2150 | |||||||||||||||||||||||||||||||||
| 2151 | =item * | ||||||||||||||||||||||||||||||||
| 2152 | |||||||||||||||||||||||||||||||||
| 2153 | L |
||||||||||||||||||||||||||||||||
| 2154 | |||||||||||||||||||||||||||||||||
| 2155 | =item * | ||||||||||||||||||||||||||||||||
| 2156 | |||||||||||||||||||||||||||||||||
| 2157 | L |
||||||||||||||||||||||||||||||||
| 2158 | |||||||||||||||||||||||||||||||||
| 2159 | =item * | ||||||||||||||||||||||||||||||||
| 2160 | |||||||||||||||||||||||||||||||||
| 2161 | L |
||||||||||||||||||||||||||||||||
| 2162 | |||||||||||||||||||||||||||||||||
| 2163 | =item * | ||||||||||||||||||||||||||||||||
| 2164 | |||||||||||||||||||||||||||||||||
| 2165 | L |
||||||||||||||||||||||||||||||||
| 2166 | management, this plugin provides a useful wrapper around L |
||||||||||||||||||||||||||||||||
| 2167 | |||||||||||||||||||||||||||||||||
| 2168 | =item * | ||||||||||||||||||||||||||||||||
| 2169 | |||||||||||||||||||||||||||||||||
| 2170 | L |
||||||||||||||||||||||||||||||||
| 2171 | |||||||||||||||||||||||||||||||||
| 2172 | =back | ||||||||||||||||||||||||||||||||
| 2173 | |||||||||||||||||||||||||||||||||
| 2174 | =head2 More plug-ins | ||||||||||||||||||||||||||||||||
| 2175 | |||||||||||||||||||||||||||||||||
| 2176 | Many more plugins are available as alternatives and for specific uses. For a | ||||||||||||||||||||||||||||||||
| 2177 | current complete list, please consult CPAN: | ||||||||||||||||||||||||||||||||
| 2178 | |||||||||||||||||||||||||||||||||
| 2179 | http://search.cpan.org/search?m=dist&q=CGI%2DApplication%2DPlugin | ||||||||||||||||||||||||||||||||
| 2180 | |||||||||||||||||||||||||||||||||
| 2181 | =over 4 | ||||||||||||||||||||||||||||||||
| 2182 | |||||||||||||||||||||||||||||||||
| 2183 | =item * | ||||||||||||||||||||||||||||||||
| 2184 | |||||||||||||||||||||||||||||||||
| 2185 | L |
||||||||||||||||||||||||||||||||
| 2186 | |||||||||||||||||||||||||||||||||
| 2187 | =item * | ||||||||||||||||||||||||||||||||
| 2188 | |||||||||||||||||||||||||||||||||
| 2189 | L |
||||||||||||||||||||||||||||||||
| 2190 | |||||||||||||||||||||||||||||||||
| 2191 | =item * | ||||||||||||||||||||||||||||||||
| 2192 | |||||||||||||||||||||||||||||||||
| 2193 | L |
||||||||||||||||||||||||||||||||
| 2194 | |||||||||||||||||||||||||||||||||
| 2195 | |||||||||||||||||||||||||||||||||
| 2196 | =item * | ||||||||||||||||||||||||||||||||
| 2197 | |||||||||||||||||||||||||||||||||
| 2198 | L |
||||||||||||||||||||||||||||||||
| 2199 | |||||||||||||||||||||||||||||||||
| 2200 | =item * | ||||||||||||||||||||||||||||||||
| 2201 | |||||||||||||||||||||||||||||||||
| 2202 | L |
||||||||||||||||||||||||||||||||
| 2203 | |||||||||||||||||||||||||||||||||
| 2204 | =item * | ||||||||||||||||||||||||||||||||
| 2205 | |||||||||||||||||||||||||||||||||
| 2206 | L |
||||||||||||||||||||||||||||||||
| 2207 | |||||||||||||||||||||||||||||||||
| 2208 | =item * | ||||||||||||||||||||||||||||||||
| 2209 | |||||||||||||||||||||||||||||||||
| 2210 | L |
||||||||||||||||||||||||||||||||
| 2211 | |||||||||||||||||||||||||||||||||
| 2212 | |||||||||||||||||||||||||||||||||
| 2213 | =item * | ||||||||||||||||||||||||||||||||
| 2214 | |||||||||||||||||||||||||||||||||
| 2215 | L |
||||||||||||||||||||||||||||||||
| 2216 | |||||||||||||||||||||||||||||||||
| 2217 | =item * | ||||||||||||||||||||||||||||||||
| 2218 | |||||||||||||||||||||||||||||||||
| 2219 | L |
||||||||||||||||||||||||||||||||
| 2220 | |||||||||||||||||||||||||||||||||
| 2221 | =item * | ||||||||||||||||||||||||||||||||
| 2222 | |||||||||||||||||||||||||||||||||
| 2223 | L |
||||||||||||||||||||||||||||||||
| 2224 | code structure, with the difference that code and HTML for each screen are in | ||||||||||||||||||||||||||||||||
| 2225 | separate files. | ||||||||||||||||||||||||||||||||
| 2226 | |||||||||||||||||||||||||||||||||
| 2227 | =item * | ||||||||||||||||||||||||||||||||
| 2228 | |||||||||||||||||||||||||||||||||
| 2229 | L |
||||||||||||||||||||||||||||||||
| 2230 | |||||||||||||||||||||||||||||||||
| 2231 | |||||||||||||||||||||||||||||||||
| 2232 | =back | ||||||||||||||||||||||||||||||||
| 2233 | |||||||||||||||||||||||||||||||||
| 2234 | |||||||||||||||||||||||||||||||||
| 2235 | |||||||||||||||||||||||||||||||||
| 2236 | Consult each plug-in for the exact usage syntax. | ||||||||||||||||||||||||||||||||
| 2237 | |||||||||||||||||||||||||||||||||
| 2238 | =head2 Writing Plug-ins | ||||||||||||||||||||||||||||||||
| 2239 | |||||||||||||||||||||||||||||||||
| 2240 | Writing plug-ins is simple. Simply create a new package, and export the | ||||||||||||||||||||||||||||||||
| 2241 | methods that you want to become part of a CGI::Application project. See | ||||||||||||||||||||||||||||||||
| 2242 | L |
||||||||||||||||||||||||||||||||
| 2243 | |||||||||||||||||||||||||||||||||
| 2244 | In order to avoid namespace conflicts within a CGI::Application object, | ||||||||||||||||||||||||||||||||
| 2245 | plugin developers are recommended to use a unique prefix, such as the | ||||||||||||||||||||||||||||||||
| 2246 | name of plugin package, when storing information. For instance: | ||||||||||||||||||||||||||||||||
| 2247 | |||||||||||||||||||||||||||||||||
| 2248 | $app->{__PARAM} = 'foo'; # BAD! Could conflict. | ||||||||||||||||||||||||||||||||
| 2249 | $app->{'MyPlugin::Module::__PARAM'} = 'foo'; # Good. | ||||||||||||||||||||||||||||||||
| 2250 | $app->{'MyPlugin::Module'}{__PARAM} = 'foo'; # Good. | ||||||||||||||||||||||||||||||||
| 2251 | |||||||||||||||||||||||||||||||||
| 2252 | =head2 Writing Advanced Plug-ins - Using callbacks | ||||||||||||||||||||||||||||||||
| 2253 | |||||||||||||||||||||||||||||||||
| 2254 | When writing a plug-in, you may want some action to happen automatically at a | ||||||||||||||||||||||||||||||||
| 2255 | particular stage, such as setting up a database connection or initializing a | ||||||||||||||||||||||||||||||||
| 2256 | session. By using these 'callback' methods, you can register a subroutine | ||||||||||||||||||||||||||||||||
| 2257 | to run at a particular phase, accomplishing this goal. | ||||||||||||||||||||||||||||||||
| 2258 | |||||||||||||||||||||||||||||||||
| 2259 | B |
||||||||||||||||||||||||||||||||
| 2260 | |||||||||||||||||||||||||||||||||
| 2261 | # register a callback to the standard CGI::Application hooks | ||||||||||||||||||||||||||||||||
| 2262 | # one of 'init', 'prerun', 'postrun', 'teardown' or 'load_tmpl' | ||||||||||||||||||||||||||||||||
| 2263 | # As a plug-in author, this is probably the only method you need. | ||||||||||||||||||||||||||||||||
| 2264 | |||||||||||||||||||||||||||||||||
| 2265 | # Class-based: callback will persist for all runs of the application | ||||||||||||||||||||||||||||||||
| 2266 | $class->add_callback('init', \&some_other_method); | ||||||||||||||||||||||||||||||||
| 2267 | |||||||||||||||||||||||||||||||||
| 2268 | # Object-based: callback will only last for lifetime of this object | ||||||||||||||||||||||||||||||||
| 2269 | $self->add_callback('prerun', \&some_method); | ||||||||||||||||||||||||||||||||
| 2270 | |||||||||||||||||||||||||||||||||
| 2271 | # If you want to create a new hook location in your application, | ||||||||||||||||||||||||||||||||
| 2272 | # You'll need to know about the following two methods to create | ||||||||||||||||||||||||||||||||
| 2273 | # the hook and call it. | ||||||||||||||||||||||||||||||||
| 2274 | |||||||||||||||||||||||||||||||||
| 2275 | # Create a new hook | ||||||||||||||||||||||||||||||||
| 2276 | $self->new_hook('pretemplate'); | ||||||||||||||||||||||||||||||||
| 2277 | |||||||||||||||||||||||||||||||||
| 2278 | # Then later execute all the callbacks registered at this hook | ||||||||||||||||||||||||||||||||
| 2279 | $self->call_hook('pretemplate'); | ||||||||||||||||||||||||||||||||
| 2280 | |||||||||||||||||||||||||||||||||
| 2281 | B |
||||||||||||||||||||||||||||||||
| 2282 | |||||||||||||||||||||||||||||||||
| 2283 | =head3 add_callback() | ||||||||||||||||||||||||||||||||
| 2284 | |||||||||||||||||||||||||||||||||
| 2285 | $self->add_callback ('teardown', \&callback); | ||||||||||||||||||||||||||||||||
| 2286 | $class->add_callback('teardown', 'method'); | ||||||||||||||||||||||||||||||||
| 2287 | |||||||||||||||||||||||||||||||||
| 2288 | The add_callback method allows you to register a callback | ||||||||||||||||||||||||||||||||
| 2289 | function that is to be called at the given stage of execution. | ||||||||||||||||||||||||||||||||
| 2290 | Valid hooks include 'init', 'prerun', 'postrun' and 'teardown', | ||||||||||||||||||||||||||||||||
| 2291 | 'load_tmpl', and any other hooks defined using the C |
||||||||||||||||||||||||||||||||
| 2292 | method. | ||||||||||||||||||||||||||||||||
| 2293 | |||||||||||||||||||||||||||||||||
| 2294 | The callback should be a reference to a subroutine or the name of a | ||||||||||||||||||||||||||||||||
| 2295 | method. | ||||||||||||||||||||||||||||||||
| 2296 | |||||||||||||||||||||||||||||||||
| 2297 | If multiple callbacks are added to the same hook, they will all be | ||||||||||||||||||||||||||||||||
| 2298 | executed one after the other. The exact order depends on which class | ||||||||||||||||||||||||||||||||
| 2299 | installed each callback, as described below under B |
||||||||||||||||||||||||||||||||
| 2300 | |||||||||||||||||||||||||||||||||
| 2301 | Callbacks can either be I |
||||||||||||||||||||||||||||||||
| 2302 | upon whether you call C |
||||||||||||||||||||||||||||||||
| 2303 | method: | ||||||||||||||||||||||||||||||||
| 2304 | |||||||||||||||||||||||||||||||||
| 2305 | # add object-based callback | ||||||||||||||||||||||||||||||||
| 2306 | $self->add_callback('teardown', \&callback); | ||||||||||||||||||||||||||||||||
| 2307 | |||||||||||||||||||||||||||||||||
| 2308 | # add class-based callbacks | ||||||||||||||||||||||||||||||||
| 2309 | $class->add_callback('teardown', \&callback); | ||||||||||||||||||||||||||||||||
| 2310 | My::Project->add_callback('teardown', \&callback); | ||||||||||||||||||||||||||||||||
| 2311 | |||||||||||||||||||||||||||||||||
| 2312 | Object-based callbacks are stored in your web application's C<$c> | ||||||||||||||||||||||||||||||||
| 2313 | object; at the end of the request when the C<$c> object goes out of | ||||||||||||||||||||||||||||||||
| 2314 | scope, the callbacks are gone too. | ||||||||||||||||||||||||||||||||
| 2315 | |||||||||||||||||||||||||||||||||
| 2316 | Object-based callbacks are useful for one-time tasks that apply only to | ||||||||||||||||||||||||||||||||
| 2317 | the current running application. For instance you could install a | ||||||||||||||||||||||||||||||||
| 2318 | C |
||||||||||||||||||||||||||||||||
| 2319 | end of the current request, after all the HTML has been sent to the | ||||||||||||||||||||||||||||||||
| 2320 | browser. | ||||||||||||||||||||||||||||||||
| 2321 | |||||||||||||||||||||||||||||||||
| 2322 | Class-based callbacks survive for the duration of the running Perl | ||||||||||||||||||||||||||||||||
| 2323 | process. (In a persistent environment such as C |
||||||||||||||||||||||||||||||||
| 2324 | C |
||||||||||||||||||||||||||||||||
| 2325 | |||||||||||||||||||||||||||||||||
| 2326 | Class-based callbacks are useful for plugins to add features to all web | ||||||||||||||||||||||||||||||||
| 2327 | applications. | ||||||||||||||||||||||||||||||||
| 2328 | |||||||||||||||||||||||||||||||||
| 2329 | Another feature of class-based callbacks is that your plugin can create | ||||||||||||||||||||||||||||||||
| 2330 | hooks and add callbacks at any time - even before the web application's | ||||||||||||||||||||||||||||||||
| 2331 | C<$c> object has been initialized. A good place to do this is in | ||||||||||||||||||||||||||||||||
| 2332 | your plugin's C |
||||||||||||||||||||||||||||||||
| 2333 | |||||||||||||||||||||||||||||||||
| 2334 | package CGI::Application::Plugin::MyPlugin; | ||||||||||||||||||||||||||||||||
| 2335 | use base 'Exporter'; | ||||||||||||||||||||||||||||||||
| 2336 | sub import { | ||||||||||||||||||||||||||||||||
| 2337 | my $caller = scalar(caller); | ||||||||||||||||||||||||||||||||
| 2338 | $caller->add_callback('init', 'my_setup'); | ||||||||||||||||||||||||||||||||
| 2339 | goto &Exporter::import; | ||||||||||||||||||||||||||||||||
| 2340 | } | ||||||||||||||||||||||||||||||||
| 2341 | |||||||||||||||||||||||||||||||||
| 2342 | Notice that C<< $caller->add_callback >> installs the callback | ||||||||||||||||||||||||||||||||
| 2343 | on behalf of the module that contained the line: | ||||||||||||||||||||||||||||||||
| 2344 | |||||||||||||||||||||||||||||||||
| 2345 | use CGI::Application::Plugin::MyPlugin; | ||||||||||||||||||||||||||||||||
| 2346 | |||||||||||||||||||||||||||||||||
| 2347 | =cut | ||||||||||||||||||||||||||||||||
| 2348 | |||||||||||||||||||||||||||||||||
| 2349 | sub add_callback { | ||||||||||||||||||||||||||||||||
| 2350 | 44 | 44 | 1 | 1594 | my ($c_or_class, $hook, $callback) = @_; | ||||||||||||||||||||||||||||
| 2351 | |||||||||||||||||||||||||||||||||
| 2352 | 44 | 61 | $hook = lc $hook; | ||||||||||||||||||||||||||||||
| 2353 | |||||||||||||||||||||||||||||||||
| 2354 | 44 | 50 | 67 | die "no callback provided when calling add_callback" unless $callback; | |||||||||||||||||||||||||||||
| 2355 | 44 | 50 | 73 | die "Unknown hook ($hook)" unless exists $INSTALLED_CALLBACKS{$hook}; | |||||||||||||||||||||||||||||
| 2356 | |||||||||||||||||||||||||||||||||
| 2357 | 44 | 100 | 61 | if (ref $c_or_class) { | |||||||||||||||||||||||||||||
| 2358 | # Install in object | ||||||||||||||||||||||||||||||||
| 2359 | 5 | 8 | my $self = $c_or_class; | ||||||||||||||||||||||||||||||
| 2360 | 5 | 6 | push @{ $self->{__INSTALLED_CALLBACKS}{$hook} }, $callback; | ||||||||||||||||||||||||||||||
| 5 | 16 | ||||||||||||||||||||||||||||||||
| 2361 | } | ||||||||||||||||||||||||||||||||
| 2362 | else { | ||||||||||||||||||||||||||||||||
| 2363 | # Install in class | ||||||||||||||||||||||||||||||||
| 2364 | 39 | 42 | my $class = $c_or_class; | ||||||||||||||||||||||||||||||
| 2365 | 39 | 40 | push @{ $INSTALLED_CALLBACKS{$hook}{$class} }, $callback; | ||||||||||||||||||||||||||||||
| 39 | 88 | ||||||||||||||||||||||||||||||||
| 2366 | } | ||||||||||||||||||||||||||||||||
| 2367 | |||||||||||||||||||||||||||||||||
| 2368 | } | ||||||||||||||||||||||||||||||||
| 2369 | |||||||||||||||||||||||||||||||||
| 2370 | =head3 new_hook(HOOK) | ||||||||||||||||||||||||||||||||
| 2371 | |||||||||||||||||||||||||||||||||
| 2372 | $self->new_hook('pretemplate'); | ||||||||||||||||||||||||||||||||
| 2373 | |||||||||||||||||||||||||||||||||
| 2374 | The C |
||||||||||||||||||||||||||||||||
| 2375 | register callbacks. It takes one argument, a hook name. The hook location is | ||||||||||||||||||||||||||||||||
| 2376 | created if it does not already exist. A true value is always returned. | ||||||||||||||||||||||||||||||||
| 2377 | |||||||||||||||||||||||||||||||||
| 2378 | For an example, L |
||||||||||||||||||||||||||||||||
| 2379 | template is processed. | ||||||||||||||||||||||||||||||||
| 2380 | |||||||||||||||||||||||||||||||||
| 2381 | See C |
||||||||||||||||||||||||||||||||
| 2382 | |||||||||||||||||||||||||||||||||
| 2383 | =cut | ||||||||||||||||||||||||||||||||
| 2384 | |||||||||||||||||||||||||||||||||
| 2385 | sub new_hook { | ||||||||||||||||||||||||||||||||
| 2386 | 5 | 5 | 1 | 399 | my ($class, $hook) = @_; | ||||||||||||||||||||||||||||
| 2387 | 5 | 100 | 24 | $INSTALLED_CALLBACKS{$hook} ||= {}; | |||||||||||||||||||||||||||||
| 2388 | 5 | 11 | return 1; | ||||||||||||||||||||||||||||||
| 2389 | } | ||||||||||||||||||||||||||||||||
| 2390 | |||||||||||||||||||||||||||||||||
| 2391 | =head3 call_hook(HOOK) | ||||||||||||||||||||||||||||||||
| 2392 | |||||||||||||||||||||||||||||||||
| 2393 | $self->call_hook('pretemplate', @args); | ||||||||||||||||||||||||||||||||
| 2394 | |||||||||||||||||||||||||||||||||
| 2395 | The C |
||||||||||||||||||||||||||||||||
| 2396 | at the given hook. It is used in conjunction with the C |
||||||||||||||||||||||||||||||||
| 2397 | allows you to create a new hook location. | ||||||||||||||||||||||||||||||||
| 2398 | |||||||||||||||||||||||||||||||||
| 2399 | The first argument to C |
||||||||||||||||||||||||||||||||
| 2400 | are passed to every callback executed at the hook location. So, a stub for a | ||||||||||||||||||||||||||||||||
| 2401 | callback at the 'pretemplate' hook would look like this: | ||||||||||||||||||||||||||||||||
| 2402 | |||||||||||||||||||||||||||||||||
| 2403 | sub my_hook { | ||||||||||||||||||||||||||||||||
| 2404 | my ($c,@args) = @_; | ||||||||||||||||||||||||||||||||
| 2405 | # .... | ||||||||||||||||||||||||||||||||
| 2406 | } | ||||||||||||||||||||||||||||||||
| 2407 | |||||||||||||||||||||||||||||||||
| 2408 | Note that hooks are semi-public locations. Calling a hook means executing | ||||||||||||||||||||||||||||||||
| 2409 | callbacks that were registered to that hook by the current object and also | ||||||||||||||||||||||||||||||||
| 2410 | those registered by any of the current object's parent classes. See below for | ||||||||||||||||||||||||||||||||
| 2411 | the exact ordering. | ||||||||||||||||||||||||||||||||
| 2412 | |||||||||||||||||||||||||||||||||
| 2413 | =cut | ||||||||||||||||||||||||||||||||
| 2414 | |||||||||||||||||||||||||||||||||
| 2415 | sub call_hook { | ||||||||||||||||||||||||||||||||
| 2416 | 261 | 261 | 1 | 431 | my $self = shift; | ||||||||||||||||||||||||||||
| 2417 | 261 | 33 | 545 | my $app_class = ref $self || $self; | |||||||||||||||||||||||||||||
| 2418 | 261 | 463 | my $hook = lc shift; | ||||||||||||||||||||||||||||||
| 2419 | 261 | 426 | my @args = @_; | ||||||||||||||||||||||||||||||
| 2420 | |||||||||||||||||||||||||||||||||
| 2421 | 261 | 50 | 525 | die "Unknown hook ($hook)" unless exists $INSTALLED_CALLBACKS{$hook}; | |||||||||||||||||||||||||||||
| 2422 | |||||||||||||||||||||||||||||||||
| 2423 | 261 | 302 | my %executed_callback; | ||||||||||||||||||||||||||||||
| 2424 | |||||||||||||||||||||||||||||||||
| 2425 | # First, run callbacks installed in the object | ||||||||||||||||||||||||||||||||
| 2426 | 261 | 303 | foreach my $callback (@{ $self->{__INSTALLED_CALLBACKS}{$hook} }) { | ||||||||||||||||||||||||||||||
| 261 | 700 | ||||||||||||||||||||||||||||||||
| 2427 | 5 | 50 | 15 | next if $executed_callback{$callback}; | |||||||||||||||||||||||||||||
| 2428 | 5 | 5 | eval { $self->$callback(@args); }; | ||||||||||||||||||||||||||||||
| 5 | 18 | ||||||||||||||||||||||||||||||||
| 2429 | 5 | 46 | $executed_callback{$callback} = 1; | ||||||||||||||||||||||||||||||
| 2430 | 5 | 50 | 12 | die "Error executing object callback in $hook stage: $@" if $@; | |||||||||||||||||||||||||||||
| 2431 | } | ||||||||||||||||||||||||||||||||
| 2432 | |||||||||||||||||||||||||||||||||
| 2433 | # Next, run callbacks installed in class hierarchy | ||||||||||||||||||||||||||||||||
| 2434 | |||||||||||||||||||||||||||||||||
| 2435 | # Cache this value as a performance boost | ||||||||||||||||||||||||||||||||
| 2436 | 261 | 100 | 739 | $self->{__CALLBACK_CLASSES} ||= [ Class::ISA::self_and_super_path($app_class) ]; | |||||||||||||||||||||||||||||
| 2437 | |||||||||||||||||||||||||||||||||
| 2438 | # Get list of classes that the current app inherits from | ||||||||||||||||||||||||||||||||
| 2439 | 261 | 2756 | foreach my $class (@{ $self->{__CALLBACK_CLASSES} }) { | ||||||||||||||||||||||||||||||
| 261 | 466 | ||||||||||||||||||||||||||||||||
| 2440 | |||||||||||||||||||||||||||||||||
| 2441 | # skip those classes that contain no callbacks | ||||||||||||||||||||||||||||||||
| 2442 | 521 | 100 | 1019 | next unless exists $INSTALLED_CALLBACKS{$hook}{$class}; | |||||||||||||||||||||||||||||
| 2443 | |||||||||||||||||||||||||||||||||
| 2444 | # call all of the callbacks in the class | ||||||||||||||||||||||||||||||||
| 2445 | 277 | 331 | foreach my $callback (@{ $INSTALLED_CALLBACKS{$hook}{$class} }) { | ||||||||||||||||||||||||||||||
| 277 | 525 | ||||||||||||||||||||||||||||||||
| 2446 | 305 | 100 | 588 | next if $executed_callback{$callback}; | |||||||||||||||||||||||||||||
| 2447 | 295 | 366 | eval { $self->$callback(@args); }; | ||||||||||||||||||||||||||||||
| 295 | 940 | ||||||||||||||||||||||||||||||||
| 2448 | 295 | 907 | $executed_callback{$callback} = 1; | ||||||||||||||||||||||||||||||
| 2449 | 295 | 50 | 769 | die "Error executing class callback in $hook stage: $@" if $@; | |||||||||||||||||||||||||||||
| 2450 | } | ||||||||||||||||||||||||||||||||
| 2451 | } | ||||||||||||||||||||||||||||||||
| 2452 | |||||||||||||||||||||||||||||||||
| 2453 | } | ||||||||||||||||||||||||||||||||
| 2454 | |||||||||||||||||||||||||||||||||
| 2455 | =pod | ||||||||||||||||||||||||||||||||
| 2456 | |||||||||||||||||||||||||||||||||
| 2457 | B |
||||||||||||||||||||||||||||||||
| 2458 | |||||||||||||||||||||||||||||||||
| 2459 | Object-based callbacks are run before class-based callbacks. | ||||||||||||||||||||||||||||||||
| 2460 | |||||||||||||||||||||||||||||||||
| 2461 | The order of class-based callbacks is determined by the inheritance tree of the | ||||||||||||||||||||||||||||||||
| 2462 | running application. The built-in methods of C |
||||||||||||||||||||||||||||||||
| 2463 | C |
||||||||||||||||||||||||||||||||
| 2464 | ordering below. | ||||||||||||||||||||||||||||||||
| 2465 | |||||||||||||||||||||||||||||||||
| 2466 | In a persistent environment, there might be a lot of applications | ||||||||||||||||||||||||||||||||
| 2467 | in memory at the same time. For instance: | ||||||||||||||||||||||||||||||||
| 2468 | |||||||||||||||||||||||||||||||||
| 2469 | CGI::Application | ||||||||||||||||||||||||||||||||
| 2470 | Other::Project # uses CGI::Application::Plugin::Baz | ||||||||||||||||||||||||||||||||
| 2471 | Other::App # uses CGI::Application::Plugin::Bam | ||||||||||||||||||||||||||||||||
| 2472 | |||||||||||||||||||||||||||||||||
| 2473 | My::Project # uses CGI::Application::Plugin::Foo | ||||||||||||||||||||||||||||||||
| 2474 | My::App # uses CGI::Application::Plugin::Bar | ||||||||||||||||||||||||||||||||
| 2475 | |||||||||||||||||||||||||||||||||
| 2476 | Suppose that each of the above plugins each added a callback to be run | ||||||||||||||||||||||||||||||||
| 2477 | at the 'init' stage: | ||||||||||||||||||||||||||||||||
| 2478 | |||||||||||||||||||||||||||||||||
| 2479 | Plugin init callback | ||||||||||||||||||||||||||||||||
| 2480 | ------ ------------- | ||||||||||||||||||||||||||||||||
| 2481 | CGI::Application::Plugin::Baz baz_startup | ||||||||||||||||||||||||||||||||
| 2482 | CGI::Application::Plugin::Bam bam_startup | ||||||||||||||||||||||||||||||||
| 2483 | |||||||||||||||||||||||||||||||||
| 2484 | CGI::Application::Plugin::Foo foo_startup | ||||||||||||||||||||||||||||||||
| 2485 | CGI::Application::Plugin::Bar bar_startup | ||||||||||||||||||||||||||||||||
| 2486 | |||||||||||||||||||||||||||||||||
| 2487 | When C |
||||||||||||||||||||||||||||||||
| 2488 | run. The other callbacks are skipped. | ||||||||||||||||||||||||||||||||
| 2489 | |||||||||||||||||||||||||||||||||
| 2490 | The C<@ISA> list of C |
||||||||||||||||||||||||||||||||
| 2491 | |||||||||||||||||||||||||||||||||
| 2492 | My::App | ||||||||||||||||||||||||||||||||
| 2493 | My::Project | ||||||||||||||||||||||||||||||||
| 2494 | CGI::Application | ||||||||||||||||||||||||||||||||
| 2495 | |||||||||||||||||||||||||||||||||
| 2496 | This order determines the order of callbacks run. | ||||||||||||||||||||||||||||||||
| 2497 | |||||||||||||||||||||||||||||||||
| 2498 | When C |
||||||||||||||||||||||||||||||||
| 2499 | installed by these modules are run in order, resulting in: | ||||||||||||||||||||||||||||||||
| 2500 | C |
||||||||||||||||||||||||||||||||
| 2501 | |||||||||||||||||||||||||||||||||
| 2502 | If a single class installs more than one callback at the same hook, then | ||||||||||||||||||||||||||||||||
| 2503 | these callbacks are run in the order they were registered (FIFO). | ||||||||||||||||||||||||||||||||
| 2504 | |||||||||||||||||||||||||||||||||
| 2505 | |||||||||||||||||||||||||||||||||
| 2506 | |||||||||||||||||||||||||||||||||
| 2507 | =cut | ||||||||||||||||||||||||||||||||
| 2508 | |||||||||||||||||||||||||||||||||
| 2509 | |||||||||||||||||||||||||||||||||
| 2510 | =head1 COMMUNITY | ||||||||||||||||||||||||||||||||
| 2511 | |||||||||||||||||||||||||||||||||
| 2512 | Therese are primary resources available for those who wish to learn more | ||||||||||||||||||||||||||||||||
| 2513 | about CGI::Application and discuss it with others. | ||||||||||||||||||||||||||||||||
| 2514 | |||||||||||||||||||||||||||||||||
| 2515 | B |
||||||||||||||||||||||||||||||||
| 2516 | |||||||||||||||||||||||||||||||||
| 2517 | This is a community built and maintained resource that anyone is welcome to | ||||||||||||||||||||||||||||||||
| 2518 | contribute to. It contains a number of articles of its own and links | ||||||||||||||||||||||||||||||||
| 2519 | to many other CGI::Application related pages: | ||||||||||||||||||||||||||||||||
| 2520 | |||||||||||||||||||||||||||||||||
| 2521 | L |
||||||||||||||||||||||||||||||||
| 2522 | |||||||||||||||||||||||||||||||||
| 2523 | B |
||||||||||||||||||||||||||||||||
| 2524 | |||||||||||||||||||||||||||||||||
| 2525 | If you have any questions, comments, bug reports or feature suggestions, | ||||||||||||||||||||||||||||||||
| 2526 | post them to the support mailing list! To join the mailing list, visit | ||||||||||||||||||||||||||||||||
| 2527 | http://lists.openlib.org/mailman/listinfo/cgiapp | ||||||||||||||||||||||||||||||||
| 2528 | |||||||||||||||||||||||||||||||||
| 2529 | B |
||||||||||||||||||||||||||||||||
| 2530 | |||||||||||||||||||||||||||||||||
| 2531 | This project is managed using git and is available on Github: | ||||||||||||||||||||||||||||||||
| 2532 | |||||||||||||||||||||||||||||||||
| 2533 | L |
||||||||||||||||||||||||||||||||
| 2534 | |||||||||||||||||||||||||||||||||
| 2535 | =head1 SEE ALSO | ||||||||||||||||||||||||||||||||
| 2536 | |||||||||||||||||||||||||||||||||
| 2537 | =over 4 | ||||||||||||||||||||||||||||||||
| 2538 | |||||||||||||||||||||||||||||||||
| 2539 | =item o | ||||||||||||||||||||||||||||||||
| 2540 | |||||||||||||||||||||||||||||||||
| 2541 | L |
||||||||||||||||||||||||||||||||
| 2542 | |||||||||||||||||||||||||||||||||
| 2543 | =item o | ||||||||||||||||||||||||||||||||
| 2544 | |||||||||||||||||||||||||||||||||
| 2545 | L |
||||||||||||||||||||||||||||||||
| 2546 | |||||||||||||||||||||||||||||||||
| 2547 | =item o | ||||||||||||||||||||||||||||||||
| 2548 | |||||||||||||||||||||||||||||||||
| 2549 | B |
||||||||||||||||||||||||||||||||
| 2550 | CGI::Application. http://www.cafweb.org/ | ||||||||||||||||||||||||||||||||
| 2551 | |||||||||||||||||||||||||||||||||
| 2552 | =back | ||||||||||||||||||||||||||||||||
| 2553 | |||||||||||||||||||||||||||||||||
| 2554 | =head1 MORE READING | ||||||||||||||||||||||||||||||||
| 2555 | |||||||||||||||||||||||||||||||||
| 2556 | If you're interested in finding out more about CGI::Application, the | ||||||||||||||||||||||||||||||||
| 2557 | following articles are available on Perl.com: | ||||||||||||||||||||||||||||||||
| 2558 | |||||||||||||||||||||||||||||||||
| 2559 | Using CGI::Application | ||||||||||||||||||||||||||||||||
| 2560 | http://www.perl.com/pub/a/2001/06/05/cgi.html | ||||||||||||||||||||||||||||||||
| 2561 | |||||||||||||||||||||||||||||||||
| 2562 | Rapid Website Development with CGI::Application | ||||||||||||||||||||||||||||||||
| 2563 | http://www.perl.com/pub/a/2006/10/19/cgi_application.html | ||||||||||||||||||||||||||||||||
| 2564 | |||||||||||||||||||||||||||||||||
| 2565 | Thanks to O'Reilly for publishing these articles, and for the incredible value | ||||||||||||||||||||||||||||||||
| 2566 | they provide to the Perl community! | ||||||||||||||||||||||||||||||||
| 2567 | |||||||||||||||||||||||||||||||||
| 2568 | =head1 AUTHOR | ||||||||||||||||||||||||||||||||
| 2569 | |||||||||||||||||||||||||||||||||
| 2570 | Jesse Erlbaum |
||||||||||||||||||||||||||||||||
| 2571 | |||||||||||||||||||||||||||||||||
| 2572 | Mark Stosberg has served as a co-maintainer since version 3.2, Martin McGrath | ||||||||||||||||||||||||||||||||
| 2573 | became a co-maintainer as of version 4.51, with the help of the numerous | ||||||||||||||||||||||||||||||||
| 2574 | contributors documented in the Changes file. | ||||||||||||||||||||||||||||||||
| 2575 | |||||||||||||||||||||||||||||||||
| 2576 | =head1 CREDITS | ||||||||||||||||||||||||||||||||
| 2577 | |||||||||||||||||||||||||||||||||
| 2578 | CGI::Application was originally developed by The Erlbaum Group, a software | ||||||||||||||||||||||||||||||||
| 2579 | engineering and consulting firm in New York City. | ||||||||||||||||||||||||||||||||
| 2580 | |||||||||||||||||||||||||||||||||
| 2581 | Thanks to Vanguard Media (http://www.vm.com) for funding the initial | ||||||||||||||||||||||||||||||||
| 2582 | development of this library and for encouraging Jesse Erlbaum to release it to | ||||||||||||||||||||||||||||||||
| 2583 | the world. | ||||||||||||||||||||||||||||||||
| 2584 | |||||||||||||||||||||||||||||||||
| 2585 | Many thanks to Sam Tregar (author of the most excellent | ||||||||||||||||||||||||||||||||
| 2586 | HTML::Template module!) for his innumerable contributions | ||||||||||||||||||||||||||||||||
| 2587 | to this module over the years, and most of all for getting | ||||||||||||||||||||||||||||||||
| 2588 | me off my ass to finally get this thing up on CPAN! | ||||||||||||||||||||||||||||||||
| 2589 | |||||||||||||||||||||||||||||||||
| 2590 | Many other people have contributed specific suggestions or patches, | ||||||||||||||||||||||||||||||||
| 2591 | which are documented in the C |
||||||||||||||||||||||||||||||||
| 2592 | |||||||||||||||||||||||||||||||||
| 2593 | Thanks also to all the members of the CGI-App mailing list! | ||||||||||||||||||||||||||||||||
| 2594 | Your ideas, suggestions, insights (and criticism!) have helped | ||||||||||||||||||||||||||||||||
| 2595 | shape this module immeasurably. (To join the mailing list, visit | ||||||||||||||||||||||||||||||||
| 2596 | http://lists.openlib.org/mailman/listinfo/cgiapp ) | ||||||||||||||||||||||||||||||||
| 2597 | |||||||||||||||||||||||||||||||||
| 2598 | =head1 LICENSE | ||||||||||||||||||||||||||||||||
| 2599 | |||||||||||||||||||||||||||||||||
| 2600 | CGI::Application : Framework for building reusable web-applications | ||||||||||||||||||||||||||||||||
| 2601 | Copyright (C) 2000-2003 Jesse Erlbaum |
||||||||||||||||||||||||||||||||
| 2602 | |||||||||||||||||||||||||||||||||
| 2603 | This module is free software; you can redistribute it and/or modify it | ||||||||||||||||||||||||||||||||
| 2604 | under the terms of either: | ||||||||||||||||||||||||||||||||
| 2605 | |||||||||||||||||||||||||||||||||
| 2606 | a) the GNU General Public License as published by the Free Software | ||||||||||||||||||||||||||||||||
| 2607 | Foundation; either version 1, or (at your option) any later version, | ||||||||||||||||||||||||||||||||
| 2608 | |||||||||||||||||||||||||||||||||
| 2609 | or | ||||||||||||||||||||||||||||||||
| 2610 | |||||||||||||||||||||||||||||||||
| 2611 | b) the "Artistic License" which comes with this module. | ||||||||||||||||||||||||||||||||
| 2612 | |||||||||||||||||||||||||||||||||
| 2613 | This program is distributed in the hope that it will be useful, | ||||||||||||||||||||||||||||||||
| 2614 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||||||||||||||||||||||||||||
| 2615 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either | ||||||||||||||||||||||||||||||||
| 2616 | the GNU General Public License or the Artistic License for more details. | ||||||||||||||||||||||||||||||||
| 2617 | |||||||||||||||||||||||||||||||||
| 2618 | You should have received a copy of the Artistic License with this | ||||||||||||||||||||||||||||||||
| 2619 | module, in the file ARTISTIC. If not, I'll be glad to provide one. | ||||||||||||||||||||||||||||||||
| 2620 | |||||||||||||||||||||||||||||||||
| 2621 | You should have received a copy of the GNU General Public License | ||||||||||||||||||||||||||||||||
| 2622 | along with this program; if not, write to the Free Software | ||||||||||||||||||||||||||||||||
| 2623 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||||||||||||||||||||||||||||||||
| 2624 | USA | ||||||||||||||||||||||||||||||||
| 2625 | |||||||||||||||||||||||||||||||||
| 2626 | |||||||||||||||||||||||||||||||||
| 2627 | =cut | ||||||||||||||||||||||||||||||||
| 2628 |