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