=pod 

=head1 NAME

Apache::Voodoo API 

=head1 Synopsis

Each page module must inherit from Apache::Voodoo.  This module provides the new() method to 
make the package a proper object under Voodoo, along with some other minor black magic.  
Inheriting from this module provides access to some essential methods for interacting 
with Voodoo.

	package my_app::index;

	use strict;
	use base ("Apache::Voodoo");

	sub handle {
		my $self = shift;
		my $p    = shift;

		# hash reference of data suitable for passing to the 
		# params() method in HTML::Tempate
		return $hash_ref;
	}

	1;


$p is a hash reference that contains plethora of things:

=over 4 

=item dbh          

DBI object already connected to the database as described in the Voodoo configuration file.

=item dir_config

Directory configuration directives from Apache (see the mod_perl docs for $r->dir_config)

=item document_root 

/path/to/the/document/root/for/this/site

=item params 

key / value pairs of all the url POST or GET parameters.  If a given key is present more than
once in the POST/GET parameters then the value is an array reference of them.

=item session

Apache::Session object where you may store any client persistant data.

Voodoo keeps a few of it's own internal variables here as well, so a little bit of care must be taken
to not clobber them.  'timestamp' and 'history' are reserved, look but don't touch.

=item template_conf 

Contents of the matching template_conf section in the Voodoo configuration file.

=item uri

/the/current/url/minus/the/server.com/part/and/parameters

=item user-agent 

User-agent string as presented by the browser

=back

The call and return syntax is the same for any page modules and pre/post includes.

=head1 METHODS INHERITED FROM Apache::Voodoo

=over 4

=item init()

Since the new() method is reserved for some Voodoo specific black magic, you may 
add the init method in your modules to do basically the same sorts of things that you
would normally do inside a new().  For example:

 usage:
    sub init {
        my $self = shift;
        $self->{'some_private_var'} = 'SOME VALUE';
    }

=back

=head2 Debugging

=over 4

=item db_error()

Used to report catastrophic database errors to the error_log file and to the web browser.
If DEBUG is turned on, then the details or the error will be displayed, otherwise a 500
error is returned to Apache.  This method uses die() internally and thus DOES NOT RETURN.

 usage:
	$dbh->selectall_arrayref($query) || $self->db_error();


=item debug($one_message, [ $two_message, ... ] )

Prints user debugging messages to the error_log file and to the 'Debug' section of the DEBUG 
template block. (See L<Apache::Voodoo::Debug> for more details).  Messages can be turn on or off 
globally using the DEBUG option of the Voodoo configuration file.

If any of the parameters to debug a references, they printed using Data::Dumper.

 usage:
     return $self->debug('The value of foo is:',$foo);

=item mark($message)

Optionally appends a Time::HiRes time stamp to the 'Generation Time' section of the DEBUG
block.  Messages can be turn on or off globally using the DEBUG option of the configuration.

 usage:
     $self->mark('descriptive message about this point in the code');

 example:

     $self->mark('Start of big nasty loop');
     foreach (@lots_of_stuff) {
         # do stuff
     }
     $self->mark('End of big nasty loop');

=back
       
=head2 Browser Redirection

=over 4

=item access_denied( [ $uri ] )

This method is used to indicate to the Handler that the user is not allowed
to access the URI requested.  If the optional parameter is not supplied the standard 
Apache 403 (Forbidden) is returned to the user.

 usage:
    return $self->access_denied;
        or
    return $self->access_denied($url_for_access_denied_message);

=item display_error($error,$uri)

Redirects the user to a generic error message display page.

 usage:
	return $self->display_error('stuff went bang!','/index');


=item history($voodo_session,$index)

Voodoo keeps a running list of the last 10 urls visited in the current session.
This method provides access to that list.  $index == 0 is the current page,
$index == 1 is the page before this one.  Successive requests to the same page with 
different parameters DOES NOT add a new entry to this history, rather it only updates
the URI parameters for that entry in the history.  For example, if you click the  
'next' link in paginated result set 10 times, the history doesn't contain 10 entries
for each of those pages.

 usage:
    $url = $self->history($p->{'session'},3);

=item tardis($p, $uri1, [$uri2, ...] )

Often within a website there is the need to go back to a previous page that the user
has already visited.  For example the page that let's you view a record contains an 
'edit' link for that record.  After the edit has finished, odds are you'd want to send
the user back to that view page.  This can quickly lead to a lot of tedious parameter
management for those return-to pages. Plus there may be more than one entry point for the
current module only adding to the complexity.  Tardis provides a convenient way search the
history for a set of URI's and redirect the user back to the first one it finds.

The uri's must contain the full path, relative uri's don't work.  You do not need
to specify the parameters for that page, in fact doing so would kinda defeat the point :)

If no history items match, it redirects to the previously accessed uri.

 usage:
    return $self->tardis($p,'/first/url/no_params','/second/url/no_params');

 example:
    /admin/view_user and /admin/list_user contain a link to the edit command.  Each
    takes different parameters and the user could have been on either before clicking
    the edit link.

    Your edit method could look like this:

    sub edit {
        my $self = shift;
        my $p = shift;
  
        # do some stuff

        return $self->tardis($p,'/admin/view_user','/admin/list_user');
    }

    You no longer have to figure out which link they came from, and what parameters they
    were using at the time.

=item redirect($uri)

Redirects the user to the given URI. These may be absolute or relative

 usage:
	return $self->redirect('/some/uri');

=back

=head2 Data Manipulation

=over 4

=item prep_select($array_of_arrays, [ $selected_value ] )

Ever notice how when you're making select lists or lists of radio buttons that you end up 
doing 95% of them exactly the same way?  This method does the HTML::Template-ifying of the
data for you for those 95% cases.

 usage:
    $return->{'my_list' = $self->prep_select(
        [
	    [ $id_value,  $select_label  ], 
            [ $id_value2, $select_label2 ], ...
        ],
        $id_value_to_mark_selected
    );

    or

    $return->{'my_list' = $self->prep_select(
        [
	    [ $id_value,  $select_label  ], 
            [ $id_value2, $select_label2 ], ...
        ],
        [ $selected_id1, $select_id2, ... ]
    );


 corresponding HTML::template for select lists (lines broken up for clarity):
     <select name="my_list">
     <tmpl_loop my_list>
         <option 
             value="<tmpl_var ID>" 
             <tmpl_if SELECTED>selected</tmpl_if>
         >
             <tmpl_var NAME>
         </option>
     </tmpl_loop>
     </select>

 corresponding HTML::template for radio buttons:
     <tmpl_loop my_list>
         <input 
             type="radio"
             name="my_list"
             value="<tmpl_var ID>"
             <tmpl_if SELECTED>checked</tmpl_if>
         >
         <tmpl_var NAME>
     </tmpl_loop>

=item trim($string)

Removes leading and trailing whitespace

 usage:
    $value = $self->trim("  <-- these spaces will be removed -->  ");

=item raw_mode($content_type,$contents, [ \%optional_http_headers ] )

This method is used to bypass the normal templating subsystem and allows the 'contents'
to be streamed directly to the browser.  Useful for generating CSVs and binary data 
from within Voodoo.

 usage:
    return $self->raw_mode(
        'text/csv',
        $contents,
        {
            'Content-disposition' => "attachment;filename=SomeFile.csv"
        }
    );

=item last_insert_id()

Returns the value of the last auto_increment id in MySQL

Eventually I'm going to subclass DBI for Voodoo and include this there :)

=back

=head1 AUTHOR

Maverick, /\/\averick@smurfbaneDOTorg

=head1 COPYRIGHT

Copyright (c) 2005 Steven Edwards.  All rights reserved.

You may use and distribute Voodoo under the terms described in the LICENSE file include
in this package or L<Apache::Voodoo::license>.  The summary is it's a legalese version
of the Artistic License :)
