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