]> Dogcows Code - chaz/p5-CGI-Ex/blobdiff - lib/CGI/Ex/App.pod
CGI::Ex 2.24
[chaz/p5-CGI-Ex] / lib / CGI / Ex / App.pod
index e7c827d038e110c1cc0c719af8b968a0d473c1f2..2967cbe3972d4bdf5caa4aff09db3c0c9978b5e3 100644 (file)
 
 CGI::Ex::App - Anti-framework application framework.
 
+=head1 SYNOPSIS
+
+A basic example:
+
+    -------- File: /cgi-bin/my_cgi --------
+
+    #!/usr/bin/perl -w
+
+    use strict;
+    use base qw(CGI::Ex::App);
+
+    __PACKAGE__->navigate;
+    exit;
+
+    sub main_file_print {
+        return \ "Hello World!";
+    }
+
+Well, you should put your content in an external file...
+
+    -------- File: /cgi-bin/my_cgi --------
+
+    #!/usr/bin/perl -w
+
+    use strict;
+    use base qw(CGI::Ex::App);
+
+    __PACKAGE__->navigate;
+
+    sub template_path { '/var/www/templates' }
+
+
+    -------- File: /var/www/templates/my_cgi/main.html --------
+
+    Hello World!
+
+How about if we want to add substitutions...
+
+    -------- File: /cgi-bin/my_cgi --------
+
+    #!/usr/bin/perl -w
+
+    use strict;
+    use base qw(CGI::Ex::App);
+
+    __PACKAGE__->navigate;
+
+    sub template_path { '/var/www/templates' }
+
+    sub main_hash_swap {
+        my $self = shift;
+        return {
+            greeting => 'Hello',
+            date     => sub { scalar localtime },
+        };
+    }
+
+
+    -------- File: /var/www/templates/my_cgi/main.html --------
+
+    [% greeting %] World! ([% date %])
+
+
+How about a form with validation (inluding javascript validation)...
+
+    -------- File: /cgi-bin/my_cgi --------
+
+    #!/usr/bin/perl -w
+
+    use strict;
+    use base qw(CGI::Ex::App);
+
+    __PACKAGE__->navigate;
+
+    sub template_path { '/var/www/templates' }
+
+    sub main_hash_swap { {date => sub { scalar localtime }} }
+
+    sub main_hash_fill {
+        return {
+            guess => 50,
+        };
+    }
+
+    sub main_hash_validation {
+        return {
+            guess => {
+                required => 1,
+                compare1       => '<= 100',
+                compare1_error => 'Please enter a value less than 101',
+                compare2       => '>  0',
+                compare2_error => 'Please enter a value greater than 0',
+            },
+        };
+    }
+
+    sub main_finalize {
+        my $self   = shift;
+        my $form   = $self->form;
+
+        $self->add_to_form({was_correct => ($form->{'guess'} == 23)});
+
+        return 0; # indicate to show the page without trying to move along
+    }
+
+
+    -------- File: /var/www/templates/my_cgi/main.html --------
+
+    <h2>Hello World! ([% date %])</h2>
+
+    [% IF was_correct %]
+       <b>Correct!</b> - The number was [% guess %].<br>
+    [% ELSIF guess %]
+       <b>Incorrect</b> - The number was not [% guess %].<br>
+    [% END %]
+
+    <form name="[% form_name %]" method="post">
+
+    Enter a number between 1 and 100: <input type="text" name="guess"><br>
+    <span id="guess_error" style="color:red">[% guess_error %]</span><br>
+
+    <input type="submit">
+    </form>
+
+    [% js_validation %]
+
+
+There are infinite possibilities.  There is a longer "SYNOPSIS" after
+the process flow discussion and more examples near the end of this
+document.  It is interesting to note that there have been no databases
+so far.  It is very, very difficult to find a single database
+abstraction that fits every model.  CGI::Ex::App is Controller/Viewer
+that is somewhat Model agnostic and doesn't come with any default
+database abstraction.
+
 =head1 DESCRIPTION
 
-Fill in the blanks and get a ready made web application.  This module
-is somewhat similar in spirit to CGI::Application, CGI::Path, and
-CGI::Builder and any other "CGI framework."  As with the others,
-CGI::Ex::App tries to do as much of the mundane things, in a simple
-manner, without getting in the developer's way.  Your mileage may vary.
+Fill in the blanks and get a ready made web application.
+
+This module is somewhat similar in spirit to CGI::Application,
+CGI::Path, and CGI::Builder and any other "CGI framework."  As with
+the others, CGI::Ex::App tries to do as much of the mundane things, in
+a simple manner, without getting in the developer's way.  However,
+there are various design patterns for CGI applications that
+CGI::Ex::App handles for you that the other frameworks require you to
+bring in extra support.  The entire CGI::Ex suite has been taylored to
+work seamlessly together.  Your mileage in building applications may
+vary.
 
 If you build applications that submit user information, validate it,
 re-display it, fill in forms, or separate logic into separate modules,
 then this module may be for you.  If all you need is a dispatch
-engine, then this still may be for you.  If all want is to look at
+engine, then this still may be for you.  If all you want is to look at
 user passed information, then this may still be for you.  If you like
 writing bare metal code, this could still be for you.  If you don't want
 to write any code, this module will help - but you still need to
-provide you key actions.
+provide your key actions and html.
+
+One of the great benefits of CGI::Ex::App vs. Catalyst or Rails style
+frameworks is that the model of CGI::Ex::App can be much more abstract.
+And models often are abstract.
+
+=head1 DEFAULT PROCESS FLOW
+
+The following pseudo-code describes the process flow
+of the CGI::Ex::App framework.  Several portions of the flow
+are encapsulated in hooks which may be completely overridden to give
+different flow.  All of the default actions are shown.  It may look
+like a lot to follow, but if the process is broken down into the
+discrete operations of step iteration, data validation, and template
+printing the flow feels more natural.
+
+=head2 navigate
+
+The process starts off by calling ->navigate.
+
+    navigate {
+        eval {
+            ->pre_navigate
+            ->nav_loop
+            ->post_navigate
+        }
+        # dying errors will run the ->handle_error method
+
+        ->destroy
+    }
+
+=head2 nav_loop
+
+The nav_loop method will run as follows:
+
+    nav_loop {
+        ->path (get the array of path steps)
+            # ->path_info_map_base (method - map ENV PATH_INFO to form)
+            # look in ->form for ->step_key
+            # make sure step is in ->valid_steps (if defined)
+
+        ->pre_loop($path)
+            # navigation stops if true
+
+        foreach step of path {
+
+            ->require_auth (hook)
+                # exits nav_loop if true
+
+            ->morph
+                # check ->allow_morph (hook)
+                # check ->allow_nested_morph
+                # ->morph_package (hook - get the package to bless into)
+                # ->fixup_after_morph if morph_package exists
+                # if no package is found, process continues in current file
+
+            ->path_info_map (hook - map PATH_INFO to form)
+
+            ->run_step (hook)
+
+            ->refine_path (hook)
+                # only called if run_step returned false (page not printed)
+                ->next_step (hook) # find next step and add to path
+                ->set_ready_validate(0) (hook)
+
+            ->unmorph
+                # only called if morph worked
+                # ->fixup_before_unmorph if blessed to current package
+
+            # exit loop if ->run_step returned true (page printed)
+
+        } end of foreach step
+
+        ->post_loop
+            # navigation stops if true
+
+        ->default_step
+        ->insert_path (puts the default step into the path)
+        ->nav_loop (called again recursively)
+
+    } end of nav_loop
+
+=head2 run_step (hook)
+
+For each step of the path the following methods will be run
+during the run_step hook.
+
+    run_step {
+        ->pre_step (hook)
+            # skips this step if true and exit nav_loop
+
+        ->skip (hook)
+            # skips this step if true and stays in nav_loop
+
+        ->prepare (hook - defaults to true)
+
+        ->info_complete (hook - ran if prepare was true)
+            ->ready_validate (hook)
+                ->validate_when_data (hook)
+                # returns false from info_complete if ! ready_validate
+            ->validate (hook - uses CGI::Ex::Validate to validate form info)
+                ->hash_validation (hook)
+                   ->file_val (hook)
+                       ->vob_path (defaults to template_path)
+                       ->base_dir_rel
+                       ->name_module
+                       ->name_step
+                       ->ext_val
+            # returns true if validate is true or if nothing to validate
+
+        ->finalize (hook - defaults to true - ran if prepare and info_complete were true)
+
+        if ! ->prepare || ! ->info_complete || ! ->finalize {
+            ->prepared_print
+                ->hash_base (hook)
+                ->hash_common (hook)
+                ->hash_form (hook)
+                ->hash_fill (hook)
+                ->hash_swap (hook)
+                ->hash_errors (hook)
+                # merge form, base, common, and fill into merged fill
+                # merge form, base, common, swap, and errors into merged swap
+                ->print (hook - passed current step, merged swap hash, and merged fill)
+                     ->file_print (hook - uses base_dir_rel, name_module, name_step, ext_print)
+                     ->swap_template (hook - processes the file with CGI::Ex::Template)
+                          ->template_args (hook - passed to CGI::Ex::Template->new)
+                     ->fill_template (hook - fills the any forms with CGI::Ex::Fill)
+                          ->fill_args (hook - passed to CGI::Ex::Fill::fill)
+                     ->print_out (hook - print headers and the content to STDOUT)
+
+            ->post_print (hook - used for anything after the print process)
+
+            # return true to exit from nav_loop
+        }
+
+        ->post_step (hook)
+            # exits nav_loop if true
+
+    } end of run_step
+
+It is important to learn the function and placement of each of the
+hooks in the process flow in order to make the most of CGI::Ex::App.
+It is enough to begin by learning a few common hooks - such as
+hash_validation, hash_swap, and finalize, and then learn about other
+hooks as needs arise.  Sometimes, it is enough to simply override the
+run_step hook and take care of processing the entire step yourself.
+
+Because of the hook based system, and because CGI::Ex::App uses
+sensible defaults, it is very easy to override a little or a lot which
+ends up giving the developer a lot of flexibility.
+
+Additionally, it should be possible to use CGI::Ex::App with the other
+frameworks such as CGI::Application or CGI::Prototype.  For these you
+could simple let each "runmode" call the run_step hook of CGI::Ex::App
+and you will instantly get all of the common process flow for free.
+
+=head1 MAPPING URI TO STEP
+
+The default out of the box configuration will map URIs to steps as follows:
+
+    # Assuming /cgi-bin/my_app is the program being run
+
+   URI:  /cgi-bin/my_app
+    STEP: main
+    FORM: {}
+    WHY:  No other information is passed.  The path method is
+          called which eventually calls ->default_step which
+          defaults to "main"
+
+   URI:  /cgi-bin/my_app?foo=bar
+    STEP: main
+    FORM: {foo => "bar"}
+    WHY:  Same as previous example except that QUERY_STRING
+          information was passed and placed in form.
+
+   URI:  /cgi-bin/my_app?step=my_step
+    STEP: my_step
+    FORM: {step => "my_step"}
+    WHY:  The path method is called which looks in $self->form
+          for the key ->step_key (which defaults to "step").
+
+   URI:  /cgi-bin/my_app?step=my_step&foo=bar
+    STEP: my_step
+    FORM: {foo => "bar", step => "my_step"}
+    WHY:  Same as before but another parameter was passed.
+
+   URI:  /cgi-bin/my_app/my_step
+    STEP: my_step
+    FORM: {step => "my_step"}
+    WHY:  The path method is called which called path_info_map_base
+          which matched $ENV{'PATH_INFO'} using the default regex
+          of qr{^/(\w+)$} and place the result in
+          $self->form->{$self->step_key}.  Path then looks in
+          $self->form->{$self->step_key} for the initial step. See
+          the path_info_map_base method for more information.
+
+   URI:  /cgi-bin/my_app/my_step?foo=bar
+    STEP: my_step
+    FORM: {foo => "bar", step => "my_step"}
+    WHY:  Same as before but other parameters were passed.
+
+   URI:  /cgi-bin/my_app/my_step?step=other_step
+    STEP: other_step
+    FORM: {step => "other_step"}
+    WHY:  The same procedure took place, but when the PATH_INFO
+          string was matched, the form key "step" already existed
+          and was not replaced by the value from PATH_INFO.
+
+The remaining examples in this section are based on the assumption
+that the following method is installed in your script.
+
+    sub my_step_path_info_map {
+        return [
+            [qr{^/\w+/(\w+)/(\d+)$}, 'foo', 'id'],
+            [qr{^/\w+/(\w+)$}, 'foo'],
+            [qr{^/\w+/(.+)$}, 'anything_else'],
+        ];
+    }
+
+   URI:  /cgi-bin/my_app/my_step/bar
+    STEP: my_step
+    FORM: {foo => "bar"}
+    WHY:  The step was matched as in previous examples using
+          path_info_map_base.  However, the form key "foo"
+          was set to "bar" because the second regex returned
+          by the path_info_map hook matched the PATH_INFO string
+          and the corresponding matched value was placed into
+          the form using the keys specified following the regex.
+
+   URI:  /cgi-bin/my_app/my_step/bar/1234
+    STEP: my_step
+    FORM: {foo => "bar", id => "1234"}
+    WHY:  Same as the previous example, except that the first
+          regex matched the string.  The first regex had two
+          match groups and two form keys specified.  Note that
+          it is important to order your match regexes in the
+          order that will match the most data.  The third regex
+          would also match this PATH_INFO.
+
+   URI:  /cgi-bin/my_app/my_step/some/other/type/of/data
+    STEP: my_step
+    FORM: {anything_else => 'some/other/type/of/data'}
+    WHY:  Same as the previous example, except that the third
+          regex matched.
+
+   URI:  /cgi-bin/my_app/my_step/bar?bling=blang
+    STEP: my_step
+    FORM: {foo => "bar", bling => "blang"}
+    WHY:  Same as the first sample, but additional QUERY_STRING
+          information was passed.
+
+   URI:  /cgi-bin/my_app/my_step/one%20two?bar=three%20four
+    STEP: my_step
+    FORM: {anything_else => "one two", bar => "three four"}
+    WHY:  The third path_info_map regex matched.  Note that the
+          %20 in bar was unescaped by CGI::param, but the %20
+          in anything_else was unescaped by Apache.  If you are
+          not using Apache, this behavior may vary.  CGI::Ex::App
+          doesn't decode parameters mapped from PATH_INFO.
+
+See the path method for more information about finding the initial step
+of the path.
+
+The form method calls CGI::Ex::form which uses CGI::param to retrieve
+GET and POST parameters.  See the form method for more information on
+how GET and POST parameters are parsed.
+
+See the path_info_map_base method, and path_info_map hook for more information
+on how the path_info maps function.
+
+Using the following code is very useful for determing what hooks have
+taken place:
+
+   use CGI::Ex::Dump qw(debug);
+
+   sub post_navigate {
+       my $self = shift;
+       debug $self->dump_history, $self->form;
+   }
+
+=head1 ADDING DATA VALIDATION TO A STEP
+
+CGI::Ex::App uses CGI::Ex::Validate for its data validation.  See CGI::Ex::Validate
+for more information about the many ways you can validate your data.
+
+The default hash_validation hook returns an empty hashref.  This means that passed
+in data is all valid and the script will automatically call the step's finalize method.
+
+The following shows how to add some contrived validation to a step called "my_step".
+
+    sub my_step_hash_validation {
+        return {
+            username => {
+                required    => 1,
+                match       => 'm/^(\w+)$/',
+                match_error => 'The $field field may only contain word characters',
+                max_len     => 20,
+            },
+            password => {
+                required => 1,
+                max_len  => 15,
+            },
+            password_verify => {
+                validate_if => 'password',
+                equals      => 'password',
+            },
+            usertype => {
+                required => 1,
+                enum     => [qw(animal vegetable mineral)],
+            },
+        };
+    }
+
+The step will continue to display the html form until all of the fields pass
+validation.
+
+See the hash_validation hook and validate hook for more information about how
+this takes place.
+
+=head1 ADDING JAVASCRIPT DATA VALIDATION TO A STEP
+
+You must first provide a hash_validation hook as explained in the previous section.
+
+Once you have a hash_validation hook, you would place the following tags
+into your HTML template.
+
+    <form name="[% form_name %]" method="post">
+    ...
+    </form>
+    [% js_validation %]
+
+The "form_name" swap-in places a name on the form that the javascript returned by
+the js_validation swap-in will be able to find and check for validity.
+
+See the hash_validation, js_validation, and form_name hooks for more information.
+
+Also, CGI::Ex::validate.js allows for inline errors in addition to or in replacement
+of an alert message.  To use inline errors, you must provide an element in your
+HTML document where this inline message can be placed.  The common way to do it is as
+follows:
+
+    <input type="text" name="username"><br>
+    <span class="error" id="username_error">[% username_error %]</span>
+
+The span around the error allows for the error css class and it provides a location
+that the Javascript validation can populate with errors.  The [% username_error %] provides
+a location for errors generated on the server side to be swapped in.  If there was no error
+the [% username_error %] tag would default to "".
+
+=head1 ADDING ADDITIONAL TEMPLATE VARIABLES
+
+All variables returned by the hash_base, hash_common, hash_form, hash_swap, and
+hash_errors hooks are available for swapping in templates.
+
+The following shows how to add variables using the hash_swap hook on the step "main".
+
+    sub main_hash_swap {
+        return {
+            color   => 'red',
+            choices => [qw(one two three)],
+            "warn"  => sub { warn @_ },
+        };
+    }
+
+You could also return the fields from the hash_common hook and they
+would be available in both the template swapping as well as form
+filling.
+
+See the hash_base, hash_common, hash_form, hash_swap, hash_errors,
+swap_template, and template_args hooks for more information.
+
+The default template engine used is CGI::Ex::Template which is now a subclass
+of Template::Alloy.  The default interface used is TT which is the
+Template::Toolkit interface.  Template::Alloy allows for using TT documents,
+HTML::Template documents, HTML::Template::Expr documents, Text::Tmpl documents,
+or Velocity (VTL) documents.  See the L<Template::Alloy> documentation
+for more information.
+
+=head1 ADDING ADDITIONAL FORM FILL VARIABLES
+
+All variables returned by the hash_base, hash_common, hash_form, and hash_fill hooks
+are available for filling html fields in on templates.
+
+The following shows how to add variables using the hash_fill hook on the step "main".
+
+    sub main_hash_fill {
+        return {
+            color   => 'red',
+            choices => [qw(one two three)],
+        };
+    }
+
+You could also return the fields from the hash_common hook and they would be available
+in both the form filling as well as in the template swapping.
+
+See the hash_base, hash_common, hash_form, hash_swap, hash_errors, fill_template, and
+fill_args hooks for more information.
+
+The default form filler is CGI::Ex::Fill which is similar to HTML::FillInForm but
+has several benefits.  See the CGI::Ex::Fill module for the available options.
 
+=head1 FINDING TEMPLATES AND VALIDATION FILES
+
+CGI::Ex::App tries to help your applications use a good template directory layout, but allows
+for you to override everything.
+
+External template files are used for storing your html templates and
+for storing your validation files (if you use externally stored
+validation files).
+
+The default file_print hook will look for content on your file system,
+but it can also be completely overridden to return a reference to a
+scalar containing the contents of your file (beginning with version 2.14
+string references can be cached which makes templates passed this way
+"first class" citizens).  Actually it can return
+anything that Template::Alloy (Template::Toolkit compatible) will
+treat as input.  This templated html is displayed to the user during
+any step that enters the "print" phase.
+
+Similarly the default file_val hook will look for a validation file on
+the file system, but it too can return a reference to a scalar
+containing the contents of a validation file.  It may actually return
+anything that the CGI::Ex::Validate get_validation method is able to
+understand.  This validation is used by the default "info_complete"
+method for verifying if the submitted information passes its specific
+checks.  A more common way of inlining validation is to return a
+validation hash from a hash_validation hook override.
+
+If the default file_print and file_val hooks are used, the following methods
+are employed for finding templates and validation files on your filesystem (they
+are also documented more in the HOOKS AND METHODS section.
+
+=over 4
+
+=item template_path
+
+Absolute path or arrayref of paths to the base templates directory.  Defaults to
+base_dir_abs which defaults to ['.'].
+
+=item base_dir_rel
+
+Relative path inside of the template_path directory where content can be found.  Default "".
+
+=item name_module
+
+Directory inside of base_dir_rel where files for the current CGI (module) will be
+stored.  Default value is $ENV{SCRIPT_NAME} with path and extension removed.
+
+=item name_step
+
+Used with ext_print and ext_val for creating the filename that will be looked for
+inside of the name_module directory.  Default value is the current step.
+
+=item ext_print and ext_val
+
+Filename extensions added to name_step to create the filename looked for
+inside of the name_module directory.  Default is "html" for ext_print and "val"
+for ext_val.
+
+=back
+
+It may be easier to understand the usage of each of these methods by showing
+a contrived example.  The following is a hypothetical layout for your templates:
+
+    /home/user/templates/
+    /home/user/templates/chunks/
+    /home/user/templates/wrappers/
+    /home/user/templates/content/
+    /home/user/templates/content/my_app/
+    /home/user/templates/content/my_app/main.html
+    /home/user/templates/content/my_app/step1.html
+    /home/user/templates/content/my_app/step1.val
+    /home/user/templates/content/another_cgi/main.html
+
+In this example we would most likely set values as follows:
+
+    template_path /home/user/templates
+    base_dir_rel  content
+    name_module   my_app
+
+The name_module method defaults to the name of the running program, but
+with the path and extension removed.  So if we were running
+/cgi-bin/my_app.pl, /cgi-bin/my_app, or /anypath/my_app, then
+name_module would default to "my_app" and we wouldn't have to
+hard code the value.  Often it is wise to set the value anyway so
+that we can change the name of the cgi script without effecting
+where template content should be stored.
+
+Continuing with the example and assuming that name of the step that
+the user has requested is "step1" then the following values would be
+returned:
+
+    template_path /home/user/templates
+    base_dir_rel  content
+    name_module   my_app
+    name_step     step1
+    ext_print     html
+    ext_val       val
+
+    file_print    content/my_app/step1.html
+    file_val      /home/user/templates/content/my_app/step1.val
+
+The call to the template engine would look something like
+the following:
+
+    my $t = $self->template_obj({
+        INCLUDE_PATH => $self->template_path, # defaults to base_dir_abs
+    });
+
+    $t->process($self->file_print($step), \%vars);
+
+The template engine would then look for the relative file
+inside of the absolute paths (from template_path).
+
+The call to the validation engine would pass the absolute
+filename that is returned by file_val.
+
+The name_module and name_step methods can return filenames with
+additional directories included.  The previous example could
+also have been setup using the following values:
+
+    template_path /home/user/templates
+    base_dir_rel
+    name_module   content/my_app
+
+In this case the same values would be returned for the file_print and file_val hooks
+as were returned in the previous setup.
 
 =head1 SYNOPSIS (A LONG "SYNOPSIS")
 
-More examples will come with time.  Here are the basics for now.
 This example script would most likely be in the form of a cgi, accessible via
 the path http://yourhost.com/cgi-bin/my_app (or however you do CGIs on
 your system.  About the best way to get started is to paste the following
@@ -132,7 +797,7 @@ Note: This example would be considerably shorter if the html file
 separate files.  Though CGI::Ex::App will work "out of the box" as
 shown it is more probable that any platform using it will customize
 the various hooks to their own tastes (for example, switching print to
-use a templating system other than CGI::Ex::Template).
+use a templating system other than Template::Alloy).
 
 =head1 SYNOPSIS STEP BY STEP
 
@@ -171,8 +836,9 @@ URI '/cgi-bin/my_app' would run the step 'main' first by default.  The
 URI '/cgi-bin/my_app?step=foo' would run the step 'foo' first.  The
 URI '/cgi-bin/my_app/bar' would run the step 'bar' first.
 
-CGI::Ex::App allows for running steps in a preset path.  The navigate
-method will go through a step of the path at a time and see if it is
+CGI::Ex::App allows for running steps in a preset path or each step may
+choose the next step that should follow.  The navigate
+method will go through one step of the path at a time and see if it is
 completed (various methods determine the definition of "completed").
 This preset type of path can also be automated using the CGI::Path
 module.  Rather than using a preset path, CGI::Ex::App also has
@@ -219,7 +885,7 @@ use external html templates).
 A few things to note about the template:
 
 First, we add a hidden form field called step.  This will be filled in
-at a later point with the current step we are on.
+automatically at a later point with the current step we are on.
 
 We provide locations to swap in inline errors.
 
@@ -278,161 +944,17 @@ print without trying to validate the data.  It is normally a good idea
 to set this as leaving the engine in a "ready to validate" state can result
 in an recursive loop (that will be caught).
 
-        return 1;
-    }
-
-We then return 1 which tells the engine that we completed this step successfully
-and it needs to move on to the next step.
-
-Finally we run the "success" step because we told it to.  That step isn't
-ready to validate so it prints out the template page.
-
-For more of a real world example, it would be good to read the sample recipe db
-application included at the end of this document.
-
-=head1 DEFAULT PROCESS FLOW
-
-The following pseudo-code describes the process flow
-of the CGI::Ex::App framework.  Several portions of the flow
-are encapsulated in hooks which may be completely overridden to give
-different flow.  All of the default actions are shown.  It may look
-like a lot to follow, but if the process is broken down into the
-discrete operations of step iteration, data validation, and template
-printing the flow feels more natural.
-
-=head2 navigate
-
-The process starts off by calling ->navigate.
-
-    navigate {
-        eval {
-            ->pre_navigate
-            ->nav_loop
-            ->post_navigate
-        }
-        # dying errors will run the ->handle_error method
-
-        ->destroy
-    }
-
-=head2 nav_loop
-
-The nav_loop method will run as follows:
-
-    nav_loop {
-        ->path (get the array of path steps)
-            # look in $ENV{'PATH_INFO'}
-            # look in ->form for ->step_key
-            # make sure step is in ->valid_steps (if defined)
-
-        ->pre_loop($path)
-            # navigation stops if true
-
-        foreach step of path {
-
-            ->morph
-                # check ->allow_morph
-                # check ->allow_nested_morph
-                # ->morph_package (hook - get the package to bless into)
-                # ->fixup_after_morph if morph_package exists
-                # if no package is found, process continues in current file
-
-            ->run_step (hook)
-
-            ->refine_path (hook)
-                # only called if run_step returned false (page not printed)
-                ->next_step (hook) # find next step and add to path
-                ->set_ready_validate(0) (hook)
-
-            ->unmorph
-                # only called if morph worked
-                # ->fixup_before_unmorph if blessed to current package
-
-            # exit loop if ->run_step returned true (page printed)
-
-        } end of foreach step
-
-        ->post_loop
-            # navigation stops if true
-
-        ->default_step
-        ->insert_path (puts the default step into the path)
-        ->nav_loop (called again recursively)
-
-    } end of nav_loop
-
-=head2 run_step (hook)
-
-For each step of the path the following methods will be run
-during the run_step hook.
-
-    run_step {
-        ->pre_step (hook)
-            # exits nav_loop if true
-
-        ->skip (hook)
-            # skips this step if true (stays in nav_loop)
-
-        ->prepare (hook - defaults to true)
-
-        ->info_complete (hook - ran if prepare was true)
-            ->ready_validate (hook)
-            return false if ! ready_validate
-            ->validate (hook - uses CGI::Ex::Validate to validate form info)
-                ->hash_validation (hook)
-                   ->file_val (hook)
-                       ->base_dir_abs
-                       ->base_dir_rel
-                       ->name_module
-                       ->name_step
-                       ->ext_val
-            returns true if validate is true or if nothing to validate
-
-        ->finalize (hook - defaults to true - ran if prepare and info_complete were true)
-
-        if ! ->prepare || ! ->info_complete || ! ->finalize {
-            ->prepared_print
-                ->hash_base (hook)
-                ->hash_common (hook)
-                ->hash_form (hook)
-                ->hash_fill (hook)
-                ->hash_swap (hook)
-                ->hash_errors (hook)
-                # merge form, base, common, and fill into merged fill
-                # merge form, base, common, swap, and errors into merged swap
-                ->print (hook - passed current step, merged swap hash, and merged fill)
-                     ->file_print (hook - uses base_dir_rel, name_module, name_step, ext_print)
-                     ->swap_template (hook - processes the file with CGI::Ex::Template)
-                          ->template_args (hook - passed to CGI::Ex::Template->new)
-                     ->fill_template (hook - fills the any forms with CGI::Ex::Fill)
-                          ->fill_args (hook - passed to CGI::Ex::Fill::fill)
-                     ->print_out (hook - print headers and the content to STDOUT)
-
-            ->post_print (hook - used for anything after the print process)
-
-            # return true to exit from nav_loop
-        }
-
-        ->post_step (hook)
-            # exits nav_loop if true
-
-    } end of run_step
+        return 1;
+    }
 
-It is important to learn the function and placement of each of the
-hooks in the process flow in order to make the most of CGI::Ex::App.
-It is enough to begin by learning a few common hooks - such as
-hash_validation, hash_swap, and finalize, and then learn about other
-hooks as needs arise.  Sometimes, it is enough to simply override the
-run_step hook and take care of processing the entire step yourself.
+We then return 1 which tells the engine that we completed this step successfully
+and it needs to move on to the next step.
 
-Because of the hook based system, and because CGI::Ex::App uses
-sensible defaults, it is very easy to override a little or a lot which
-ends up giving the developer a lot of flexibility.
+Finally we run the "success" step because we told it to.  That step isn't
+ready to validate so it prints out the template page.
 
-Consequently, it should be possible to use CGI::Ex::App with the other
-frameworks such as CGI::Application or CGI::Prototype.  For these you
-could simple let each "runmode" call the run_step hook of CGI::Ex::App
-and you will instantly get all of the common process flow for free.
+For more of a real world example, it would be good to read the sample recipe db
+application included at the end of this document.
 
 =head1 AVAILABLE METHODS / HOOKS
 
@@ -460,7 +982,7 @@ The following is the alphabetical list of methods and hooks.
 
 =over 4
 
-=item allow_morph (method)
+=item allow_morph (hook)
 
 Should return true if this step is allowed to "morph" the current App
 object into another package.  Default is false.  It is passed a single
@@ -507,7 +1029,8 @@ steps to the end of the current path.
 
 =item auth_args (method)
 
-Should return a hashref that will be passed to the new method of CGI::Ex::Auth.
+Should return a hashref that will be passed to the auth_obj method
+which should return a CGI::Ex::Auth compatible object.
 It is augmented with arguments that integrate it into CGI::Ex::App.
 
 See the get_valid_auth method and the CGI::Ex::Auth documentation.
@@ -530,15 +1053,142 @@ was successful - so this data can be defined but false.
 
 See the get_valid_auth method.
 
+=item auth_obj (method)
+
+Passed auth_args.  Should return a CGI::Ex::Auth compatible object.  Default
+is to call CGI::Ex::Auth->new with the passed args.
+
+=item base_dir_abs (method)
+
+Used as the absolute base directory to find template, validation and conf files.
+It may return a single value or an arrayref of values, or a coderef that
+returns an arrayref or coderef of values.  You may pass base_dir_abs
+as a parameter in the arguments passed to the "new" method.
+
+Default value is ['.'].
+
+For example, to pass multiple paths, you would use something
+similar to the following:
+
+    sub base_dir_abs {
+        return ['/my/path/one', '/some/other/path'];
+    }
+
+The base_dir_abs value is used by template_path along with the
+base_dir_rel, name_module, name_step, ext_print and ext_values for
+determining the values returned by the default file_print and file_val
+hooks.  See those methods for further discussion.
+
+See the section on FINDING TEMPLATES for further discussion.
+
+The base_dir_abs method is also used as the default value for conf_path and vob_path.
+
+=item base_dir_rel (method)
+
+Added as a relative base directory to content under the base_dir_abs directory.
+
+Default value is "".
+
+The template_path method is used as top level where template includes may
+pull from, while the base_dir_rel is directory relative to the template_path
+where the content files will be stored.
+
+A value for base_dir_rel may passed as a parameter in the arguments passed
+to the new method.
+
+See the template_path and base_dir_abs methods for more discussion.
+
+See the section on FINDING TEMPLATES for further discussion.
+
 =item cleanup_user (method)
 
-Installed as a hook during get_valid_auth.  Allows for cleaning
+Used as a hook during get_valid_auth.  Allows for cleaning
 up the username.  See the get_valid_auth method.
 
-     sub cleanup_user {
-         my ($self, $user) = @_;
-         return lc $user;
-     }
+    sub cleanup_user {
+        my ($self, $user) = @_;
+        return lc $user;
+    }
+
+=item clear_app (method)
+
+If the same CGI::Ex::App based object is used to run multiple
+navigate sessions, the clear_app method should be called which
+will attempt to clear as much session information as it can.
+The following items will be cleared:
+
+    cgix
+    vob
+    form
+    cookies
+    stash
+    path
+    path_i
+    history
+    _morph_lineage_start_index
+    _morph_lineage
+    hash_errors
+    hash_fill
+    hash_swap
+    hash_common
+
+=item conf (method)
+
+Used by default in init_from_conf if load_conf returns true.
+Will try to read the file returned by the conf_file method
+using the object returned by conf_obj using that object's read
+method.  If conf_validation returns a non-empty hashref, the
+conf hash will be validated using $self->vob->validate (see the
+validate method).
+
+This method may be used for other purposes as well (including when
+load_conf is false)..
+
+Caches results in $self->{'conf'}.
+
+If the conf_file can't be found, the method will die unless
+conf_die_on_fail returns 0 (defaults to true).
+
+=item conf_args
+
+Used by conf_obj.
+
+Defaults to $self->{'conf_args'} which defaults to {}.  Will have
+paths => $self->conf_path added before passing to CGI::Ex::Conf->new.
+
+=item conf_file (method)
+
+Used by conf for finding the configuration file to load.  Defaults
+to $self->{'conf_file'} which defaults $self->name_module with the extention
+returned by $self->ext_conf added on.  For example, if name_module
+returns "my_app" and ext_conf returns "ini" the value returned will
+be "my_app.ini".
+
+The value returned can absolute.  If the value will be searched for
+in the paths passed to conf_obj.
+
+The ext_conf may be any of those extentions understood by CGI::Ex::Conf.
+
+=item conf_obj
+
+Used by the conf method to load the file returned by conf_file.  Defaults
+to conf_obj which defaults to loading args from conf_args, adding in paths
+returned by conf_path, and calling CGI::Ex::Conf->new.
+
+Any object that provides a read method that returns a hashref can be used.
+
+=item conf_path
+
+Defaults to $self->{'conf_path'} which defaults to base_dir_abs.  Should be
+a path or an arrayref of paths to look the configuration file returned by
+conf_file when that file is not absolute.
+
+=item conf_validation
+
+Used by default conf method.
+Defaults to an empty hashref.  If non-empty hashref is passed, the
+hashref returned by conf_obj->read will be validated using the hashref
+returned by conf_validation.
 
 =item current_step (method)
 
@@ -596,6 +1246,7 @@ called is "view".
     debug: admin/Recipe.pm line 14
     shift->dump_history = [
             "Elapsed: 0.00562",
+            "view - require_auth - require_auth - 0.00001 - 0",
             "view - run_step - run_step - 0.00488 - 1",
             "    view - pre_step - pre_step - 0.00003 - 0",
             "    view - skip - view_skip - 0.00004 - 0",
@@ -621,6 +1272,11 @@ called is "view".
             "    view - post_print - post_print - 0.00003 - 0"
     ];
 
+=item error_step (method)
+
+Defaults to "__error".  The name of a step to run should a dying error
+be caught by the default handle_error method.  See the handle_error method.
+
 =item exit_nav_loop (method)
 
 This method should not normally used but there is no problem with
@@ -632,39 +1288,33 @@ hooks for the current and remaining steps.  It is used to allow the
 unmorphed before returning.  Also - the post_navigate method will
 still be called.
 
-=item first_step (method)
+=item ext_conf
 
-Returns the first step of the path.  Note that first_step may not be the same
-thing as default_step if the path was overridden.
+Used by the default conf_file method.  Defaults to $self->{'ext_conf'} which
+defaults to 'pl' meaning that the read configuration file should return a
+valid perl hashref.
 
-=item form (method)
+=item ext_print (method)
 
-Returns a hashref of the items passed to the CGI.  Returns
-$self->{form} which defaults to CGI::Ex::get_form.
+Added as suffix to "name_step" during the default file_print hook.
 
-=item handle_error (method)
+Default value is 'html'.
 
-If anything dies during execution, handle_error will be called with
-the error that had happened.  Default action is to die with that error.
+For example, if name_step returns "foo" and ext_print returns "html"
+then the file "foo.html" will be searched for.
 
-=item history (method)
+See the section on FINDING TEMPLATES for further discussion.
 
-Returns an arrayref which contains trace history of which hooks of
-which steps were ran.  Useful for seeing what happened.  In general -
-each line of the history will show the current step, the hook
-requested, and which hook was actually called.
+=item ext_val (method)
 
-The dump_history method shows a short condensed version of this
-history which makes it easier to see what path was followed.
+Added as suffix to "name_step" during the default file_val hook.
 
-In general, the arrayref is free for anything to push onto which will
-help in tracking other occurrences in the program as well.
+Default value is 'val'.
 
-=item init (method)
+For example, if name_step returns "foo" and ext_val returns "val"
+then the file "foo.val" will be searched for.
 
-Called by the default new method.  Allows for any object
-initilizations that may need to take place.  Default action does
-nothing.
+See the section on FINDING TEMPLATES for further discussion.
 
 =item fill_args (hook)
 
@@ -689,15 +1339,15 @@ Returns a filename of the content to be used in the default print
 hook.  Adds method base_dir_rel to hook name_module, and name_step and
 adds on the default file extension found in $self->ext_print which
 defaults to the property $self->{ext_print} which will default to
-".html".  Should return a filename relative to base_dir_abs that can be
-swapped using CGI::Ex::Template, or should be a scalar reference to
+".html".  Should return a filename relative to template_path that can be
+swapped using Template::Alloy, or should be a scalar reference to
 the template content that can be swapped.  This will be used by the
 hook print.
 
-    sub base_dir_abs { '/var/www/templates' }
-    sub base_dir_rel { 'content' }
-    sub name_module  { 'recipe' }
-    sub ext_print    { 'html' } # default
+    sub template_path { '/var/www/templates' }
+    sub base_dir_rel  { 'content' }
+    sub name_module   { 'recipe' }
+    sub ext_print     { 'html' } # default
 
     # ->file_print('this_step')
     # would return 'content/recipe/this_step.html'
@@ -710,16 +1360,19 @@ the data for the application in a single location.
 
 =item file_val (hook)
 
-Returns a filename containing the validation.  Performs the same
-as file_print, but uses ext_val to get the extension, and it adds
-base_dir_abs onto the returned value (file_print is relative to
-base_dir_abs, while file_val is fully qualified with base_dir_abs)
+Returns a filename containing the validation.  Performs the same as
+file_print, but uses ext_val to get the extension, and it adds
+vob_path (which defaults to template_path which defaults to
+base_dir_abs) onto the returned value (file_print is relative to
+template_path, while file_val is fully qualified with vob_path).  If
+vob_path returns an arrayref of paths, then each path is checked for
+the existence of the file.
 
 The file should be readable by CGI::Ex::Validate::get_validation.
 
 This hook is only necessary if the hash_validation hook has not been
 overridden.
-
+5B
 This method an also return a hashref containing the validation - but
 then you may have wanted to override the hash_validation hook.
 
@@ -763,12 +1416,22 @@ override the base package (it is still OK to use the full method name
 
 See the run_hook method and the morph method for more details.
 
+=item first_step (method)
+
+Returns the first step of the path.  Note that first_step may not be the same
+thing as default_step if the path was overridden.
+
 =item forbidden_step (method)
 
 Defaults to "__forbidden".  The name of a step to run should the current
 step name be invalid, or if a step found by the default path method
 is invalid.  See the path method.
 
+=item form (method)
+
+Returns a hashref of the items passed to the CGI.  Returns
+$self->{form} which defaults to CGI::Ex::get_form.
+
 =item form_name (hook)
 
 Return the name of the form to attach the js validation to.  Used by
@@ -783,8 +1446,7 @@ to the authentication object during the get_valid_auth method.
 
 =item get_valid_auth (method)
 
-If require_auth is true at either the application level or at the
-step level, get_valid_auth will be called.
+If require_auth hook returns true on any given step then get_valid_auth will be called.
 
 It will call auth_args to get some default args to pass to
 CGI::Ex::Auth->new.  It augments the args with sensible defaults that
@@ -829,6 +1491,12 @@ Full customization of the login process and the login template can
 be done via the auth_args hash.  See the auth_args method and
 CGI::Ex::Auth perldoc for more information.
 
+=item handle_error (method)
+
+If anything dies during execution, handle_error will be called with
+the error that had happened.  Default action is to try running the
+step returned by the error_step method.
+
 =item hash_base (hook)
 
 A hash of base items to be merged with hash_form - such as pulldown
@@ -921,6 +1589,19 @@ pass it to CGI::Ex::Validate::get_validation.  If no file_val is
 returned or if the get_validation fails, an empty hash will be returned.
 Validation is implemented by ->vob which loads a CGI::Ex::Validate object.
 
+=item history (method)
+
+Returns an arrayref which contains trace history of which hooks of
+which steps were ran.  Useful for seeing what happened.  In general -
+each line of the history will show the current step, the hook
+requested, and which hook was actually called.
+
+The dump_history method shows a short condensed version of this
+history which makes it easier to see what path was followed.
+
+In general, the arrayref is free for anything to push onto which will
+help in tracking other occurrences in the program as well.
+
 =item info_complete (hook)
 
 Calls the ready_validate hook to see if data is ready to validate.  If
@@ -928,6 +1609,22 @@ so it calls the validate hook to validate the data.  Should make
 sure the data is ready and valid.  Will not be run unless
 prepare returns true (default).
 
+=item init (method)
+
+Called by the default new method.  Allows for any object
+initilizations that may need to take place.  Default action does
+nothing.
+
+=item init_from_conf (method)
+
+Called by the default new method.  If load_conf is true, then the
+conf method will be called and the keys returned will be added to
+the $self object.
+
+This method is called after the init method.  If you need to further
+fix up values added during init_from_conf, you can use the pre_navigate
+method.
+
 =item insert_path (method)
 
 Arguments are the steps to insert.  Can be called any time.  Inserts
@@ -1023,6 +1720,14 @@ jumping (the path is modified so that the path history is not destroyed
 
 Returns the last step of the path.  Can be used to jump to the last step.
 
+=item load_conf (method)
+
+Defaults to ->{load_conf} which defaults to false.  If true, will
+allow keys returned by the conf method to be added to $self during
+the init_from_conf method.
+
+Enabling this method allows for out-of-the-box file based configuration.
+
 =item morph (method)
 
 Allows for temporarily "becoming" another object type for the
@@ -1137,12 +1842,16 @@ have its own directory for storing html for its steps.
 
 See the file_print method for more information.
 
+See the section on FINDING TEMPLATES for further discussion.
+
 =item name_step (hook)
 
 Return the step (appended to name_module) that should used when
 looking up the file in file_print and file_val lookups.  Defaults to
 the current step.
 
+See the section on FINDING TEMPLATES for further discussion.
+
 =item nav_loop (method)
 
 This is the main loop runner.  It figures out the current path
@@ -1169,8 +1878,9 @@ This starts the process flow for the path and its steps.
 
 =item navigate_authenticated (method)
 
-Same as the method navigate but sets require_auth(1) before
-running.  See the require_auth method.
+Same as the method navigate but calls ->require_auth(1) before
+running.  It will only work if the navigate_authenticated method
+has not been overwritten. See the require_auth method.
 
 =item new (class method)
 
@@ -1220,6 +1930,70 @@ If navigation runs out of steps to run, the default step found in
 default_step will be run.  This is what allows for us to default
 to the "main" step for many applications.
 
+=item path_info_map (hook)
+
+Used to map path_info parts to form variables.  Similar to the
+path_info_map_base method.  See the path_info_map_base method
+for a discussion of how to use this hook.
+
+=item path_info_map_base (method)
+
+Called during the default path method.  It is used to custom map portions
+of $ENV{'PATH_INFO'} to form values.  If should return an arrayref of
+arrayrefs where each child arrayref contains a regex qr with match parens
+as the first element of the array.  Subsequent elements of the array are
+the key names to store the corresponding matched value from the regex under.
+The outer arrayref is iterated until it one of child arrayrefs matches
+against $ENV{'PATH_INFO'}.  The matched values are only added to the form if
+there is not already a defined value for that key in the form.
+
+The default value returned by this method looks something like the following:
+
+   sub path_info_map_base {
+       return [[qr{^/(\w+)}, $self->step_key]];
+   }
+
+This example would map the following PATH_INFO string as follows:
+
+   /my_step
+
+   # $self->form->{'step'} now equals "my_step"
+
+The following is another example:
+
+   sub path_info_map_base {
+       return [
+           [qr{^/([^/]+)/(\w+)}, 'username', $self->step_key],
+           [qr{^/(\w+)}, $self->step_key],
+       ];
+   }
+
+   # the PATH_INFO /my_step
+   # still results in
+   # $self->form->{'step'} now equals "my_step"
+
+   # but with the PATH_INFO /my_user/my_step
+   # $self->form->{'step'} now equals "my_step"
+   # and $self->form->{'username'} equals "my_user"
+
+In most cases there is not a need to override the path_info_map_base
+method, but rather override the path_info_map hook for a particular step.
+When the step is being run, just before the run_step hook is called, the
+path_info_map hook is called.  The path_info_map hook is similar to
+the path_info_map_base method, but is used to allow step level manipulation
+of form based on elements in the $ENV{'PATH_INFO'}.
+
+   sub my_step_path_info_map {
+       return [[qr{^/my_step/(\w+)$}, 'username']];
+   }
+
+   # the PATH_INFO /my_step/my_user
+   # results in
+   # $self->form->{'step'} equal to "my_step" because of default path_info_map_base
+   # and $self->form->{'username'} equals "my_user" because of my_step_path_info_map
+
+The section on mapping URIs to steps has additional examples.
+
 =item post_loop (method)
 
 Ran after all of the steps in the loop have been processed (if
@@ -1296,15 +2070,27 @@ List the step previous to this one.  Will return '' if there is no previous step
 
 =item print (hook)
 
-Take the information generated by prepared_print, format it, and print it out.
-Default incarnation uses CGI::Ex::Template which is compatible with
-Template::Toolkit.  Arguments are: step name (used to call the
-file_print hook), swap hashref (passed to call swap_template), and
-fill hashref (passed to fill_template).
+Take the information generated by prepared_print, format it using
+swap_template, fill it using fill_template and print it out using
+print_out.  Default incarnation uses CGI::Ex::Template (a subclass of
+Template::Alloy) which is compatible with Template::Toolkit to do the
+swapping.  Arguments are: step name (used to call the file_print
+hook), swap hashref (passed to call swap_template), and fill hashref
+(passed to fill_template).
 
 During the print call, the file_print hook is called which should
 return a filename or a scalar reference to the template content is
 
+=item print_out (hook)
+
+Called with the finished document.  Should print out the appropriate headers.
+The default method calls $self->cgix->print_content_type and then
+prints the content.
+
+The print_content_type is passed $self->mimetype (which defaults to
+$self->{'mimetype'} which defaults to 'text/html') and $self->charset
+(which defaults to $self->{'charset'} which defaults to '').
+
 =item ready_validate (hook)
 
 Should return true if enough information is present to run validate.
@@ -1317,6 +2103,13 @@ and check for its presence - such as the following:
 Changing the behavior of ready_validate can help in making wizard type
 applications.
 
+You can also use the validate_when_data hook to change the behavior of
+ready_validate.  If valiate_when_data returns true, then
+ready_validate will look for keys in the form matching keys that are
+in hash_validation - if they exist ready_validate will be true.  If
+there are no hash_validation keys, ready_validate uses its default
+behavior.
+
 =item refine_path (hook)
 
 Called at the end of nav_loop.  Passed a single value indicating
@@ -1354,45 +2147,104 @@ had been successfully validated and acted upon.
 Arguments are the steps used to replace.  Can be called any time.
 Replaces the remaining steps (if any) of the current path.
 
-=item require_auth (method)
+=item require_auth (hook)
 
-Default undef.  Can return either a true value or a hashref of step names.
+Defaults to self->{require_auth} which defaults to undef.
+If called as a method and passed a single value of 1, 0, or undef it will
+set the value of $self->{require_auth} to that value.  If set to a true
+value then any subsequent step will require authentication (unless its
+hook has been overwritten).
 
-If a hashref of stepnames is returned, authentication will be turned on
-at the step level.  In this mode if any step is accessed, the get_valid_auth
-method will be called.  If it fails, then the nav_loop will be stopped
-(the post_navigate method will be called - use the is_authed method to perform
-different functions).  Any step of the path not in the hash will not require
-authentication.  For example, to add authentication to add authentication
-to the add, edit and delete steps you could do:
+Any of the following ways can be used to require authentication on
+every step.
 
-    sub require_auth { {add => 1, edit => 1, delete => 1} }
+=over 4
 
-If a non-hash true value is returned from the require_auth method then
-authentication will take place before the pre_navigation or the nav_loop methods.
-If authentication fails the navigation process is exited (the post_navigate
-method will not be called).
+=item
 
     sub require_auth { 1 }
 
-Alternatively you can also could do either of the following:
+=item
 
     __PACKAGE__->navigate_authenticated; # instead of __PACKAGE__->navigate;
 
-    # OR
+=item
+
+    __PACKAGE__->new({require_auth => 1}->navigate;
+
+=item
 
     sub init { shift->require_auth(1) }
 
-    # OR
+=back
 
-    __PACKAGE__->new({require_auth => 1}->navigate;
+Because it is called as a hook, the current step is passed as the
+first argument.  If the hook returns false, no authentication will be
+required on this step.  If the hook returns a true, non-hashref value,
+authentication will be required via the get_valid_auth method.  If the
+method returns a hashref of stepnames to require authentication on,
+the step will require authentication via the get_valid_auth method if
+the current step is in the hashref.  If authentication is required and
+succeeds, the step will proceed.  If authentication is required and
+fails at the step level the current step will be aborted,
+authentication will be asked for (the post_navigate method will still
+be called).
+
+For example you could add authentication to the add, edit, and delete
+steps in any of the following ways:
 
-If get_valid_auth returns true, in either case, the is_authed method will
-return true and the auth_data will contain the authenticated user's data.
-If it returns false, auth_data may possibly contain a defined but false
-data object with details as to why authentication failed.
+=over 4
 
-See the get_valid_auth method.
+=item
+
+    sub require_auth { {add => 1, edit => 1, delete => 1} }
+
+=item
+
+    sub add_require_auth    { 1 }
+    sub edit_require_auth   { 1 }
+    sub delete_require_auth { 1 }
+
+=item
+
+    sub require_auth {
+        my ($self, $step) = @_;
+        return 1 if $step && $step =~ /^(add|edit|delete)$/;
+        return 0;
+    }
+
+=back
+
+If however you wanted to require authentication on all but one or two methods
+(such as requiring authentication on all but a forgot_password step) you could do
+either of the following:
+
+=over 4
+
+=item
+
+    sub require_auth {
+        my ($self, $step) = @_;
+        return 0 if $step && $step eq 'forgot_password';
+        return 1; # require auth on all other steps
+    }
+
+=item
+
+    sub require_auth { 1 } # turn it on for all steps
+
+    sub forgot_password_require_auth { 0 } # turn it off
+
+=back
+
+See the get_valid_auth method for what occurs should authentication be required.
+
+There is one key difference from the 2.14 version of App.  In 2.14 and
+previous versions, the pre_navigate and post_navigate methods would
+not be called if require_auth returned a true non-hashref value.  In
+version 2.15 and later, the 2.15 pre_navigate and post_navigate
+methods are always called - even if authentication fails.  Also in 2.15
+and later, the method is called as a hook meaning the step is passed in.
 
 =item run_hook (method)
 
@@ -1434,8 +2286,11 @@ This method is not normally used.
 =item set_ready_validate (hook and method)
 
 Sets that the validation is ready (or not) to validate.  Should set the value
-checked by the hook ready_validate.  The following would complement the
-processing flag above:
+checked by the hook ready_validate.  Has no affect if validate_when_data
+flag is set.
+
+The following would complement the "processing" flag example given in
+ready_validate description:
 
     sub set_ready_validate {
         my $self = shift;
@@ -1481,25 +2336,95 @@ method to look for in the form.  Default value is 'step'.
 
 =item swap_template (hook)
 
-Takes the template and hash of variables prepared in print, and processes them
-through the current template engine (default engine is CGI::Ex::Template).
+Takes the template and hash of variables prepared in print, and
+processes them through the current template engine (default engine is
+CGI::Ex::Template a subclass of Template::Alloy).
+
+Arguments are the template and the swap hashref.  The template can be
+either a scalar reference to the actual content, or the filename of
+the content.  If the filename is specified - it should be relative to
+template_path (which will be used to initialize INCLUDE_PATH by
+default).
+
+The default method will create a template object by calling the
+template_args hook and passing the returned hashref to the
+template_obj method.  The default template_obj method returns a
+CGI::Ex::Template object, but could easily be swapped to use a
+Template::Toolkit based object.  If a non-Template::Toolkit compatible
+object is to be used, then the swap_template hook can be overridden to
+use another templating engine.
+
+For example to use the HTML::Template engine you could override the swap_template
+method as follows:
+
+    use HTML::Template;
+
+    sub swap_template {
+        my ($self, $step, $file, $swap) = @_;
+
+        my $type = UNIVERSAL::isa($file, 'SCALAR') ? 'scalarref'
+                 : UNIVERSAL::isa($file, 'ARRAY')  ? 'arrayref'
+                 : ref($file)                      ? 'filehandle'
+                 :                                   'filename';
 
-Arguments are the template and the swap hashref.  The template can be either a
-scalar reference to the actual content, or the filename of the content.  If the
-filename is specified - it should be relative to base_dir_abs.
+        my $t = HTML::Template->new(source => $file,
+                                    type   => $type,
+                                    path   => $self->template_path,
+                                    die_on_bad_params => 0,
+                                    );
+
+        $t->param($swap);
+
+        return $t->output;
+    }
+
+As of version 2.13 of CGI::Ex::Template you could also simply do the
+following to parse the templates using HTML::Template::Expr syntax.
+
+    sub template_args {
+        return {SYNTAX => 'hte'};
+    }
+
+For a listing of the available syntaxes, see the current L<Template::Alloy> documentation.
 
 =item template_args (hook)
 
 Returns a hashref of args that will be passed to the "new" method of CGI::Ex::Template.
-By default this hashref contains INCLUDE_PATH which is set equal to base_dir_abs.
-It can be augmented with any arguments that CGI::Ex::Template would understand.
-
-   sub template_args {
-       return {
-           INCLUDE_PATH => '/my/own/include/path',
-           WRAPPER => 'wrappers/main_wrapper.html',
-       };
-   }
+The method is normally called from the swap_template hook.  The swap_template hook
+will add a value for INCLUDE_PATH which is set equal to template_path, if the INCLUDE_PATH
+value is not already set.
+
+The returned hashref can contain any arguments that CGI::Ex::Template (a subclass of Template::Alloy)
+would understand.
+
+    sub template_args {
+        return {
+            PRE_CHOMP => 1,
+            WRAPPER   => 'wrappers/main_wrapper.html',
+        };
+    }
+
+See the L<Template::Alloy> documentation for a listing of all possible configuration arguments.
+
+=item template_obj (method)
+
+Called from swap_template.  It is passed the result of template_args
+that have had a default INCLUDE_PATH added via template_path.  The default
+implementation uses CGI::Ex::Template (a subclass of Template::Alloy)
+but can easily be changed to use Template::Toolkit by using code
+similar to the following:
+
+    use Template;
+
+    sub template_obj {
+        my ($self, $args) = @_;
+        return Template->new($args);
+    }
+
+=item template_path (method)
+
+Defaults to $self->{'template_path'} which defaults to base_dir_abs.  Used by
+the template_obj method.
 
 =item unmorph (method)
 
@@ -1552,6 +2477,14 @@ path.  A validation item of:
 
 would append 'bar' and 'baz' to the path should all validation succeed.
 
+=item validate_when_data (hook)
+
+Defaults to "validate_when_data" property which defaults to false.  Called
+during the ready_validate hook.  If returns true, ready_validate will look
+for keys in the form matching keys that are in hash_validation - if they exist
+ready_validate will be true.  If there are no hash_validation keys, ready_validate
+uses its default behavior.
+
 =item verify_user (method)
 
 Installed as a hook to CGI::Ex::App during get_valid_auth.  Should return
@@ -1566,19 +2499,83 @@ used to abort early before the get_pass_by_user hook is called.
 
 =back
 
-=head1 OTHER APPLICATION MODULES
+=head1 HOW DO I SET COOKIES, REDIRECT, ETC
+
+Often in your program you will want to set cookies or bounce to a differnt URL.
+This can be done using either the builtin CGI::Ex object or the built in
+CGI object.  It is suggested that you only use the CGI::Ex methods as it will
+automatically send headers and method calls under cgi, mod_perl1, or mod_perl2.
+The following shows how to do basic items using the CGI::Ex object returned by
+the ->cgix method.
+
+=over 4
+
+=item printing content-type headers
+
+    ### CGI::Ex::App prints headers for you,
+    ### but if you are printing custom types, you can send your own
+    $self->cgix->print_content_type;
+    # SAME AS
+    # $self->cgix->print_content_type('text/html');
+
+=item setting a cookie
+
+    $self->cgix->set_cookie({
+        -name    => "my_key",
+        -value   => 'Some Value',
+        -expires => '1y',
+        -path    => '/',
+    });
+
+=item redirecting to another URL
+
+    $self->cgix->location_bounce("http://somewhereelse.com");
+    $self->exit_nav_loop; # normally should do this to long jump out of navigation
+
+=item making a QUERY_STRING
+
+    my $data  = {foo => "bar", one => "two or three"};
+    my $query = $self->cgix->make_form($data);
+    # $query now equals "foo=bar&one=two%20or%20three"
+
+=item getting form parameters
+
+    my $form = $self->form;
+
+In this example $form would now contain a hashref of all POST and GET parameters
+passed to the server.  The form method calls $self->cgix->get_form
+which in turn uses CGI->param to parse values.  Fields with multiple passed
+values will be in the form of an arrayref.
+
+=item getting cookies
+
+    my $cookies = $self->cookies;
+
+In this example $cookies would be a hashref of all passed in cookies.  The
+cookies method calls $self->cgix->get_cookies which in turn uses CGI->cookie
+to parse values.
+
+=back
+
+See the CGI::Ex and CGI documentation for more information.
+
+=head1 COMPARISON TO OTHER APPLICATION MODULES
 
 The concepts used in CGI::Ex::App are not novel or unique.  However, they
 are all commonly used and very useful.  All application builders were
 built because somebody observed that there are common design patterns
 in CGI building.  CGI::Ex::App differs in that it has found more common design
-patterns of CGI's than some and tries to get in the way less than others.
+patterns of CGI's than other application builders and tries to get in the way
+less than others.
 
 CGI::Ex::App is intended to be sub classed, and sub sub classed, and each step
 can choose to be sub classed or not.  CGI::Ex::App tries to remain simple
 while still providing "more than one way to do it."  It also tries to avoid
 making any sub classes have to call ->SUPER:: (although that is fine too).
 
+And if what you are doing on a particular is far too complicated or custom for
+what CGI::Ex::App provides, CGI::Ex::App makes it trivial to override all behavior.
+
 There are certainly other modules for building CGI applications.  The
 following is a short list of other modules and how CGI::Ex::App is
 different.
@@ -1590,7 +2587,8 @@ different.
 Seemingly the most well know of application builders.
 CGI::Ex::App is different in that it:
 
-  * Uses Template::Toolkit compatible CGI::Ex::Template by default
+  * Uses Template::Toolkit compatible CGI::Ex::Template (a
+      subclass of Template::Alloy) by default.
       CGI::Ex::App can easily use another toolkit by simply
       overriding the ->swap_template method.
       CGI::Application uses HTML::Template.
@@ -1605,6 +2603,9 @@ CGI::Ex::App is different in that it:
       which is only a dispatch.
   * Support for easily jumping around in navigation steps.
   * Support for storing some steps in another package.
+  * Integrated authentication
+  * Integrated form filling
+  * Integrated PATH_INFO mapping
 
 CGI::Ex::App and CGI::Application are similar in that they take care
 of handling headers and they allow for calling other "runmodes" from
@@ -1624,13 +2625,13 @@ CGI::Prototype is that it is extremely short (very very short).  The
 system (CGI::Ex::App uses CGI::Ex::Template which is TT compatible).
 CGI::Ex::App is differrent in that it:
 
-  * Offers integrated data validation.
-      CGI::Application has had custom addons created that
-      add some of this functionality.  CGI::Ex::App has the benefit
-      that once validation is created,
   * Offers more hooks into the various phases of each step.
   * Support for easily jumping around in navigation steps.
   * Support for storing only some steps in another package.
+  * Integrated data validation
+  * Integrated authentication
+  * Integrated form filling
+  * Integrated PATH_INFO mapping
 
 =back
 
@@ -1639,7 +2640,7 @@ CGI::Ex::App is differrent in that it:
 
 The following example shows the creation of a basic recipe
 database.  It requires the use of DBD::SQLite, but that is all.
-Once you have configured the db_file and base_dir_abs methods
+Once you have configured the db_file and template_path methods
 of the "recipe" file, you will have a working script that
 does CRUD for the recipe table.  The observant reader may ask - why
 not use Catalyst or Ruby on Rails?  The observant programmer will
@@ -1679,7 +2680,7 @@ the core logic of the application.
         debug shift->dump_history;
     }
 
-    sub base_dir_abs { '/var/www/templates' }
+    sub template_path { '/var/www/templates' }
 
     sub base_dir_rel { 'content' }
 
@@ -1800,7 +2801,7 @@ the core logic of the application.
             return 0;
         }
 
-        my $s = "UPDATE recipe SET title = ?, ingredients = ?, directions = ? WHERE id = ?";
+        $s = "UPDATE recipe SET title = ?, ingredients = ?, directions = ? WHERE id = ?";
         $self->dbh->do($s, {}, $form->{'title'},
                                $form->{'ingredients'},
                                $form->{'directions'},
@@ -2182,22 +3183,43 @@ will cause all steps to require validation):
 
     sub require_auth { {add => 1, edit => 1, delete => 1} }
 
+We could also enable authentication by using individual hooks as in:
+
+    sub add_require_auth    { 1 }
+    sub edit_require_auth   { 1 }
+    sub delete_require_auth { 1 }
+
+Or we could require authentication on everything - but let a few steps in:
+
+    sub require_auth { 1 }      # turn authentication on for all
+    sub main_require_auth { 0 } # turn it off for main and view
+    sub view_require_auth { 0 }
+
 That's it.  The add, edit, and delete steps will now require authentication.
 See the require_auth, get_valid_auth, and auth_args methods for more information.
 Also see the L<CGI::Ex::Auth> perldoc.
 
 =head1 THANKS
 
-    Bizhosting.com - giving a problem that fit basic design patterns.
+The following corporation and individuals contributed in some part to
+the original versions.
+
+    Bizhosting.com  - giving a problem that fit basic design patterns.
+
+    Earl Cahill     - pushing the idea of more generic frameworks.
+
+    Adam Erickson   - design feedback, bugfixing, feature suggestions.
+
+    James Lance     - design feedback, bugfixing, feature suggestions.
 
-    Earl Cahill    - pushing the idea of more generic frameworks.
+    Krassimir Berov - feedback and some warnings issues with POD examples.
 
-    Adam Erickson  - design feedback, bugfixing, feature suggestions.
+=head1 LICENSE
 
-    James Lance    - design feedback, bugfixing, feature suggestions.
+This module may be distributed under the same terms as Perl itself.
 
 =head1 AUTHOR
 
-Paul Seamons <paul at seamons dot com>
+Paul Seamons <perl at seamons dot com>
 
 =cut
This page took 0.055847 seconds and 4 git commands to generate.