]> Dogcows Code - chaz/p5-CGI-Ex/blob - lib/CGI/Ex/App.pod
CGI::Ex 2.08
[chaz/p5-CGI-Ex] / lib / CGI / Ex / App.pod
1 =head1 NAME
2
3 CGI::Ex::App - Anti-framework application framework.
4
5 =head1 SYNOPSIS
6
7 #!/usr/bin/perl -w
8
9 use strict;
10 use base qw(CGI::Ex::App);
11
12 __PACKAGE__->navigate;
13 exit;
14
15 sub main_file_print {
16 return \ "Hello World";
17 }
18
19 There is a longer "SYNOPSIS" after the process flow discussion.
20
21 =head1 DESCRIPTION
22
23 Fill in the blanks and get a ready made web application. This module
24 is somewhat similar in spirit to CGI::Application, CGI::Path, and
25 CGI::Builder and any other "CGI framework." As with the others,
26 CGI::Ex::App tries to do as much of the mundane things, in a simple
27 manner, without getting in the developer's way. However, there are
28 various design patterns for CGI applications that CGI::Ex::App handles
29 for you that the other frameworks require you to bring in extra support.
30 The entire CGI::Ex suite has been taylored to work seamlessly together.
31 Your mileage in building applications may vary.
32
33 If you build applications that submit user information, validate it,
34 re-display it, fill in forms, or separate logic into separate modules,
35 then this module may be for you. If all you need is a dispatch
36 engine, then this still may be for you. If all you want is to look at
37 user passed information, then this may still be for you. If you like
38 writing bare metal code, this could still be for you. If you don't want
39 to write any code, this module will help - but you still need to
40 provide your key actions and html.
41
42 One of the great benefits of CGI::Ex::App vs. Catalyst or Rails style
43 frameworks is that the model of CGI::Ex::App can be much more abstract
44 as models often are.
45
46 =head1 DEFAULT PROCESS FLOW
47
48 The following pseudo-code describes the process flow
49 of the CGI::Ex::App framework. Several portions of the flow
50 are encapsulated in hooks which may be completely overridden to give
51 different flow. All of the default actions are shown. It may look
52 like a lot to follow, but if the process is broken down into the
53 discrete operations of step iteration, data validation, and template
54 printing the flow feels more natural.
55
56 =head2 navigate
57
58 The process starts off by calling ->navigate.
59
60 navigate {
61 eval {
62 ->pre_navigate
63 ->nav_loop
64 ->post_navigate
65 }
66 # dying errors will run the ->handle_error method
67
68 ->destroy
69 }
70
71 =head2 nav_loop
72
73 The nav_loop method will run as follows:
74
75 nav_loop {
76 ->path (get the array of path steps)
77 # ->path_info_map_base (method - map ENV PATH_INFO to form)
78 # look in ->form for ->step_key
79 # make sure step is in ->valid_steps (if defined)
80
81 ->pre_loop($path)
82 # navigation stops if true
83
84 foreach step of path {
85
86 ->morph
87 # check ->allow_morph
88 # check ->allow_nested_morph
89 # ->morph_package (hook - get the package to bless into)
90 # ->fixup_after_morph if morph_package exists
91 # if no package is found, process continues in current file
92
93 ->path_info_map (hook - map PATH_INFO to form)
94
95 ->run_step (hook)
96
97 ->refine_path (hook)
98 # only called if run_step returned false (page not printed)
99 ->next_step (hook) # find next step and add to path
100 ->set_ready_validate(0) (hook)
101
102 ->unmorph
103 # only called if morph worked
104 # ->fixup_before_unmorph if blessed to current package
105
106 # exit loop if ->run_step returned true (page printed)
107
108 } end of foreach step
109
110 ->post_loop
111 # navigation stops if true
112
113 ->default_step
114 ->insert_path (puts the default step into the path)
115 ->nav_loop (called again recursively)
116
117 } end of nav_loop
118
119 =head2 run_step (hook)
120
121 For each step of the path the following methods will be run
122 during the run_step hook.
123
124 run_step {
125 ->pre_step (hook)
126 # exits nav_loop if true
127
128 ->skip (hook)
129 # skips this step if true (stays in nav_loop)
130
131 ->prepare (hook - defaults to true)
132
133 ->info_complete (hook - ran if prepare was true)
134 ->ready_validate (hook)
135 return false if ! ready_validate
136 ->validate (hook - uses CGI::Ex::Validate to validate form info)
137 ->hash_validation (hook)
138 ->file_val (hook)
139 ->base_dir_abs
140 ->base_dir_rel
141 ->name_module
142 ->name_step
143 ->ext_val
144 returns true if validate is true or if nothing to validate
145
146 ->finalize (hook - defaults to true - ran if prepare and info_complete were true)
147
148 if ! ->prepare || ! ->info_complete || ! ->finalize {
149 ->prepared_print
150 ->hash_base (hook)
151 ->hash_common (hook)
152 ->hash_form (hook)
153 ->hash_fill (hook)
154 ->hash_swap (hook)
155 ->hash_errors (hook)
156 # merge form, base, common, and fill into merged fill
157 # merge form, base, common, swap, and errors into merged swap
158 ->print (hook - passed current step, merged swap hash, and merged fill)
159 ->file_print (hook - uses base_dir_rel, name_module, name_step, ext_print)
160 ->swap_template (hook - processes the file with CGI::Ex::Template)
161 ->template_args (hook - passed to CGI::Ex::Template->new)
162 ->fill_template (hook - fills the any forms with CGI::Ex::Fill)
163 ->fill_args (hook - passed to CGI::Ex::Fill::fill)
164 ->print_out (hook - print headers and the content to STDOUT)
165
166 ->post_print (hook - used for anything after the print process)
167
168 # return true to exit from nav_loop
169 }
170
171 ->post_step (hook)
172 # exits nav_loop if true
173
174 } end of run_step
175
176 It is important to learn the function and placement of each of the
177 hooks in the process flow in order to make the most of CGI::Ex::App.
178 It is enough to begin by learning a few common hooks - such as
179 hash_validation, hash_swap, and finalize, and then learn about other
180 hooks as needs arise. Sometimes, it is enough to simply override the
181 run_step hook and take care of processing the entire step yourself.
182
183 Because of the hook based system, and because CGI::Ex::App uses
184 sensible defaults, it is very easy to override a little or a lot which
185 ends up giving the developer a lot of flexibility.
186
187 Consequently, it should be possible to use CGI::Ex::App with the other
188 frameworks such as CGI::Application or CGI::Prototype. For these you
189 could simple let each "runmode" call the run_step hook of CGI::Ex::App
190 and you will instantly get all of the common process flow for free.
191
192 =head1 MAPPING URI TO STEP
193
194 The default out of the box configuration will map URIs to steps as follows:
195
196 # Assuming /cgi-bin/my_cgi is the program being run
197
198 URI: /cgi-bin/my_cgi
199 STEP: main
200 FORM: {}
201 WHY: No other information is passed. The path method is
202 called which eventually calls ->default_step which
203 defaults to "main"
204
205 URI: /cgi-bin/my_cgi?foo=bar
206 STEP: main
207 FORM: {foo => "bar"}
208 WHY: Same as previous example except that QUERY_STRING
209 information was passed and placed in form.
210
211 URI: /cgi-bin/my_cgi?step=my_step
212 STEP: my_step
213 FORM: {step => "my_step"}
214 WHY: The path method is called which looks in $self->form
215 for the key ->step_key (which defaults to "step").
216
217 URI: /cgi-bin/my_cgi?step=my_step&foo=bar
218 STEP: my_step
219 FORM: {foo => "bar", step => "my_step"}
220 WHY: Same as before but has other parameters were passed.
221
222 URI: /cgi-bin/my_cgi/my_step
223 STEP: my_step
224 FORM: {step => "my_step"}
225 WHY: The path method is called which called path_info_map_base
226 which matched $ENV{'PATH_INFO'} using the default regex
227 of qr{^/(\w+)$} and place the result in
228 $self->form->{$self->step_key}. Path then looks in
229 $self->form->{$self->step_key} for the initial step. See
230 the path_info_map_base method for more information.
231
232 URI: /cgi-bin/my_cgi/my_step?foo=bar
233 STEP: my_step
234 FORM: {foo => "bar", step => "my_step"}
235 WHY: Same as before but other parameters were passed.
236
237 URI: /cgi-bin/my_cgi/my_step?step=other_step
238 STEP: other_step
239 FORM: {step => "other_step"}
240 WHY: The same procedure took place, but when the PATH_INFO
241 string was matched, the form key "step" already existed
242 and was not replaced by the value from PATH_INFO.
243
244 The remaining examples in this section are based on the assumption
245 that the following method is installed in your script.
246
247 sub my_step_path_info_map {
248 return [
249 [qr{^/\w+/(\w+)/(\d+)$}, 'foo', 'id'],
250 [qr{^/\w+/(\w+)$}, 'foo'],
251 [qr{^/\w+/(.+)$}, 'anything_else'],
252 ];
253 }
254
255 URI: /cgi-bin/my_cgi/my_step/bar
256 STEP: my_step
257 FORM: {foo => "bar"}
258 WHY: The step was matched as in previous examples using
259 path_info_map_base. However, the form key "foo"
260 was set to "bar" because the second regex returned
261 by the path_info_map hook matched the PATH_INFO string
262 and the corresponding matched value was placed into
263 the form using the keys specified following the regex.
264
265 URI: /cgi-bin/my_cgi/my_step/bar/1234
266 STEP: my_step
267 FORM: {foo => "bar", id => "1234"}
268 WHY: Same as the previous example, except that the first
269 regex matched the string. The first regex had two
270 match groups and two form keys specified. Note that
271 it is important to order your match regexes in the
272 order that will match the most data. The third regex
273 would also match this PATH_INFO.
274
275 URI: /cgi-bin/my_cgi/my_step/some/other/type/of/data
276 STEP: my_step
277 FORM: {anything_else => 'some/other/type/of/data'}
278 WHY: Same as the previous example, except that the third
279 regex matched.
280
281 URI: /cgi-bin/my_cgi/my_step/bar?bling=blang
282 STEP: my_step
283 FORM: {foo => "bar", bling => "blang"}
284 WHY: Same as the first step, but additional QUERY_STRING
285 information was passed.
286
287 URI: /cgi-bin/my_cgi/my_step/one%20two?bar=three%20four
288 STEP: my_step
289 FORM: {anything_else => "one two", bar => "three four"}
290 WHY: The third path_info_map regex matched. Note that the
291 %20 in bar was unescaped by CGI::param, but the %20
292 in anything_else was unescaped by Apache. If you are
293 not using Apache, this behavior may vary. CGI::Ex::App
294 doesn't decode parameters mapped from PATH_INFO.
295
296 See the path method for more information about finding the initial step
297 of the path.
298
299 The form method calls CGI::Ex::form which uses CGI::param to retrieve
300 GET and POST parameters. See the form method for more information on
301 how GET and POST parameters are parsed.
302
303 See the path_info_map_base method, and path_info_map hook for more information
304 on how the path_info maps function.
305
306 A Dumper($self->dump_history) is very useful for determing what hooks have
307 taken place.
308
309 =head1 ADDING DATA VALIDATION TO A STEP
310
311 CGI::Ex::App uses CGI::Ex::Validate for its data validation. See CGI::Ex::Validate
312 for more information about the many ways you can validate your data.
313
314 The default hash_validation hook returns an empty hashref. This means that passed
315 in data is all valid and the script will automatically call the step's finalize method.
316
317 The following shows how to some contrived validation to a step called "my_step".
318
319 sub my_step_hash_validation {
320 return {
321 username => {
322 required => 1,
323 match => 'm/^(\w+)$/',
324 match_error => 'The $field field may only contain word characters',
325 max_len => 20,
326 },
327 password => {
328 required => 1,
329 max_len => 15,
330 },
331 password_verify => {
332 validate_if => 'password',
333 equals => 'password',
334 },
335 usertype => {
336 required => 1,
337 enum => [qw(animal vegetable mineral)],
338 },
339 };
340 }
341
342 The step will continue to display the html form until all of the fields pass
343 validation.
344
345 See the hash_validation hook and validate hook for more information about how
346 this takes place.
347
348 =head1 ADDING JAVASCRIPT DATA VALIDATION TO A STEP
349
350 You must first provide a hash_validation hook as explained in the previous section.
351
352 Once you have a hash_validation hook, you would place the following tags
353 into your HTML template.
354
355 <form name="[% form_name %]" method="post">
356 ...
357 </form>
358 [% js_validation %]
359
360 The "form_name" swap-in places a name on the form that the javascript returned by
361 the js_validation swap-in will be able to find and check for validity.
362
363 See the hash_validation, js_validation, and form_name hooks for more information.
364
365 Also, CGI::Ex::validate.js allows for inline errors in addition to or in replacement
366 of an alert message. To use inline errors, you must provide an element in your
367 HTML document where this inline message can be placed. The common way to do it is as
368 follows:
369
370 <input type="text" name="username"><br>
371 <span class="error" id="username_error">[% username_error %]</span>
372
373 The span around the error allows for the error css class and it provides a location
374 that the Javascript validation can populate with errors. The [% username_error %] provides
375 a location for errors generated on the server side to be swapped in. If there was no error
376 the [% username_error %] tag would default to "".
377
378 =head1 ADDING ADDITIONAL TEMPLATE VARIABLES
379
380 All variables returned by the hash_base, hash_common, hash_form, hash_swap, and
381 hash_errors hooks are available for swapping in templates.
382
383 The following shows how to add variables using the hash_swap hook on the step "main".
384
385 sub main_hash_swap {
386 return {
387 color => 'red',
388 choices => [qw(one two three)],
389 "warn" => sub { warn @_ },
390 };
391 }
392
393 You could also return the fields from the hash_common hook and they would be available
394 in both the template swapping as well as form filling.
395
396 See the hash_base, hash_common, hash_form, hash_swap, hash_errors, swap_template, and
397 template_args hooks for more information.
398
399 The default template engine used is CGI::Ex::Template which is Template::Toolkit compatible.
400 See the CGI::Ex::Template or Template::Toolkit documentation for the types of data
401 that can be passed, and for the syntax that can be used.
402
403 =head1 ADDING ADDITIONAL FORM FILL VARIABLES
404
405 All variables returned by the hash_base, hash_common, hash_form, and hash_fill hooks
406 are available for filling html fields in on templates.
407
408 The following shows how to add variables using the hash_fill hook on the step "main".
409
410 sub main_hash_fill {
411 return {
412 color => 'red',
413 choices => [qw(one two three)],
414 };
415 }
416
417 You could also return the fields from the hash_common hook and they would be available
418 in both the form filling as well as in the template swapping.
419
420 See the hash_base, hash_common, hash_form, hash_swap, hash_errors, fill_template, and
421 fill_args hooks for more information.
422
423 The default form filler is CGI::Ex::Fill which is similar to HTML::FillInForm but
424 has several benefits. See the CGI::Ex::Fill module for the available options.
425
426 =head1 SYNOPSIS (A LONG "SYNOPSIS")
427
428 This example script would most likely be in the form of a cgi, accessible via
429 the path http://yourhost.com/cgi-bin/my_app (or however you do CGIs on
430 your system. About the best way to get started is to paste the following
431 code into a cgi script (such as cgi-bin/my_app) and try it out. A detailed
432 walk-through follows in the next section. There is also a longer recipe
433 database example at the end of this document that covers other topics including
434 making your module a mod_perl handler.
435
436 ### File: /var/www/cgi-bin/my_app (depending upon Apache configuration)
437 ### --------------------------------------------
438 #!/usr/bin/perl -w
439
440 use strict;
441 use base qw(CGI::Ex::App);
442 use CGI::Ex::Dump qw(debug);
443
444 __PACKAGE__->navigate;
445 # OR
446 # my $obj = __PACKAGE__->new;
447 # $obj->navigate;
448
449 exit;
450
451 ###------------------------------------------###
452
453 sub post_navigate {
454 # show what happened
455 debug shift->dump_history;
456 }
457
458 sub main_hash_validation {
459 return {
460 'general no_alert' => 1,
461 'general no_confirm' => 1,
462 'group order' => [qw(username password password2)],
463 username => {
464 required => 1,
465 min_len => 3,
466 max_len => 30,
467 match => 'm/^\w+$/',
468 match_error => 'You may only use letters and numbers.',
469 },
470 password => {
471 required => 1,
472 min_len => 6,
473 },
474 password2 => {
475 equals => 'password',
476 },
477 };
478 }
479
480 sub main_file_print {
481 # reference to string means ref to content
482 # non-reference means filename
483 return \ "<h1>Main Step</h1>
484 <form method=post name=[% form_name %]>
485 <input type=hidden name=step>
486 <table>
487 <tr>
488 <td><b>Username:</b></td>
489 <td><input type=text name=username><span style='color:red' id=username_error>[% username_error %]</span></td>
490 </tr><tr>
491 <td><b>Password:</b></td>
492 <td><input type=text name=password><span style='color:red' id=password_error>[% password_error %]</span></td>
493 </tr><tr>
494 <td><b>Verify Password:</b></td>
495 <td><input type=text name=password2><span style='color:red' id=password2_error>[% password2_error %]</span></td>
496 </tr>
497 <tr><td colspan=2 align=right><input type=submit></td></tr>
498 </table>
499 </form>
500 [% js_validation %]
501 ";
502 }
503
504 sub main_finalize {
505 my $self = shift;
506
507 if ($self->form->{'username'} eq 'bar') {
508 $self->add_errors(username => 'A trivial check to say the username cannot be "bar"');
509 return 0;
510 }
511
512 debug $self->form, "Do something useful with form here in the finalize hook.";
513
514 ### add success step
515 $self->add_to_swap({success_msg => "We did something"});
516 $self->append_path('success');
517 $self->set_ready_validate(0);
518 return 1;
519 }
520
521 sub success_file_print {
522 \ "<div style=background:lightblue>
523 <h1>Success Step - [% success_msg %]</h1>
524 Username: <b>[% username %]</b><br>
525 Password: <b>[% password %]</b><br>
526 </div>
527 ";
528 }
529
530 __END__
531
532 Note: This example would be considerably shorter if the html file
533 (file_print) and the validation file (file_val) had been placed in
534 separate files. Though CGI::Ex::App will work "out of the box" as
535 shown it is more probable that any platform using it will customize
536 the various hooks to their own tastes (for example, switching print to
537 use a templating system other than CGI::Ex::Template).
538
539 =head1 SYNOPSIS STEP BY STEP
540
541 This section goes step by step over the previous example.
542
543 Well - we start out with the customary CGI introduction.
544
545 #!/usr/bin/perl -w
546
547 use strict;
548 use base qw(CGI::Ex::App);
549 use CGI::Ex::Dump qw(debug);
550
551 Note: the "use base" is not normally used in the "main" portion of a script.
552 It does allow us to just do __PACKAGE__->navigate.
553
554 Now we need to invoke the process:
555
556 __PACKAGE__->navigate;
557 # OR
558 # my $obj = __PACKAGE__->new;
559 # $obj->navigate;
560 exit;
561
562 Note: the "exit" isn't necessary - but it is kind of nice to infer
563 that process flow doesn't go beyond the ->navigate call.
564
565 The navigate routine is now going to try and "run" through a series of
566 steps. Navigate will call the ->path method which should return an
567 arrayref containing the valid steps. By default, if path method has
568 not been overridden, the path method will default first to the step
569 found in form key named ->step_name, then it will fall to the contents
570 of $ENV{'PATH_INFO'}. If navigation runs out of steps to run it will
571 run the step found in ->default_step which defaults to 'main'. So the
572 URI '/cgi-bin/my_app' would run the step 'main' first by default. The
573 URI '/cgi-bin/my_app?step=foo' would run the step 'foo' first. The
574 URI '/cgi-bin/my_app/bar' would run the step 'bar' first.
575
576 CGI::Ex::App allows for running steps in a preset path or each step may
577 choose the next step that should follow. The navigate
578 method will go through one step of the path at a time and see if it is
579 completed (various methods determine the definition of "completed").
580 This preset type of path can also be automated using the CGI::Path
581 module. Rather than using a preset path, CGI::Ex::App also has
582 methods that allow for dynamic changing of the path, so that each step
583 can determine which step to do next (see the jump, append_path,
584 insert_path, and replace_path methods).
585
586 During development it would be nice to see what happened during the
587 course of our navigation. This is stored in the arrayref contained in
588 ->history. There is a method that is called after all of the navigation
589 has taken place called "post_navigate". This chunk will display history after we
590 have printed the content.
591
592 sub post_navigate {
593 debug shift->dump_history;
594 } # show what happened
595
596 Ok. Finally we are looking at the methods used by each step of the path. The
597 hook mechanism of CGI::Ex::App will look first for a method ${step}_${hook_name}
598 called before falling back to the method named $hook_name. Internally in the
599 code there is a call that looks like $self->run_hook('hash_validation', $step). In
600 this case the step is main. The dispatch mechanism finds our method at the following
601 chunk of code.
602
603 sub main_hash_validation { ... }
604
605 The process flow will see if the data is ready to validate. Once it is ready
606 (usually when the user presses the submit button) the data will be validated. The
607 hash_validation hook is intended to describe the data and will be tested
608 using CGI::Ex::Validate. See the CGI::Ex::Validate perldoc for more
609 information about the many types of validation available.
610
611 sub main_file_print { ... }
612
613 The navigation process will see if user submitted information (the form)
614 is ready for validation. If not, or if validation fails, the step needs to
615 be printed. Eventually the file_print hook is called. This hook should
616 return either the filename of the template to be printed, or a reference
617 to the actual template content. In this example we return a reference
618 to the content to be printed (this is useful for prototyping applications
619 and is also fine in real world use - but generally production applications
620 use external html templates).
621
622 A few things to note about the template:
623
624 First, we add a hidden form field called step. This will be filled in
625 automatically at a later point with the current step we are on.
626
627 We provide locations to swap in inline errors.
628
629 <span style="color:red" id="username_error">[% username_error %]</span>
630
631 As part of the error html we name each span with the name of the error. This
632 will allow for us to have Javascript update the error spots when the javascript
633 finds an error.
634
635 At the very end we add the TT variable [% js_validation %]. This swap in is
636 provided by the default hash_base hook and will provide for form data to be
637 validated using javascript.
638
639 Once the process flow has deemed that the data is validated, it then calls
640 the finalize hook. Finalize is where the bulk of operations should go.
641 We'll look at it more in depth.
642
643 sub main_finalize {
644 my $self = shift;
645 my $form = $self->form;
646
647 At this point, all of the validated data is in the $form hashref.
648
649 if ($form->{'username'} eq 'bar') {
650 $self->add_errors(username => 'A trivial check to say the username cannot be "bar"');
651 return 0;
652 }
653
654 It is most likely that though the data is of the correct type and formatting,
655 it still isn't completely correct. This previous section shows a hard coded
656 test to see if the username was 'bar'. If it was then an appropriate error will
657 be set, the routine returns 0 and the run_step process knows that it needs to
658 redisplay the form page for this step. The username_error will be shown inline.
659 The program could do more complex things such as checking to see if the username
660 was already taken in a database.
661
662 debug $form, "Do something useful with form here in the finalize hook.";
663
664 This debug $form piece is simply a place holder. It is here that the program would
665 do something useful such as add the information to a database.
666
667 ### add success step
668 $self->add_to_swap({success_msg => "We did something"});
669
670 Now that we have finished finalize, we add a message that will be passed to the template
671 engine.
672
673 $self->append_path('success');
674 $self->set_ready_validate(0);
675
676 The program now needs to move on to the next step. In this case we want to
677 follow with a page that informs us we succeeded. So, we append a step named "success".
678 We also call set_ready_validate(0) to inform the navigation control that the
679 form is no longer ready to validate - which will cause the success page to
680 print without trying to validate the data. It is normally a good idea
681 to set this as leaving the engine in a "ready to validate" state can result
682 in an recursive loop (that will be caught).
683
684 return 1;
685 }
686
687 We then return 1 which tells the engine that we completed this step successfully
688 and it needs to move on to the next step.
689
690 Finally we run the "success" step because we told it to. That step isn't
691 ready to validate so it prints out the template page.
692
693 For more of a real world example, it would be good to read the sample recipe db
694 application included at the end of this document.
695
696 =head1 AVAILABLE METHODS / HOOKS
697
698 CGI::Ex::App's dispatch system works on the principles of hooks (which
699 are essentially glorified method lookups). When the run_hook method
700 is called, CGI::Ex::App will look for a corresponding method call for
701 that hook for the current step name. It is perhaps easier to show than
702 to explain.
703
704 If we are calling the "print" hook for the step "edit" we would call
705 run_hook like this:
706
707 $self->run_hook('print', 'edit', $template, \%swap, \%fill);
708
709 This would first look for a method named "edit_print". If it is unable to
710 find a method by that name, it will look for a method named "print". If it
711 is unable to find this method - it will die.
712
713 If allow_morph is set to true, the same methods are searched for but it becomes
714 possible to move some of those methods into an external package.
715
716 See the discussions under the methods named "find_hook" and "run_hook" for more details.
717
718 The following is the alphabetical list of methods and hooks.
719
720 =over 4
721
722 =item allow_morph (method)
723
724 Should return true if this step is allowed to "morph" the current App
725 object into another package. Default is false. It is passed a single
726 argument of the current step. For more granularity, if true value is
727 a hash, the step being morphed to must be in the hash.
728
729 To enable morphing for all steps, add the following:
730
731 sub allow_morph { 1 }
732
733 To enable morph on specific steps, do either of the following:
734
735 sub allow_morph {
736 return {
737 edit => 1,
738 delete => 1,
739 };
740 }
741
742 # OR
743
744 sub allow_morph {
745 my ($self, $step) = @_;
746 return $step =~ /^(edit|delete)$/;
747 }
748
749 See the morph "hook" for more information.
750
751 =item allow_nested_morph (method)
752
753 Similar to the allow_morph hook, but allows for one more level of morphing.
754 This is useful in cases where the base class was morphed early on, or
755 if a step needs to call a sub-step but morph first.
756
757 See the allow_morph and the morph method for more information.
758
759 Should return a boolean value or hash of allowed steps - just as the
760 allow_morph method does.
761
762 =item append_path (method)
763
764 Arguments are the steps to append. Can be called any time. Adds more
765 steps to the end of the current path.
766
767 =item auth_args (method)
768
769 Should return a hashref that will be passed to the new method of CGI::Ex::Auth.
770 It is augmented with arguments that integrate it into CGI::Ex::App.
771
772 See the get_valid_auth method and the CGI::Ex::Auth documentation.
773
774 sub auth_args {
775 return {
776 login_header => '<h1>My login header</h1>',
777 login_footer => '[% TRY %][% INCLUDE login/login_footer.htm %][% CATCH %]<!-- [% error %] -->[% END %]',
778 secure_hash_keys => [qw(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccccc 2222222222222)],
779 # use_blowfish => 'my_blowfish_key',
780 };
781 }
782
783 =item auth_data (method)
784
785 Contains authentication data stored during the get_valid_auth method.
786 The data is normally blessed into the CGI::Ex::Auth::Data package which
787 evaluates to false if there was an error and true if the authentication
788 was successful - so this data can be defined but false.
789
790 See the get_valid_auth method.
791
792 =item cleanup_user (method)
793
794 Installed as a hook during get_valid_auth. Allows for cleaning
795 up the username. See the get_valid_auth method.
796
797 sub cleanup_user {
798 my ($self, $user) = @_;
799 return lc $user;
800 }
801
802 =item clear_app (method)
803
804 If the same CGI::Ex::App based object is used to run multiple
805 navigate sessions, the clear_app method should be called which
806 will attempt to clear as much session information as it can.
807 The following items will be cleared:
808
809 cgix
810 vob
811 form
812 cookies
813 stash
814 path
815 path_i
816 history
817 __morph_lineage_start_index
818 __morph_lineage
819 hash_errors
820 hash_fill
821 hash_swap
822 hash_common
823
824 =item current_step (method)
825
826 Returns the current step that the nav_loop is functioning on.
827
828 =item default_step (method)
829
830 Step to show if the path runs out of steps. Default value is the
831 'default_step' property which defaults to 'main'.
832
833 If nav_loop runs of the end of the path (runs out of steps), this
834 method is called, the step is added to the path, and nav_loop calls
835 itself recursively.
836
837 =item destroy (method)
838
839 Called at the end of navigate after all other actions have run. Can
840 be used for undoing things done in the ->init method called during
841 the ->new method.
842
843 =item dump_history (method)
844
845 Show simplified trace information of which steps were called, the
846 order they were called in, the time they took to run, and a brief list
847 of the output (to see the full response returned by each hook, pass a
848 true value as the only argument to dump_history -
849 $self->dump_history(1)). Indentation is also applied to show which
850 hooks called other hooks.
851
852
853 The first line shows the amount of time elapsed for the entire
854 navigate execution. Subsequent lines contain:
855
856 Step - the name of the current step.
857 Hook - the name of the hook being called.
858 Found - the name of the method that was found.
859 Time - the total elapsed seconds that method took to run.
860 Output - the response of the hook - shown in shortened form.
861
862 Note - to get full output responses - pass a true value to
863 dump_history - or just call ->history. Times displayed are to 5
864 decimal places - this accuracy can only be provided if the Time::HiRes
865 module is installed on your system (it will only be used if installed).
866
867 It is usually best to print this history during the post_navigate
868 method as in the following:
869
870 use CGI::Ex::Dump qw(debug);
871 sub post_navigate { debug shift->dump_history }
872
873 The following is a sample output of dump_history called from the
874 sample recipe application at the end of this document. The step
875 called is "view".
876
877 debug: admin/Recipe.pm line 14
878 shift->dump_history = [
879 "Elapsed: 0.00562",
880 "view - run_step - run_step - 0.00488 - 1",
881 " view - pre_step - pre_step - 0.00003 - 0",
882 " view - skip - view_skip - 0.00004 - 0",
883 " view - prepare - prepare - 0.00003 - 1",
884 " view - info_complete - info_complete - 0.00010 - 0",
885 " view - ready_validate - ready_validate - 0.00004 - 0",
886 " view - prepared_print - prepared_print - 0.00441 - 1",
887 " view - hash_base - hash_base - 0.00009 - HASH(0x84ea6ac)",
888 " view - hash_common - view_hash_common - 0.00148 - HASH(0x8310a20)",
889 " view - hash_form - hash_form - 0.00004 - HASH(0x84eaa78)",
890 " view - hash_fill - hash_fill - 0.00003 - {}",
891 " view - hash_swap - hash_swap - 0.00003 - {}",
892 " view - hash_errors - hash_errors - 0.00003 - {}",
893 " view - print - print - 0.00236 - 1",
894 " view - file_print - file_print - 0.00024 - recipe/view.html",
895 " view - name_module - name_module - 0.00007 - recipe",
896 " view - name_step - name_step - 0.00004 - view",
897 " view - swap_template - swap_template - 0.00161 - <html> ...",
898 " view - template_args - template_args - 0.00008 - HASH(0x865abf8)",
899 " view - fill_template - fill_template - 0.00018 - 1",
900 " view - fill_args - fill_args - 0.00003 - {}",
901 " view - print_out - print_out - 0.00015 - 1",
902 " view - post_print - post_print - 0.00003 - 0"
903 ];
904
905 =item exit_nav_loop (method)
906
907 This method should not normally used but there is no problem with
908 using it on a regular basis. Essentially it is a "goto" that allows
909 for a long jump to the end of all nav_loops (even if they are
910 recursively nested). This effectively short circuits all remaining
911 hooks for the current and remaining steps. It is used to allow the
912 ->jump functionality. If the application has morphed, it will be
913 unmorphed before returning. Also - the post_navigate method will
914 still be called.
915
916 =item first_step (method)
917
918 Returns the first step of the path. Note that first_step may not be the same
919 thing as default_step if the path was overridden.
920
921 =item form (method)
922
923 Returns a hashref of the items passed to the CGI. Returns
924 $self->{form} which defaults to CGI::Ex::get_form.
925
926 =item handle_error (method)
927
928 If anything dies during execution, handle_error will be called with
929 the error that had happened. Default action is to die with that error.
930
931 =item history (method)
932
933 Returns an arrayref which contains trace history of which hooks of
934 which steps were ran. Useful for seeing what happened. In general -
935 each line of the history will show the current step, the hook
936 requested, and which hook was actually called.
937
938 The dump_history method shows a short condensed version of this
939 history which makes it easier to see what path was followed.
940
941 In general, the arrayref is free for anything to push onto which will
942 help in tracking other occurrences in the program as well.
943
944 =item init (method)
945
946 Called by the default new method. Allows for any object
947 initilizations that may need to take place. Default action does
948 nothing.
949
950 =item fill_args (hook)
951
952 Returns a hashref of args that will be passed to the CGI::Ex::Fill::fill.
953 It is augmented with the template to swap and the fill hash. This
954 could be useful if you needed to only swap a particular form on the template
955 page. Arguments are passed directly to the fill function.
956
957 sub fill_args { {target => 'my_form'} }
958
959 =item fill_template (hook)
960
961 Arguments are a template and a hashref. Takes the template that was
962 prepared using swap_template, and swaps html form fields using the
963 passed hashref. Overriding this method can control the fill behavior.
964
965 Calls the fill_args hook prior to calling CGI::Ex::Fill::fill
966
967 =item file_print (hook)
968
969 Returns a filename of the content to be used in the default print
970 hook. Adds method base_dir_rel to hook name_module, and name_step and
971 adds on the default file extension found in $self->ext_print which
972 defaults to the property $self->{ext_print} which will default to
973 ".html". Should return a filename relative to base_dir_abs that can be
974 swapped using CGI::Ex::Template, or should be a scalar reference to
975 the template content that can be swapped. This will be used by the
976 hook print.
977
978 sub base_dir_abs { '/var/www/templates' }
979 sub base_dir_rel { 'content' }
980 sub name_module { 'recipe' }
981 sub ext_print { 'html' } # default
982
983 # ->file_print('this_step')
984 # would return 'content/recipe/this_step.html'
985 # the template engine would look in '/var/www/templates'
986 # for a file by that name
987
988 It may also return a reference to a string containing the html template.
989 This is useful for prototyping applications and/or keeping all of
990 the data for the application in a single location.
991
992 =item file_val (hook)
993
994 Returns a filename containing the validation. Performs the same
995 as file_print, but uses ext_val to get the extension, and it adds
996 base_dir_abs onto the returned value (file_print is relative to
997 base_dir_abs, while file_val is fully qualified with base_dir_abs)
998
999 The file should be readable by CGI::Ex::Validate::get_validation.
1000
1001 This hook is only necessary if the hash_validation hook has not been
1002 overridden.
1003
1004 This method an also return a hashref containing the validation - but
1005 then you may have wanted to override the hash_validation hook.
1006
1007 =item finalize (hook)
1008
1009 Defaults to true. Used to do whatever needs to be done with the data once
1010 prepare has returned true and info_complete has returned true. On failure
1011 the print operations are ran. On success navigation moves on to the next
1012 step.
1013
1014 This is normally were there core logic of a script will occur (such as
1015 adding to a database, or updating a record). At this point, the data
1016 should be validated. It is possible to do additional validation
1017 and return errors using code such as the following.
1018
1019 if (! $user_is_unique) {
1020 $self->add_errors(username => 'The username was already used');
1021 return 0;
1022 }
1023
1024 =item find_hook (method)
1025
1026 Called by run_hook. Arguments are a hook name, a step name. It
1027 should return an arrayref containing the code_ref to run, and the
1028 name of the method looked for. It uses ->can to find the appropriate
1029 hook.
1030
1031 my $code = $self->hook('finalize', 'main');
1032 ### will look first for $self->main_finalize;
1033 ### will then look for $self->finalize;
1034
1035 This system is used to allow for multiple steps to be in the same
1036 file and still allow for moving some steps out to external sub classed
1037 packages (if desired).
1038
1039 If the application has successfully morphed via the morph method and
1040 allow_morph then it is not necessary to add the step name to the
1041 beginning of the method name as the morphed packages method will
1042 override the base package (it is still OK to use the full method name
1043 "${step}_hookname").
1044
1045 See the run_hook method and the morph method for more details.
1046
1047 =item forbidden_step (method)
1048
1049 Defaults to "__forbidden". The name of a step to run should the current
1050 step name be invalid, or if a step found by the default path method
1051 is invalid. See the path method.
1052
1053 =item form_name (hook)
1054
1055 Return the name of the form to attach the js validation to. Used by
1056 js_validation.
1057
1058 =item get_pass_by_user (method)
1059
1060 This method is passed a username and the authentication object. It
1061 should return the password for the given user. See the get_pass_by_user
1062 method of CGI::Ex::Auth for more information. Installed as a hook
1063 to the authentication object during the get_valid_auth method.
1064
1065 =item get_valid_auth (method)
1066
1067 If require_auth is true at either the application level or at the
1068 step level, get_valid_auth will be called.
1069
1070 It will call auth_args to get some default args to pass to
1071 CGI::Ex::Auth->new. It augments the args with sensible defaults that
1072 App already provides (such as form, cookies, and template facilities).
1073 It also installs hooks for the get_pass_by_user, cleanup_user, and verify_user
1074 hooks of CGI::Ex::Auth.
1075
1076 It stores the $auth->last_auth_data in $self->auth_data for later use. For
1077 example, to get the authenticated user:
1078
1079 sub require_auth { 1 }
1080
1081 sub cleanup_user {
1082 my ($self, $user) = @_;
1083 return lc $user;
1084 }
1085
1086 sub get_pass_by_user {
1087 my ($self, $user) = @_;
1088 my $pass = $self->some_method_to_get_the_pass($user);
1089 return $pass;
1090 }
1091
1092 sub auth_args {
1093 return {
1094 login_header => '<h1>My login header</h1>',
1095 login_footer => '[% TRY %][% INCLUDE login/login_footer.htm %][% CATCH %]<!-- [% error %] -->[% END %]',
1096 };
1097 }
1098
1099 sub main_hash_swap {
1100 my $self = shift;
1101 my $user = $self->auth_data->{'user'};
1102 return {user => $user};
1103 }
1104
1105 Successful authentication is cached for the duration of the
1106 nav_loop so multiple steps will run the full authentication routine
1107 only once.
1108
1109 Full customization of the login process and the login template can
1110 be done via the auth_args hash. See the auth_args method and
1111 CGI::Ex::Auth perldoc for more information.
1112
1113 =item hash_base (hook)
1114
1115 A hash of base items to be merged with hash_form - such as pulldown
1116 menus, javascript validation, etc. It will now also be merged with
1117 hash_fill, so it can contain default fillins as well. It can be
1118 populated by passing a hash to ->add_to_base. By default a sub
1119 similar to the following is what is used for hash_common. Note the
1120 use of values that are code refs - so that the js_validation and
1121 form_name hooks are only called if requested:
1122
1123 sub hash_base {
1124 my ($self, $step) = @_;
1125 return $self->{hash_base} ||= {
1126 script_name => $ENV{SCRIPT_NAME},
1127 js_validation => sub { $self->run_hook('js_validation', $step) },
1128 form_name => sub { $self->run_hook('form_name', $step) },
1129 };
1130 }
1131
1132 =item hash_common (hook)
1133
1134 Almost identical in function and purpose to hash_base. It is
1135 intended that hash_base be used for common items used in various
1136 scripts inheriting from a common CGI::Ex::App type parent. Hash_common
1137 is more intended for step level populating of both swap and fill.
1138
1139 =item hash_errors (hook)
1140
1141 Called in preparation for print after failed prepare, info_complete,
1142 or finalize. Should contain a hash of any errors that occurred. Will
1143 be merged into hash_form before the pass to print. Each error that
1144 occurred will be passed to method format_error before being added to
1145 the hash. If an error has occurred, the default validate will
1146 automatically add {has_errors =>1}. To the error hash at the time of
1147 validation. has_errors will also be added during the merge in case the
1148 default validate was not used. Can be populated by passing a hash to
1149 ->add_to_errors or ->add_errors.
1150
1151 =item hash_fill (hook)
1152
1153 Called in preparation for print after failed prepare, info_complete,
1154 or finalize. Should contain a hash of any items needed to be filled
1155 into the html form during print. Items from hash_form, hash_base, and
1156 hash_common will be layered together. Can be populated by passing a
1157 hash to ->add_to_fill.
1158
1159 By default - forms are sticky and data from previous requests will try
1160 and populate the form. You can use the fill_template hook to disable
1161 templating on a single page or on all pages.
1162
1163 This method can be used to pre-populate the form as well (such as on an
1164 edit step). If a form fails validation, hash_fill will also be called
1165 and will only want the submitted form fields to be sticky. You can
1166 use the ready_validate hook to prevent pre-population in these cases as
1167 follows:
1168
1169 sub edit_hash_fill {
1170 my $self = shift;
1171 my $step = shift;
1172 return {} if $self->run_hook('ready_validate', $step);
1173
1174 my %hash;
1175
1176 ### get previous values from the database
1177
1178 return \%hash;
1179 }
1180
1181 =item hash_form (hook)
1182
1183 Called in preparation for print after failed prepare, info_complete,
1184 or finalize. Defaults to ->form. Can be populated by passing a hash
1185 to ->add_to_form.
1186
1187 =item hash_swap (hook)
1188
1189 Called in preparation for print after failed prepare, info_complete,
1190 or finalize. Should contain a hash of any items needed to be swapped
1191 into the html during print. Will be merged with hash_base,
1192 hash_common, hash_form, and hash_errors. Can be populated by passing
1193 a hash to ->add_to_swap.
1194
1195 The hash will be passed as the second argument to swap_template.
1196
1197 =item hash_validation (hook)
1198
1199 Returns a hash of the validation information to check form against.
1200 By default, will look for a filename using the hook file_val and will
1201 pass it to CGI::Ex::Validate::get_validation. If no file_val is
1202 returned or if the get_validation fails, an empty hash will be returned.
1203 Validation is implemented by ->vob which loads a CGI::Ex::Validate object.
1204
1205 =item info_complete (hook)
1206
1207 Calls the ready_validate hook to see if data is ready to validate. If
1208 so it calls the validate hook to validate the data. Should make
1209 sure the data is ready and valid. Will not be run unless
1210 prepare returns true (default).
1211
1212 =item insert_path (method)
1213
1214 Arguments are the steps to insert. Can be called any time. Inserts
1215 the new steps at the current path location.
1216
1217 =item is_authed (method)
1218
1219 Returns true if the object has successful authentication data. It
1220 returns false if the object has not been authenticated.
1221
1222 =item js_uri_path (method)
1223
1224 Return the URI path where the CGI/Ex/yaml_load.js and
1225 CGI/Ex/validate.js files can be found. This will default to
1226 "$ENV{SCRIPT_NAME}/js" if the path method has not been overridden,
1227 otherwise it will default to "$ENV{SCRIPT_NAME}?step=js&js=" (the
1228 latter is more friendly with overridden paths). A default handler for
1229 the "js" step has been provided in "js_run_step" (this handler will
1230 nicely print out the javascript found in the js files which are
1231 included with this distribution. js_run_step will work properly with the
1232 default "path" handler.
1233
1234 =item js_validation (hook)
1235
1236 Requires JSON or YAML. Will return Javascript that is capable of
1237 validating the form. This is done using the capabilities of
1238 CGI::Ex::Validate. This will call the hook hash_validation which will
1239 then be encoded either json or into yaml and placed in a javascript
1240 string. It will also call the hook form_name to determine which html
1241 form to attach the validation to. The method js_uri_path is called to
1242 determine the path to the appropriate validate.js files. If the
1243 method ext_val is htm, then js_validation will return an empty string
1244 as it assumes the htm file will take care of the validation itself.
1245 In order to make use of js_validation, it must be added to the
1246 variables returned by either the hash_base, hash_common, hash_swap or
1247 hash_form hook (see examples of hash_base used in this doc).
1248
1249 By default it will try and use JSON first and then fail to YAML and
1250 then will fail to returning an html comment that does nothing.
1251
1252 =item jump (method)
1253
1254 This method should not normally be used but is fine to use it on a
1255 regular basis. It provides for moving to the next step at any point
1256 during the nav_loop. It effectively short circuits the remaining
1257 hooks for the current step. It does increment the recursion counter
1258 (which has a limit of ->recurse_limit - default 15). It is normally
1259 better to allow the other hooks in the loop to carry on their normal
1260 functions and avoid jumping. (Essentially, this hook behaves like a
1261 goto method to bypass everything else and continue at a different
1262 location in the path - there are times when it is necessary or useful
1263 to do this).
1264
1265 Jump takes a single argument which is the location in the path to jump
1266 to. This argument may be either a step name, the special strings
1267 "FIRST, LAST, CURRENT, PREVIOUS, OR NEXT" or the number of steps to
1268 jump forward (or backward) in the path. The default value, 1,
1269 indicates that CGI::Ex::App should jump to the next step (the default
1270 action for jump). A value of 0 would repeat the current step (watch
1271 out for recursion). A value of -1 would jump to the previous step.
1272 The special value of "LAST" will jump to the last step. The special
1273 value of "FIRST" will jump back to the first step. In each of these
1274 cases, the path array returned by ->path is modified to allow for the
1275 jumping (the path is modified so that the path history is not destroyed
1276 - if we were on step 3 and jumped to one, that path would contain
1277 1, 2, 3, *1, 2, 3, 4, etc and we would be at the *).
1278
1279 ### goto previous step
1280 $self->jump($self->previous_step);
1281 $self->jump('PREVIOUS');
1282 $self->jump(-1);
1283
1284 ### goto next step
1285 $self->jump($self->next_step);
1286 $self->jump('NEXT');
1287 $self->jump(1);
1288 $self->jump;
1289
1290 ### goto current step (repeat)
1291 $self->jump($self->current_step);
1292 $self->jump('CURRENT');
1293 $self->jump(0);
1294
1295 ### goto last step
1296 $self->jump($self->last_step);
1297 $self->jump('LAST');
1298
1299 ### goto first step
1300 $self->jump($self->first_step);
1301 $self->jump('FIRST');
1302
1303 =item last_step (method)
1304
1305 Returns the last step of the path. Can be used to jump to the last step.
1306
1307 =item morph (method)
1308
1309 Allows for temporarily "becoming" another object type for the
1310 execution of the current step. This allows for separating some steps
1311 out into their own packages.
1312
1313 Morph will only run if the method allow_morph returns true.
1314 Additionally if the allow_morph returns a hash ref, morph will only
1315 run if the step being morphed to is in the hash. Morph also passes
1316 the step name to allow_morph.
1317
1318 The morph call occurs at the beginning of the step loop. A
1319 corresponding unmorph call occurs before the loop is exited. An
1320 object can morph several levels deep if allow_nested_morph returns
1321 true. For example, an object running as Foo::Bar that is looping on
1322 the step "my_step" that has allow_morph = 1, will do the following:
1323
1324 Call the morph_package hook (which would default to returning
1325 Foo::Bar::MyStep in this case)
1326
1327 Translate this to a package filename (Foo/Bar/MyStep.pm) and try
1328 and require it, if the file can be required, the object is blessed
1329 into that package.
1330
1331 Call the fixup_after_morph method.
1332
1333 Continue on with the run_step for the current step.
1334
1335 At any exit point of the loop, the unmorph call is made which
1336 re-blesses the object into the original package.
1337
1338 Samples of allowing morph:
1339
1340 sub allow_morph { 1 }
1341
1342 sub allow_morph { {edit => 1} }
1343
1344 sub allow_morph { my ($self, $step) = @_; return $step eq 'edit' }
1345
1346 It is possible to call morph earlier on in the program. An example of
1347 a useful early use of morph would be as in the following code:
1348
1349 sub allow_morph { 1 }
1350
1351 sub pre_navigate {
1352 my $self = shift;
1353 if ($ENV{'PATH_INFO'} && $ENV{'PATH_INFO'} =~ s|^/(\w+)||) {
1354 my $step = $1;
1355 $self->morph($step);
1356 $ENV{'PATH_INFO'} = "/$step";
1357 $self->stash->{'base_morphed'} = 1;
1358 }
1359 return 0;
1360 }
1361
1362 sub post_navigate {
1363 my $self = shift;
1364 $self->unmorph if $self->stash->{'base_morphed'};
1365 }
1366
1367 If this code was in a module Base.pm and the cgi running was cgi/base
1368 and called:
1369
1370 Base->navigate;
1371
1372 and you created a sub module that inherited Base.pm called
1373 Base/Ball.pm -- you could then access it using cgi/base/ball. You
1374 would be able to pass it steps using either cgi/base/ball/step_name or
1375 cgi/base/ball?step=step_name - Or Base/Ball.pm could implement its
1376 own path. It should be noted that if you do an early morph, it is
1377 suggested to provide a call to unmorph. And if you want to let your
1378 early morphed object morph again - you will need to provide
1379
1380 sub allow_nested_morph { 1 }
1381
1382 With allow_nested_morph enabled you could create the file
1383 Base/Ball/StepName.pm which inherits Base/Ball.pm. The Base.pm, with
1384 the custom init and default path method, would automatically morph us
1385 first into a Base::Ball object (during init) and then into a
1386 Base::Ball::StepName object (during the navigation loop).
1387
1388 Since it is complicated to explain - it may be a bit complicated to
1389 those who will try to follow your code later. CGI::Ex::App provides
1390 many ways to do things, but use the best one for your situation.
1391
1392 =item morph_package (hook)
1393
1394 Used by morph. Return the package name to morph into during a morph
1395 call. Defaults to using the current object type as a base. For
1396 example, if the current object running is a Foo::Bar object and the
1397 step running is my_step, then morph_package will return
1398 Foo::Bar::MyStep.
1399
1400 Because of the way that run_hook works, it is possible that several
1401 steps could be located in the same external file and overriding morph_package
1402 could allow for this to happen.
1403
1404 See the morph method.
1405
1406 =item name_module (hook)
1407
1408 Return the name (relative path) that should be pre-pended to name_step
1409 during the default file_print and file_val lookups. Defaults to
1410 the value in $self->{name_module} which in turn defaults to the name
1411 of the current script.
1412
1413 cgi-bin/my_app.pl => my_app
1414 cgi/my_app => my_app
1415
1416 This method is provided so that each cgi or mod_perl application can
1417 have its own directory for storing html for its steps.
1418
1419 See the file_print method for more information.
1420
1421 =item name_step (hook)
1422
1423 Return the step (appended to name_module) that should used when
1424 looking up the file in file_print and file_val lookups. Defaults to
1425 the current step.
1426
1427 =item nav_loop (method)
1428
1429 This is the main loop runner. It figures out the current path
1430 and runs all of the appropriate hooks for each step of the path. If
1431 nav_loop runs out of steps to run (which happens if no path is set, or if
1432 all other steps run successfully), it will insert the ->default_step into
1433 the path and run nav_loop again (recursively). This way a step is always
1434 assured to run. There is a method ->recurse_limit (default 15) that
1435 will catch logic errors (such as inadvertently running the same
1436 step over and over and over because there is either no hash_validation,
1437 or the data is valid but the set_ready_validate(0) method was not called).
1438
1439 =item navigate (method)
1440
1441 Takes a class name or a CGI::Ex::App object as arguments. If a class
1442 name is given it will call the "new" method to instantiate an object
1443 by that class (passing any extra arguments to the new method). All
1444 returns from navigate will return the object.
1445
1446 The method navigate is essentially a safe wrapper around the ->nav_loop
1447 method. It will catch any dies and pass them to ->handle_error.
1448
1449 This starts the process flow for the path and its steps.
1450
1451 =item navigate_authenticated (method)
1452
1453 Same as the method navigate but sets require_auth(1) before
1454 running. See the require_auth method.
1455
1456 =item new (class method)
1457
1458 Object creator. Takes a hashref of arguments that will become the
1459 initial properties of the object. Calls the init method once the
1460 object has been blessed to allow for any other initilizations.
1461
1462 my $app = MyApp->new({name_module => 'my_app'});
1463
1464 =item next_step (hook and method)
1465
1466 Returns the next step in the path. If there is no next step, it
1467 returns the default_step.
1468
1469 It can be used as a method to return the next step in the path
1470 to pass to a method such as ->jump.
1471
1472 It is also used as a hook by the refine_path hook. If there is no
1473 more steps, it will call the next_step hook to try and find a step to
1474 append to the path.
1475
1476 =item path (method)
1477
1478 Return an arrayref (modifiable) of the steps in the path. For each
1479 step the run_step hook and all of its remaining hooks will be run.
1480
1481 Hook methods are looked up and ran using the method "run_hook" which
1482 uses the method "find_hook" to lookup the hook. A history of ran
1483 hooks is stored in the array ref returned by $self->history.
1484
1485 If path has not been defined, the method will look first in the form
1486 for a key by the name found in ->step_key. It will then look in
1487 $ENV{'PATH_INFO'}. It will use this step to create a path with that
1488 one step as its contents. If a step is passed in via either of these
1489 ways, the method will call valid_steps to make sure that the step
1490 is valid (by default valid_steps returns undef - which means that
1491 any step is valid). Any step beginning with _ can not be passed in
1492 and are intended for use on private paths. If a non-valid step is
1493 found, then path will be set to contain a single step of ->forbidden_step.
1494
1495 For the best functionality, the arrayref returned should be the same
1496 reference returned for every call to path - this ensures that other
1497 methods can add to the path (and will most likely break if the
1498 arrayref is not the same).
1499
1500 If navigation runs out of steps to run, the default step found in
1501 default_step will be run. This is what allows for us to default
1502 to the "main" step for many applications.
1503
1504 =item path_info_map (hook)
1505
1506 Used to map path_info parts to form variables. Similar to the
1507 path_info_map_base method. See the path_info_map_base method
1508 for a discussion of how to use this hook.
1509
1510 =item path_info_map_base (method)
1511
1512 Called during the default path method. It is used to custom map portions
1513 of $ENV{'PATH_INFO'} to form values. If should return an arrayref of
1514 arrayrefs where each child arrayref contains a regex qr with match parens
1515 as the first element of the array. Subsequent elements of the array are
1516 the key names to store the corresponding matched value from the regex under.
1517 The outer arrayref is iterated until it one of child arrayrefs matches
1518 against $ENV{'PATH_INFO'}. The matched values are only added to the form if
1519 there is not already a defined value for that key in the form.
1520
1521 The default value returned by this method looks something like the following:
1522
1523 sub path_info_map_base {
1524 return [[qr{^/(\w+)}, $self->step_key]];
1525 }
1526
1527 This example would map the following PATH_INFO string as follows:
1528
1529 /my_step
1530
1531 # $self->form->{'step'} now equals "my_step"
1532
1533 The following is another example:
1534
1535 sub path_info_map_base {
1536 return [
1537 [qr{^/([^/]+)/(\w+)}, 'username', $self->step_key],
1538 [qr{^/(\w+)}, $self->step_key],
1539 ];
1540 }
1541
1542 # the PATH_INFO /my_step
1543 # still results in
1544 # $self->form->{'step'} now equals "my_step"
1545
1546 # but with the PATH_INFO /my_user/my_step
1547 # $self->form->{'step'} now equals "my_step"
1548 # and $self->form->{'username'} equals "my_user"
1549
1550 In most cases there is not a need to override the path_info_map_base
1551 method, but rather override the path_info_map hook for a particular step.
1552 When the step is being run, just before the run_step hook is called, the
1553 path_info_map hook is called. The path_info_map hook is similar to
1554 the path_info_map_base method, but is used to allow step level manipulation
1555 of form based on elements in the $ENV{'PATH_INFO'}.
1556
1557 sub my_step_path_info_map {
1558 return [[qr{^/my_step/(\w+)$}, 'username']];
1559 }
1560
1561 # the PATH_INFO /my_step/my_user
1562 # results in
1563 # $self->form->{'step'} equal to "my_step" because of default path_info_map_base
1564 # and $self->form->{'username'} equals "my_user" because of my_step_path_info_map
1565
1566 The section on mapping URIs to steps has additional examples.
1567
1568 =item post_loop (method)
1569
1570 Ran after all of the steps in the loop have been processed (if
1571 prepare, info_complete, and finalize were true for each of the steps).
1572 If it returns a true value the navigation loop will be aborted. If it
1573 does not return true, navigation continues by then inserting the step
1574 $self->default_step and running $self->nav_loop again (recurses) to
1575 fall back to the default step.
1576
1577 =item post_navigate (method)
1578
1579 Called from within navigate. Called after the nav_loop has finished
1580 running but within the eval block to catch errors. Will only run if
1581 there were no errors which died during the nav_loop process.
1582
1583 It can be disabled from running by setting the _no_post_navigate
1584 property.
1585
1586 If per-step authentication is enabled and authentication fails,
1587 the post_navigate method will still be called (the post_navigate
1588 method can check the ->is_authed method to change behavior). If
1589 application level authentication is enabled and authentication
1590 fails, none of the pre_navigate, nav_loop, or post_navigate methods
1591 will be called.
1592
1593 =item post_print (hook)
1594
1595 A hook which occurs after the printing has taken place. Is only run
1596 if the information was not complete. Useful for cases such as
1597 printing rows of a database query after displaying a query form.
1598
1599 =item post_step (hook)
1600
1601 Ran at the end of the step's loop if prepare, info_complete, and
1602 finalize all returned true. Allows for cleanup. If a true value is
1603 returned, execution of navigate is returned and no more steps are
1604 processed.
1605
1606 =item pre_loop (method)
1607
1608 Called right before the navigation loop is started (at the beginning
1609 of nav_loop). At this point the path is set (but could be modified).
1610 The only argument is a reference to the path array. If it returns a
1611 true value - the navigation routine is aborted.
1612
1613 =item pre_navigate (method)
1614
1615 Called at the very beginning of the navigate method, but within the
1616 eval block to catch errors. Called before the nav_loop method is
1617 started. If a true value is returned then navigation is skipped (the
1618 nav_loop is never started).
1619
1620 =item pre_step (hook)
1621
1622 Ran at the beginning of the loop before prepare, info_compelete, and
1623 finalize are called. If it returns true, execution of nav_loop is
1624 returned and no more steps are processed..
1625
1626 =item prepare (hook)
1627
1628 Defaults to true. A hook before checking if the info_complete is true.
1629 Intended to be used to cleanup the form data.
1630
1631 =item prepared_print (hook)
1632
1633 Called when any of prepare, info_complete, or finalize fail. Prepares
1634 a form hash and a fill hash to pass to print. The form hash is primarily
1635 intended for use by the templating system. The fill hash is intended
1636 to be used to fill in any html forms.
1637
1638 =item previous_step (method)
1639
1640 List the step previous to this one. Will return '' if there is no previous step.
1641
1642 =item print (hook)
1643
1644 Take the information generated by prepared_print, format it, and print it out.
1645 Default incarnation uses CGI::Ex::Template which is compatible with
1646 Template::Toolkit. Arguments are: step name (used to call the
1647 file_print hook), swap hashref (passed to call swap_template), and
1648 fill hashref (passed to fill_template).
1649
1650 During the print call, the file_print hook is called which should
1651 return a filename or a scalar reference to the template content is
1652
1653 =item ready_validate (hook)
1654
1655 Should return true if enough information is present to run validate.
1656 Default is to look if $ENV{'REQUEST_METHOD'} is 'POST'. A common
1657 usage is to pass a common flag in the form such as 'processing' => 1
1658 and check for its presence - such as the following:
1659
1660 sub ready_validate { shift->form->{'processing'} }
1661
1662 Changing the behavior of ready_validate can help in making wizard type
1663 applications.
1664
1665 =item refine_path (hook)
1666
1667 Called at the end of nav_loop. Passed a single value indicating
1668 if there are currently more steps in the path.
1669
1670 The default implementation returns if there are still more steps
1671 in the path. Otherwise, it calls the next_step hook and appends
1672 it to the path with the append_path method, and then calls
1673 the set_ready_validate hook and passes it 0.
1674
1675 This allows you to simply put
1676
1677 sub edit_next_step { '_edit_success' }
1678
1679 In your code and it will automatically do the right thing and
1680 go to the _edit_success step.
1681
1682 =item recurse_limit (method)
1683
1684 Default 15. Maximum number of times to allow nav_loop to call itself.
1685 The recurse level will increase every time that ->jump is called, or if
1686 the end of the nav_loop is reached and the process tries to add the
1687 default_step and run it again.
1688
1689 If ->jump is used often - the recurse_limit will be reached more
1690 quickly. It is safe to raise this as high as is necessary - so long
1691 as it is intentional.
1692
1693 Often the limit is reached if a step did not have a validation hash,
1694 or if the set_ready_validate(0) method was not called once the data
1695 had been successfully validated and acted upon.
1696
1697 =item replace_path (method)
1698
1699 Arguments are the steps used to replace. Can be called any time.
1700 Replaces the remaining steps (if any) of the current path.
1701
1702 =item require_auth (method)
1703
1704 Default undef. Can return either a true value or a hashref of step names.
1705
1706 If a hashref of stepnames is returned, authentication will be turned on
1707 at the step level. In this mode if any step is accessed, the get_valid_auth
1708 method will be called. If it fails, then the nav_loop will be stopped
1709 (the post_navigate method will be called - use the is_authed method to perform
1710 different functions). Any step of the path not in the hash will not require
1711 authentication. For example, to add authentication to add authentication
1712 to the add, edit and delete steps you could do:
1713
1714 sub require_auth { {add => 1, edit => 1, delete => 1} }
1715
1716 If a non-hash true value is returned from the require_auth method then
1717 authentication will take place before the pre_navigation or the nav_loop methods.
1718 If authentication fails the navigation process is exited (the post_navigate
1719 method will not be called).
1720
1721 sub require_auth { 1 }
1722
1723 Alternatively you can also could do either of the following:
1724
1725 __PACKAGE__->navigate_authenticated; # instead of __PACKAGE__->navigate;
1726
1727 # OR
1728
1729 sub init { shift->require_auth(1) }
1730
1731 # OR
1732
1733 __PACKAGE__->new({require_auth => 1}->navigate;
1734
1735 If get_valid_auth returns true, in either case, the is_authed method will
1736 return true and the auth_data will contain the authenticated user's data.
1737 If it returns false, auth_data may possibly contain a defined but false
1738 data object with details as to why authentication failed.
1739
1740 See the get_valid_auth method.
1741
1742 =item run_hook (method)
1743
1744 Arguments are a hook name and the step to find the hook for. Calls
1745 the find_hook method to get a code ref which it then calls and returns
1746 the result passing any extra arguments to run_hook as arguments to the
1747 code ref.
1748
1749 Each call to run_hook is logged in the arrayref returned by the
1750 history method. This information is summarized in the dump_history
1751 method and is useful for tracing the flow of the program.
1752
1753 The run_hook method is part of the core of CGI::Ex::App. It allows
1754 for an intermediate layer in normal method calls. Because of
1755 run_hook, it is possible to logically override methods on a step by
1756 step basis, or override a method for all of the steps, or even to
1757 break code out into separate modules.
1758
1759 =item run_step (hook)
1760
1761 Runs all of the hooks specific to each step, beginning with pre_step
1762 and ending with post_step (for a full listing of steps, see the
1763 section on process flow). Called after ->morph($step) has been run.
1764 If this hook returns true, the nav_loop is exited (meaning the
1765 run_step hook displayed a printed page). If it returns false, the
1766 nav_loop continues on to run the next step.
1767
1768 This hook performs the same base functionality as a method defined in
1769 CGI::Applications ->run_modes. The default run_step method provides
1770 much more granular control over the flow of the CGI.
1771
1772 =item set_path (method)
1773
1774 Arguments are the steps to set. Should be called before navigation
1775 begins. This will set the path arrayref to the passed steps.
1776
1777 This method is not normally used.
1778
1779 =item set_ready_validate (hook and method)
1780
1781 Sets that the validation is ready (or not) to validate. Should set the value
1782 checked by the hook ready_validate. The following would complement the
1783 processing flag above:
1784
1785 sub set_ready_validate {
1786 my $self = shift;
1787 my ($step, $is_ready) = (@_ == 2) ? @_ : (undef, shift);
1788 if ($is_ready) {
1789 $self->form->{'processing'} = 1;
1790 } else {
1791 delete $self->form->{'processing'};
1792 }
1793 return $is_ready;
1794 }
1795
1796 Note that for this example the form key "processing" was deleted. This
1797 is so that the call to fill in any html forms won't swap in a value of
1798 zero for form elements named "processing."
1799
1800 Also note that this method may be called as a hook as in
1801
1802 $self->run_hook('set_ready_validate', $step, 0)
1803 # OR
1804 $self->set_ready_validate($step, 0);
1805
1806 Or it can take a single argument and should set the ready status
1807 regardless of the step as in:
1808
1809 $self->set_ready_validate(0);
1810
1811 =item skip (hook)
1812
1813 Ran at the beginning of the loop before prepare, info_complete, and
1814 finalize are called. If it returns true, nav_loop moves on to the
1815 next step (the current step is skipped).
1816
1817 =item stash (method)
1818
1819 Returns a hashref that can store arbitrary user space data without
1820 worrying about overwriting the internals of the application.
1821
1822 =item step_key (method)
1823
1824 Should return the keyname that will be used by the default "path"
1825 method to look for in the form. Default value is 'step'.
1826
1827 =item swap_template (hook)
1828
1829 Takes the template and hash of variables prepared in print, and processes them
1830 through the current template engine (default engine is CGI::Ex::Template).
1831
1832 Arguments are the template and the swap hashref. The template can be either a
1833 scalar reference to the actual content, or the filename of the content. If the
1834 filename is specified - it should be relative to base_dir_abs.
1835
1836 =item template_args (hook)
1837
1838 Returns a hashref of args that will be passed to the "new" method of CGI::Ex::Template.
1839 By default this hashref contains INCLUDE_PATH which is set equal to base_dir_abs.
1840 It can be augmented with any arguments that CGI::Ex::Template would understand.
1841
1842 sub template_args {
1843 return {
1844 INCLUDE_PATH => '/my/own/include/path',
1845 WRAPPER => 'wrappers/main_wrapper.html',
1846 };
1847 }
1848
1849 =item unmorph (method)
1850
1851 Allows for returning an object back to its previous blessed state if
1852 the "morph" method was successful in morphing the App object. This
1853 only happens if the object was previously morphed into another object
1854 type. Before the object is re-blessed the method fixup_before_unmorph
1855 is called.
1856
1857 See allow_morph and morph.
1858
1859 =item valid_steps (method)
1860
1861 Called by the default path method. Should return a hashref of path
1862 steps that are allowed. If the current step is not found in the hash
1863 (or is not the default_step or js_step) the path method will return a
1864 single step of ->forbidden_step and run its hooks. If no hash or undef is
1865 returned, all paths are allowed (default). A key "forbidden_step"
1866 containing the step that was not valid will be placed in the stash.
1867 Often the valid_steps method does not need to be defined as arbitrary
1868 method calls are not possible with CGI::Ex::App.
1869
1870 Any steps that begin with _ are also "not" valid for passing in via the form
1871 or path info. See the path method.
1872
1873 Also, the pre_step, skip, prepare, and info_complete hooks allow for validating
1874 the data before running finalize.
1875
1876 =item validate (hook)
1877
1878 Passed the form from $self->form. Runs validation on the information
1879 contained in the passed form. Uses CGI::Ex::Validate for the default
1880 validation. Calls the hook hash_validation to load validation hashref
1881 (an empty hash means to pass validation). Should return true if the
1882 form passed validation and false otherwise. Errors are stored as a
1883 hash in $self->{hash_errors} via method add_errors and can be checked
1884 for at a later time with method has_errors (if the default validate
1885 was used).
1886
1887 There are many ways and types to validate the data. Please see the
1888 L<CGI::Ex::Validate> module.
1889
1890 Upon success, it will look through all of the items which were
1891 validated, if any of them contain the keys append_path, insert_path,
1892 or replace_path, that method will be called with the value as
1893 arguments. This allows for the validation to apply redirection to the
1894 path. A validation item of:
1895
1896 {field => 'foo', required => 1, append_path => ['bar', 'baz']}
1897
1898 would append 'bar' and 'baz' to the path should all validation succeed.
1899
1900 =item verify_user (method)
1901
1902 Installed as a hook to CGI::Ex::App during get_valid_auth. Should return
1903 true if the user is ok. Default is to always return true. This can be
1904 used to abort early before the get_pass_by_user hook is called.
1905
1906 sub verify_user {
1907 my ($self, $user) = @_;
1908 return 0 if $user eq 'paul'; # don't let paul in
1909 return 1; # let anybody else in
1910 }
1911
1912 =back
1913
1914 =head1 HOW DO I SET COOKIES, REDIRECT, ETC
1915
1916 Often in your program you will want to set cookies or bounce to a differnt URL.
1917 This can be done using either the builtin CGI::Ex object or the built in
1918 CGI object. It is suggested that you only use the CGI::Ex methods as it will
1919 automatically send headers and method calls under cgi, mod_perl1, or mod_perl2.
1920 The following shows how to do basic items using the CGI::Ex object returned by
1921 the ->cgix method.
1922
1923 =over 4
1924
1925 =item printing content-type headers
1926
1927 ### CGI::Ex::App prints headers for you,
1928 ### but if you are printing custom types, you can send your own
1929 $self->cgix->print_content_type;
1930 # SAME AS
1931 # $self->cgix->print_content_type('text/html');
1932
1933 =item setting a cookie
1934
1935 $self->cgix->set_cookie({
1936 -name => "my_key",
1937 -value => 'Some Value',
1938 -expires => '1y',
1939 -path => '/',
1940 });
1941
1942 =item redirecting to another URL
1943
1944 $self->cgix->location_bounce("http://somewhereelse.com");
1945 $self->exit_nav_loop; # normally should do this to long jump out of navigation
1946
1947 =item making a QUERY_STRING
1948
1949 my $data = {foo => "bar", one => "two or three"};
1950 my $query = $self->cgix->make_form($data);
1951 # $query now equals "foo=bar&one=two%20or%20three"
1952
1953 =item getting form parameters
1954
1955 my $form = $self->form;
1956
1957 In this example $form would now contain a hashref of all POST and GET parameters
1958 passed to the server. The form method calls $self->cgix->get_form
1959 which in turn uses CGI->param to parse values. Fields with multiple passed
1960 values will be in the form of an arrayref.
1961
1962 =item getting cookies
1963
1964 my $cookies = $self->cookies;
1965
1966 In this example $cookies would be a hashref of all passed in cookies. The
1967 cookies method calls $self->cgix->get_cookies which in turn uses CGI->cookie
1968 to parse values.
1969
1970 =back
1971
1972 See the CGI::Ex and CGI documentation for more information.
1973
1974 =head1 COMPARISON TO OTHER APPLICATION MODULES
1975
1976 The concepts used in CGI::Ex::App are not novel or unique. However, they
1977 are all commonly used and very useful. All application builders were
1978 built because somebody observed that there are common design patterns
1979 in CGI building. CGI::Ex::App differs in that it has found more common design
1980 patterns of CGI's than other application builders and tries to get in the way
1981 less than others.
1982
1983 CGI::Ex::App is intended to be sub classed, and sub sub classed, and each step
1984 can choose to be sub classed or not. CGI::Ex::App tries to remain simple
1985 while still providing "more than one way to do it." It also tries to avoid
1986 making any sub classes have to call ->SUPER:: (although that is fine too).
1987
1988 And if what you are doing on a particular is far too complicated or custom for
1989 what CGI::Ex::App provides, CGI::Ex::App makes it trivial to override all behavior.
1990
1991 There are certainly other modules for building CGI applications. The
1992 following is a short list of other modules and how CGI::Ex::App is
1993 different.
1994
1995 =over 4
1996
1997 =item C<CGI::Application>
1998
1999 Seemingly the most well know of application builders.
2000 CGI::Ex::App is different in that it:
2001
2002 * Uses Template::Toolkit compatible CGI::Ex::Template by default
2003 CGI::Ex::App can easily use another toolkit by simply
2004 overriding the ->swap_template method.
2005 CGI::Application uses HTML::Template.
2006 * Offers integrated data validation.
2007 CGI::Application has had custom plugins created that
2008 add some of this functionality. CGI::Ex::App has the benefit
2009 that validation is automatically available in javascript as well.
2010 * Allows the user to print at any time (so long as proper headers
2011 are sent. CGI::Application requires data to be pipelined.
2012 * Offers hooks into the various phases of each step ("mode" in
2013 CGI::Application lingo). CGI::Application provides only ->runmode
2014 which is only a dispatch.
2015 * Support for easily jumping around in navigation steps.
2016 * Support for storing some steps in another package.
2017 * Integrated authentication
2018 * Integrated form filling
2019 * Integrated PATH_INFO mapping
2020
2021 CGI::Ex::App and CGI::Application are similar in that they take care
2022 of handling headers and they allow for calling other "runmodes" from
2023 within any given runmode. CGI::Ex::App's ->run_step is essentially
2024 equivalent to a method call defined in CGI::Application's ->run_modes.
2025 The ->run method of CGI::Application starts the application in the same
2026 manner as CGI::Ex::App's ->navigate call. Many of the hooks around
2027 CGI::Ex::App's ->run_step call are similar in nature to those provided by
2028 CGI::Application.
2029
2030 =item C<CGI::Prototype>
2031
2032 There are actually many similarities. One of the nicest things about
2033 CGI::Prototype is that it is extremely short (very very short). The
2034 ->activate starts the application in the same manner as CGI::Ex::App's
2035 ->navigate call. Both use Template::Toolkit as the default template
2036 system (CGI::Ex::App uses CGI::Ex::Template which is TT compatible).
2037 CGI::Ex::App is differrent in that it:
2038
2039 * Offers more hooks into the various phases of each step.
2040 * Support for easily jumping around in navigation steps.
2041 * Support for storing only some steps in another package.
2042 * Integrated data validation
2043 * Integrated authentication
2044 * Integrated form filling
2045 * Integrated PATH_INFO mapping
2046
2047 =back
2048
2049
2050 =head1 SIMPLE EXTENDED EXAMPLE
2051
2052 The following example shows the creation of a basic recipe
2053 database. It requires the use of DBD::SQLite, but that is all.
2054 Once you have configured the db_file and base_dir_abs methods
2055 of the "recipe" file, you will have a working script that
2056 does CRUD for the recipe table. The observant reader may ask - why
2057 not use Catalyst or Ruby on Rails? The observant programmer will
2058 reply that making a framework do something simple is easy, but making
2059 it do something complex is complex and any framework that tries to
2060 do the those complex things for you is too complex. CGI::Ex::App
2061 lets you write the complex logic but gives you the ability to
2062 not worry about the boring details such as template engines,
2063 or sticky forms, or cgi parameters, or data validation. Once
2064 you are setup and are running, you are only left with providing
2065 the core logic of the application.
2066
2067 ### File: /var/www/cgi-bin/recipe (depending upon Apache configuration)
2068 ### --------------------------------------------
2069 #!/usr/bin/perl -w
2070
2071 use lib qw(/var/www/lib);
2072 use Recipe;
2073 Recipe->navigate;
2074
2075
2076 ### File: /var/www/lib/Recipe.pm
2077 ### --------------------------------------------
2078 package Recipe;
2079
2080 use strict;
2081 use base qw(CGI::Ex::App);
2082 use CGI::Ex::Dump qw(debug);
2083
2084 use DBI;
2085 use DBD::SQLite;
2086
2087 ###------------------------------------------###
2088
2089 sub post_navigate {
2090 # show what happened
2091 debug shift->dump_history;
2092 }
2093
2094 sub base_dir_abs { '/var/www/templates' }
2095
2096 sub base_dir_rel { 'content' }
2097
2098 sub db_file { '/var/www/recipe.sqlite' }
2099
2100 sub dbh {
2101 my $self = shift;
2102 if (! $self->{'dbh'}) {
2103 my $file = $self->db_file;
2104 my $exists = -e $file;
2105 $self->{'dbh'} = DBI->connect("dbi:SQLite:dbname=$file", '', '',
2106 {RaiseError => 1});
2107 $self->create_tables if ! $exists;
2108 }
2109 return $self->{'dbh'};
2110 }
2111
2112 sub create_tables {
2113 my $self = shift;
2114
2115 $self->dbh->do("CREATE TABLE recipe (
2116 id INTEGER PRIMARY KEY AUTOINCREMENT,
2117 title VARCHAR(50) NOT NULL,
2118 ingredients VARCHAR(255) NOT NULL,
2119 directions VARCHAR(255) NOT NULL,
2120 date_added VARCHAR(20) NOT NULL
2121 )");
2122 }
2123
2124 ###----------------------------------------------------------------###
2125
2126 sub main_info_complete { 0 }
2127
2128 sub main_hash_swap {
2129 my $self = shift;
2130
2131 my $s = "SELECT id, title, date_added
2132 FROM recipe
2133 ORDER BY date_added";
2134 my $data = $self->dbh->selectall_arrayref($s);
2135 my @data = map {my %h; @h{qw(id title date_added)} = @$_; \%h} @$data;
2136
2137 return {
2138 recipies => \@data,
2139 };
2140 }
2141
2142 ###----------------------------------------------------------------###
2143
2144 sub add_name_step { 'edit' }
2145
2146 sub add_hash_validation {
2147 return {
2148 'group order' => [qw(title ingredients directions)],
2149 title => {
2150 required => 1,
2151 max_len => 30,
2152 },
2153 ingredients => {
2154 required => 1,
2155 max_len => 255,
2156 },
2157 directions => {
2158 required => 1,
2159 max_len => 255,
2160 },
2161 };
2162 }
2163
2164 sub add_finalize {
2165 my $self = shift;
2166 my $form = $self->form;
2167
2168 my $s = "SELECT COUNT(*) FROM recipe WHERE title = ?";
2169 my ($count) = $self->dbh->selectrow_array($s, {}, $form->{'title'});
2170 if ($count) {
2171 $self->add_errors(title => 'A recipe by this title already exists');
2172 return 0;
2173 }
2174
2175 $s = "INSERT INTO recipe (title, ingredients, directions, date_added)
2176 VALUES (?, ?, ?, ?)";
2177 $self->dbh->do($s, {}, $form->{'title'},
2178 $form->{'ingredients'},
2179 $form->{'directions'},
2180 scalar(localtime));
2181
2182 $self->add_to_form(success => "Recipe added to the database");
2183
2184 return 1;
2185 }
2186
2187 ###----------------------------------------------------------------###
2188
2189 sub edit_skip { shift->form->{'id'} ? 0 : 1 }
2190
2191 sub edit_hash_common {
2192 my $self = shift;
2193 return {} if $self->ready_validate;
2194
2195 my $sth = $self->dbh->prepare("SELECT * FROM recipe WHERE id = ?");
2196 $sth->execute($self->form->{'id'});
2197 my $hash = $sth->fetchrow_hashref;
2198
2199 return $hash;
2200 }
2201
2202 sub edit_hash_validation { shift->add_hash_validation(@_) }
2203
2204 sub edit_finalize {
2205 my $self = shift;
2206 my $form = $self->form;
2207
2208 my $s = "SELECT COUNT(*) FROM recipe WHERE title = ? AND id != ?";
2209 my ($count) = $self->dbh->selectrow_array($s, {}, $form->{'title'}, $form->{'id'});
2210 if ($count) {
2211 $self->add_errors(title => 'A recipe by this title already exists');
2212 return 0;
2213 }
2214
2215 my $s = "UPDATE recipe SET title = ?, ingredients = ?, directions = ? WHERE id = ?";
2216 $self->dbh->do($s, {}, $form->{'title'},
2217 $form->{'ingredients'},
2218 $form->{'directions'},
2219 $form->{'id'});
2220
2221 $self->add_to_form(success => "Recipe updated in the database");
2222
2223 return 1;
2224 }
2225
2226 ###----------------------------------------------------------------###
2227
2228 sub view_skip { shift->edit_skip(@_) }
2229
2230 sub view_hash_common { shift->edit_hash_common(@_) }
2231
2232 ###----------------------------------------------------------------###
2233
2234 sub delete_skip { shift->edit_skip(@_) }
2235
2236 sub delete_info_complete { 1 }
2237
2238 sub delete_finalize {
2239 my $self = shift;
2240 $self->dbh->do("DELETE FROM recipe WHERE id = ?", {}, $self->form->{'id'});
2241
2242 $self->add_to_form(success => "Recipe deleted from the database");
2243 return 1;
2244 }
2245
2246 1;
2247
2248 __END__
2249
2250
2251
2252 File: /var/www/templates/content/recipe/main.html
2253 ### --------------------------------------------
2254 <html>
2255 <head>
2256 <title>Recipe DB</title>
2257 </head>
2258 <h1>Recipe DB</h1>
2259
2260 [% IF success %]<span style="color:darkgreen"><h2>[% success %]</h2></span>[% END %]
2261
2262 <table style="border:1px solid blue">
2263 <tr><th>#</th><th>Title</th><th>Date Added</th></tr>
2264
2265 [% FOR row IN recipies %]
2266 <tr>
2267 <td>[% loop.count %].</td>
2268 <td><a href="[% script_name %]/view?id=[% row.id %]">[% row.title %]</a>
2269 (<a href="[% script_name %]/edit?id=[% row.id %]">Edit</a>)
2270 </td>
2271 <td>[% row.date_added %]</td>
2272 </tr>
2273 [% END %]
2274
2275 <tr><td colspan=2 align=right><a href="[% script_name %]/add">Add new recipe</a></td></tr>
2276 </table>
2277
2278 </html>
2279
2280
2281 File: /var/www/templates/content/recipe/edit.html
2282 ### --------------------------------------------
2283 <html>
2284 <head>
2285 <title>[% step == 'add' ? "Add" : "Edit" %] Recipe</title>
2286 </head>
2287 <h1>[% step == 'add' ? "Add" : "Edit" %] Recipe</h1>
2288
2289 <form method=post name=[% form_name %]>
2290 <input type=hidden name=step>
2291
2292 <table>
2293
2294 [% IF step != 'add' ~%]
2295 <tr>
2296 <td><b>Id:</b></td><td>[% id %]</td></tr>
2297 <input type=hidden name=id>
2298 </tr>
2299 <tr>
2300 <td><b>Date Added:</b></td><td>[% date_added %]</td></tr>
2301 </tr>
2302 [% END ~%]
2303
2304 <tr>
2305 <td valign=top><b>Title:</b></td>
2306 <td><input type=text name=title>
2307 <span style='color:red' id=title_error>[% title_error %]</span></td>
2308 </tr>
2309 <tr>
2310 <td valign=top><b>Ingredients:</b></td>
2311 <td><textarea name=ingredients rows=10 cols=40 wrap=physical></textarea>
2312 <span style='color:red' id=ingredients_error>[% ingredients_error %]</span></td>
2313 </tr>
2314 <tr>
2315 <td valign=top><b>Directions:</b></td>
2316 <td><textarea name=directions rows=10 cols=40 wrap=virtual></textarea>
2317 <span style='color:red' id=directions_error>[% directions_error %]</span></td>
2318 </tr>
2319 <tr>
2320 <td colspan=2 align=right>
2321 <input type=submit value="[% step == 'add' ? 'Add' : 'Update' %]"></td>
2322 </tr>
2323 </table>
2324 </form>
2325
2326 (<a href="[% script_name %]">Main Menu</a>)
2327 [% IF step != 'add' ~%]
2328 (<a href="[% script_name %]/delete?id=[% id %]">Delete this recipe</a>)
2329 [%~ END %]
2330
2331 [% js_validation %]
2332
2333 </html>
2334
2335
2336 File: /var/www/templates/content/recipe/view.html
2337 ### --------------------------------------------
2338 <html>
2339 <head>
2340 <title>[% title %] - Recipe DB</title>
2341 </head>
2342 <h1>[% title %]</h1>
2343 <h3>Date Added: [% date_added %]</h3>
2344
2345 <h2>Ingredients</h2>
2346 [% ingredients %]
2347
2348 <h2>Directions</h2>
2349 [% directions %]
2350
2351 <hr>
2352 (<a href="[% script_name %]">Main Menu</a>)
2353 (<a href="[% script_name %]/edit?id=[% id %]">Edit this recipe</a>)
2354
2355 </html>
2356
2357 ### --------------------------------------------
2358
2359 Notes:
2360
2361 The dbh method returns an SQLite dbh handle and auto creates the
2362 schema. You will normally want to use MySQL or Oracle, or Postgres
2363 and you will want your schema to NOT be auto-created.
2364
2365 This sample uses hand rolled SQL. Class::DBI or a similar module
2366 might make this example shorter. However, more complex cases that
2367 need to involve two or three or four tables would probably be better
2368 off using the hand crafted SQL.
2369
2370 This sample uses SQL. You could write the application to use whatever
2371 storage you want - or even to do nothing with the submitted data.
2372
2373 We had to write our own HTML (Catalyst and Ruby on Rails do this for
2374 you). For most development work - the HTML should be in a static
2375 location so that it can be worked on by designers. It is nice that
2376 the other frameworks give you stub html - but that is all it is. It
2377 is worth about as much as copying and pasting the above examples. All
2378 worthwhile HTML will go through a non-automated design/finalization
2379 process.
2380
2381 The add step used the same template as the edit step. We did
2382 this using the add_name_step hook which returned "edit". The template
2383 contains IF conditions to show different information if we were in
2384 add mode or edit mode.
2385
2386 We reused code, validation, and templates. Code and data reuse is a
2387 good thing.
2388
2389 The edit_hash_common returns an empty hashref if the form was ready to
2390 validate. When hash_common is called and the form is ready to
2391 validate, that means the form failed validation and is now printing
2392 out the page. To let us fall back and use the "sticky" form fields
2393 that were just submitted, we need to not provide values in the
2394 hash_common method.
2395
2396 We use hash_common. Values from hash_common are used for both
2397 template swapping and filling. We could have used hash_swap and
2398 hash_fill independently.
2399
2400 The hook main_info_complete is hard coded to 0. This basically says
2401 that we will never try and validate or finalize the main step - which
2402 is most often the case.
2403
2404 =head1 SEPARATING STEPS INTO SEPARATE FILES
2405
2406 It may be useful sometimes to separate some or all of the steps of an
2407 application into separate files. This is the way that CGI::Prototype
2408 works. This is useful in cases were some steps and their hooks are
2409 overly large - or are seldom used.
2410
2411 The following modifications can be made to the previous "recipe db"
2412 example that would move the "delete" step into its own file. Similar
2413 actions can be taken to break other steps into their own file as well.
2414
2415
2416 ### File: /var/www/lib/Recipe.pm
2417 ### Same as before but add the following line:
2418 ### --------------------------------------------
2419
2420 sub allow_morph { 1 }
2421
2422
2423 ### File: /var/www/lib/Recipe/Delete.pm
2424 ### Remove the delete_* subs from lib/Recipe.pm
2425 ### --------------------------------------------
2426 package Recipe::Delete;
2427
2428 use strict;
2429 use base qw(Recipe);
2430
2431 sub skip { shift->edit_skip(@_) }
2432
2433 sub info_complete { 1 }
2434
2435 sub finalize {
2436 my $self = shift;
2437 $self->dbh->do("DELETE FROM recipe WHERE id = ?", {}, $self->form->{'id'});
2438
2439 $self->add_to_form(success => "Recipe deleted from the database");
2440 return 1;
2441 }
2442
2443
2444 Notes:
2445
2446 The hooks that are called (skip, info_complete, and finalize) do not
2447 have to be prefixed with the step name because they are now in their
2448 own individual package space. However, they could still be named
2449 delete_skip, delete_info_complete, and delete_finalize and the
2450 run_hook method will find them (this would allow several steps with
2451 the same "morph_package" to still be stored in the same external
2452 module).
2453
2454 The method allow_morph is passed the step that we are attempting to
2455 morph to. If allow_morph returns true every time, then it will try
2456 and require the extra packages every time that step is ran. You could
2457 limit the morphing process to run only on certain steps by using code
2458 similar to the following:
2459
2460 sub allow_morph { return {delete => 1} }
2461
2462 # OR
2463
2464 sub allow_morph {
2465 my ($self, $step) = @_;
2466 return ($step eq 'delete') ? 1 : 0;
2467 }
2468
2469 The CGI::Ex::App temporarily blesses the object into the
2470 "morph_package" for the duration of the step and re-blesses it into the
2471 original package upon exit. See the morph method and allow_morph for more
2472 information.
2473
2474 =head1 RUNNING UNDER MOD_PERL
2475
2476 The previous samples are essentially suitable for running under flat CGI,
2477 Fast CGI, or mod_perl Registry or mod_perl PerlRun type environments. It
2478 is very easy to move the previous example to be a true mod_perl handler.
2479
2480 To convert the previous recipe example, simply add the following:
2481
2482 ### File: /var/www/lib/Recipe.pm
2483 ### Same as before but add the following lines:
2484 ### --------------------------------------------
2485
2486 sub handler {
2487 Recipe->navigate;
2488 return;
2489 }
2490
2491
2492 ### File: apache2.conf - or whatever your apache conf file is.
2493 ### --------------------------------------------
2494 <Location /recipe>
2495 SetHandler perl-script
2496 PerlHandler Recipe
2497 </Location>
2498
2499 Notes:
2500
2501 Both the /cgi-bin/recipe version and the /recipe version can co-exist.
2502 One of them will be a normal cgi and the other will correctly use
2503 mod_perl hooks for headers.
2504
2505 Setting the location to /recipe means that the $ENV{SCRIPT_NAME} will
2506 also be set to /recipe. This means that name_module method will
2507 resolve to "recipe". If a different URI location is desired such as
2508 "/my_cool_recipe" but the program is to use the same template content
2509 (in the /var/www/templates/content/recipe directory), then we would
2510 need to explicitly set the "name_module" parameter. It could be done
2511 in either of the following ways:
2512
2513 ### File: /var/www/lib/Recipe.pm
2514 ### Same as before but add the following line:
2515 ### --------------------------------------------
2516
2517 sub name_module { 'recipe' }
2518
2519 # OR
2520
2521 sub init {
2522 my $self = shift;
2523 $self->{'name_module'} = 'recipe';
2524 }
2525
2526 In most use cases it isn't necessary to set name_module, but it also
2527 doesn't hurt and in all cases it is more descriptive to anybody who is
2528 going to maintain the code later.
2529
2530 =head1 ADDING AUTHENTICATION TO THE ENTIRE APPLICATION
2531
2532 Having authentication is sometimes a good thing. To force
2533 the entire application to be authenticated (require a valid username
2534 and password before doing anything) you could do the following.
2535
2536 ### File: /var/www/lib/Recipe.pm
2537 ### Same as before but add
2538 ### --------------------------------------------
2539
2540 sub get_pass_by_user {
2541 my $self = shift;
2542 my $user = shift;
2543 my $pass = $self->lookup_and_cache_the_pass($user);
2544 return $pass;
2545 }
2546
2547
2548 ### File: /var/www/cgi-bin/recipe (depending upon Apache configuration)
2549 ### Change the line with ->navigate; to
2550 ### --------------------------------------------
2551
2552 Recipe->navigate_authenticated;
2553
2554 # OR
2555
2556 ### File: /var/www/lib/Recipe.pm
2557 ### Same as before but add
2558 ### --------------------------------------------
2559
2560 sub require_auth { 1 }
2561
2562 # OR
2563
2564 ### File: /var/www/lib/Recipe.pm
2565 ### Same as before but add
2566 ### --------------------------------------------
2567
2568 sub init { shift->require_auth(1) }
2569
2570 See the require_auth, get_valid_auth, and auth_args methods for more information.
2571 Also see the L<CGI::Ex::Auth> perldoc.
2572
2573 =head1 ADDING AUTHENTICATION TO INDIVIDUAL STEPS
2574
2575 Sometimes you may only want to have certain steps require
2576 authentication. For example, in the previous recipe example we
2577 might want to let the main and view steps be accessible to anybody,
2578 but require authentication for the add, edit, and delete steps.
2579
2580 To do this, we would do the following to the original example (the
2581 navigation must start with ->navigate. Starting with ->navigate_authenticated
2582 will cause all steps to require validation):
2583
2584 ### File: /var/www/lib/Recipe.pm
2585 ### Same as before but add
2586 ### --------------------------------------------
2587
2588 sub get_pass_by_user {
2589 my $self = shift;
2590 my $user = shift;
2591 my $pass = $self->lookup_and_cache_the_pass($user);
2592 return $pass;
2593 }
2594
2595 sub require_auth { {add => 1, edit => 1, delete => 1} }
2596
2597 That's it. The add, edit, and delete steps will now require authentication.
2598 See the require_auth, get_valid_auth, and auth_args methods for more information.
2599 Also see the L<CGI::Ex::Auth> perldoc.
2600
2601 =head1 THANKS
2602
2603 The following corporation and individuals contributed in some part to
2604 the original versions.
2605
2606 Bizhosting.com - giving a problem that fit basic design patterns.
2607
2608 Earl Cahill - pushing the idea of more generic frameworks.
2609
2610 Adam Erickson - design feedback, bugfixing, feature suggestions.
2611
2612 James Lance - design feedback, bugfixing, feature suggestions.
2613
2614 =head1 AUTHOR
2615
2616 Paul Seamons <paul at seamons dot com>
2617
2618 =cut
This page took 0.160398 seconds and 4 git commands to generate.