NAME
HTML::Application - Framework for complex portable web apps.
DEPENDENCIES
Perl Version
5.004
Standard Modules
I<none>
Nonstandard Modules
File::VirtualPath 1.0
HTML::EasyTags 1.04
Data::MultiValuedHash 1.07
CGI::MultiValuedHash 1.07
SYNOPSIS
Content of thin shell "startup.pl" for UNIX file system, CGI environment:
#!/usr/bin/perl
use strict;
use lib '/home/johndoe/myperl5/lib';
# make new framework; set where our files are today
require HTML::Application;
my $globals = HTML::Application->new( "/home/johndoe/projects/aardvark" );
# fetch the web user's input
$globals->user_path( $ENV{'PATH_INFO'} );
$globals->user_query( $ENV{'QUERY_STRING'} );
if( $ENV{'REQUEST_METHOD'} eq 'POST' ) {
my $post_data;
read( STDIN, $post_data, $ENV{'CONTENT_LENGTH'} );
chomp( $post_data );
$globals->user_post( $post_data );
}
$globals->user_cookies( $ENV{'HTTP_COOKIE'} || $ENV{'COOKIE'} );
# remember the url for this script in call-back urls
$globals->url_base( "http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}" );
# check if owner's here and wants to debug; replicate fact in call-back urls
if( $globals->user_query_param( 'debugging' ) eq 'on' ) {
$globals->is_debug( 1 );
$globals->url_query_param( 'debugging', 'on' );
}
# set up component context including file prefs and user path level
$globals->set_prefs( "config.pl" );
$globals->inc_user_path_level();
# run our main program to do all the real work, now that its sandbox is ready
$globals->call_component( 'Aardvark', 1 );
# make an error message if the main program failed for some reason
if( $globals->get_error() ) {
$globals->page_title( 'Fatal Program Error' );
$globals->set_page_body( <<__endquote );
<H1>@{[$globals->page_title()]}</H1>
<P>I'm sorry, but an error has occurred while trying to run Aardvark.
The problem could be temporary. Click @{[$globals->recall_html('here')]}
to automatically try again, or come back later.
<P>Details: @{[$globals->get_error()]}</P>
__endquote
}
# let web user know that we know that they are debugging
if( $globals->is_debug() ) {
$globals->append_page_body( <<__endquote );
<P>Debugging is currently turned on.</P>
__endquote
}
# send the user output
print STDOUT "Status: @{[$globals->http_status_code()]}\n";
print STDOUT "Content-type: @{[$globals->http_content_type()]}\n";
if( my $url = $globals->http_redirect_url() ) {
print STDOUT "Uri: $url\nLocation: $url\n";
}
print STDOUT "\n".$globals->page_as_string();
1;
Content of settings file "config.pl"
my $rh_prefs = {
title => 'Welcome to Aardvark',
credits => '<P>This program copyright 2001 Darren Duncan.</P>',
screens => {
one => {
'link' => 'Door Number One',
mod_name => 'Panda',
mod_prefs => {
food => 'plants',
color => 'black and white',
size => 'medium',
files => [qw( priv prot publ )],
file_reader => '/three',
},
},
two => {
'link' => 'Door Number Two',
mod_name => 'Owl',
mod_prefs => {
fly_to => 'http://www.owl.org',
},
},
three => {
'link' => 'Door Number Three',
mod_name => 'Camel',
mod_subdir => 'files',
mod_prefs => {
priv => 'private.txt',
prot => 'protected.txt',
publ => 'public.txt',
},
},
},
};
Content of fat main program component "Aardvark.pm"
package Aardvark;
use strict;
use HTML::Application;
sub main {
my ($class, $globals) = @_;
$globals->page_title( $globals->pref( 'title' ) );
my $users_choice = $globals->current_user_path_element();
my $rh_screens = $globals->pref( 'screens' );
if( my $rh_screen = $rh_screens->{$users_choice} ) {
my $inner = $globals->make_new_context();
$inner->inc_user_path_level();
$inner->navigate_url_path( $users_choice );
$inner->navigate_file_path( $rh_screen->{mod_subdir} );
$inner->set_prefs( $rh_screen->{mod_prefs} );
$inner->call_component( $rh_screen->{mod_name}, 1 );
if( $inner->get_error() ) {
$globals->append_page_body(
"Can't show requested screen: ".$inner->get_error() );
} else {
$globals->take_context_output( $inner, 1 );
}
} else {
$globals->set_page_body( "<P>Please choose a screen to view.</P>" );
foreach my $key (keys %{$rh_screens}) {
my $label = $rh_screens->{$key}->{link};
my $url = $globals->url_as_string( $key );
$globals->append_page_body( "<BR><A HREF=\"$url\">$label</A>" );
}
}
$globals->append_page_body( $globals->pref( 'credits' ) );
}
1;
Content of component module "Panda.pm"
package Panda;
use strict;
use HTML::Application;
sub main {
my ($class, $globals) = @_;
$globals->set_page_body( <<__endquote );
<P>Food: @{[$globals->pref( 'food' )]}
<BR>Color: @{[$globals->pref( 'color' )]}
<BR>Size: @{[$globals->pref( 'size' )]}</P>
<P>Now let's look at some files; take your pick:
__endquote
$globals->navigate_url_path( $globals->pref( 'file_reader' ) );
foreach my $frag (@{$globals->pref( 'files' )}) {
my $url = $globals->url_as_string( $frag );
$globals->append_page_body( "<BR><A HREF=\"$url\">$frag</A>" );
}
$globals->append_page_body( "</P>" );
}
1;
Content of component module "Owl.pm"
package Owl;
use strict;
use HTML::Application;
sub main {
my ($class, $globals) = @_;
my $url = $globals->pref( 'fly_to' );
$globals->http_status_code( '301 Moved' );
$globals->http_redirect_url( $url );
}
1;
Content of component module "Camel.pm"
package Camel;
use strict;
use HTML::Application;
sub main {
my ($class, $globals) = @_;
my $users_choice = $globals->current_user_path_element();
my $filename = $globals->pref( $users_choice );
my $filepath = $globals->physical_filename( $filename );
SWITCH: {
open( FH, $filepath ) or do {
$globals->add_virtual_filename_error( 'open', $filename );
last SWITCH;
};
local $/ = undef;
defined( my $file_content = <FH> ) or do {
$globals->add_virtual_filename_error( "read from", $filename );
last SWITCH;
};
close( FH ) or do {
$globals->add_virtual_filename_error( "close", $filename );
last SWITCH;
};
$globals->set_page_body( $file_content );
}
if( $globals->get_error() ) {
$globals->append_page_body(
"Can't show requested screen: ".$globals->get_error() );
}
}
1;
DESCRIPTION
This Perl 5 object class is a framework intended to support complex web applications that are easily portable across servers because common environment-specific details are abstracted away, including the file system type, the web server type, and your project's location in the file system or uri hierarchy. In addition, this class can make it easier for your applications to be broken down into reusable data-controlled components, each of which would act like it was its own application, which receives user input and instance configuration data some how, and returns an HTML page or other HTTP response.
OVERVIEW
This class is designed primarily as a data structure that intermediates between your large central program logic and the small shell part of your code that knows anything specific about your environment. The way that this works is that the shell code instantiates an HTML::Application object and stores any valid user input in it, gathered from the appropriate places in the current environment. Then the central program is started and given the HTML::Application object, from which it takes stored user input and performs whatever tasks it needs to. The central program stores its user output in the same HTML::Application object and then quits. Finally, the shell code takes the stored user output from the HTML::Application object and does whatever is necessary to send it to the user. Similarly, your thin shell code knows where to get the instance-specific file system and stored program settings data, which it gives to the HTML::Application object along with the user input.
Here is a diagram:
YOUR THIN HTML::Application YOUR FAT "CORE"
USER <----> "MAIN" CONFIG, <----> INTERFACE LAYER <----> PROGRAM LOGIC
I/O SHELL FRAMEWORK FUNCTIONALITY
(may be portable) (portable) (portable)
This class does not gather any user input or send any user input by itself, but expects your thin program instance shell to do that. The rationale is both for keeping this class simpler and for keeping it compatible with all types of web servers instead of just the ones it knows about. So it works equally well with CGI under any server or mod_perl or when your Perl is its own web server or when you are debugging on the command line.
Because your program core uses this class to communicate with its "superior", it can be written the same way regardless of what platform it is running on. The interface that it needs to written to is consistent across platforms. An analogy to this is that the core always plays in the same sandbox and that environment is all it knows; you can move the sandbox anywhere you want and its occupant doesn't have to be any the wiser to how the outside world had changed.
From there, it is a small step to breaking your program core into reusable components and using HTML::Application as an interface between them. Each component exists in its own sandbox and acts like it is its own core program, with its own task to produce an html page or other http response, and with its own set of user input and program settings to tell it how to do its job. Depending on your needs, each "component" instance could very well be its own complete application, or it would in fact be a subcontractee of another one. In the latter case, the "subcontractor" component may have other components do a part of its own task, and then assemble a derivative work as its own output.
When one component wants another to do work for it, the first one instantiates a new HTML::Application object which it can pass on any user input or settings data that it wishes, and then provides this to the second component; the second one never has to know where its HTML::Application object it has came from, but that everything it needs to know for its work is right there. This class provides convenience methods like make_new_context() to simplify this task by making a partial clone that replicates input but not output data.
Due to the way HTML::Application stores program settings and other input/output data, it lends itself well to supporting data-driven applications. That is, your application components can be greatly customizable as to their function by simply providing instances of them with different setup data. If any component is so designed, its own config instructions can detail which other components it subcontracts, as well as what operating contexts it sets up for them. This results in a large variety of functionality from just a small set of components.
Another function that HTML::Application provides for component management is that there is limited protection for components that are not properly designed to be kept from harming other ones. You see, any components designed a certain way can be invoked by HTML::Application itself at the request of another component. This internal call is wrapped in an eval block such that if a component fails to compile or has a run-time exception, this class will log an error to the effect and the component that called it continues to run. Also, called components get a different HTML::Application object than the parent, so that if they mess around with the stored input/output then the parent component's own data isn't lost. It is the parent's own choice as to which output of its child that it decides to copy back into its own output, with or without further processing.
Note that the term "components" above suggests that each one is structured as a Perl 5 module and is called like one; the module should have a method called main() that takes an HTML::Application object as its argument and has the dispatch code for that component. Of course, it is up to you.
SYNTAX
This class does not export any functions or methods, so you need to call them using object notation. This means using Class->function() for functions and $object->method() for methods. If you are inheriting this class for your own modules, then that often means something like $self->method().
CONSTRUCTOR FUNCTIONS AND METHODS
These functions and methods are involved in making new HTML::Application objects.
new([ FILE_ROOT[, FILE_DELIM[, PREFS]] ])
This function creates a new HTML::Application (or subclass) object and returns it. All of the method arguments are passed to initialize() as is; please see the POD for that method for an explanation of them.
initialize([ FILE_ROOT[, FILE_DELIM[, PREFS]] ])
This method is used by new() to set the initial properties of objects that it creates. The optional 3 arguments are used in turn to set the properties accessed by these methods: file_path_root(), file_path_delimiter(), set_prefs().
clone([ CLONE ])
This method initializes a new object to have all of the same properties of the current object and returns it. This new object can be provided in the optional argument CLONE (if CLONE is an object of the same class as the current object); otherwise, a brand new object of the current class is used. Only object properties recognized by HTML::Application are set in the clone; other properties are not changed.
METHODS FOR DEBUGGING
is_debug([ VALUE ])
This method is an accessor for the "is debug" boolean property of this object, which it returns. If VALUE is defined, this property is set to it. If this property is true then it indicates that the program is currently being debugged by the owner/maintainer; if it is false then the program is being run by a normal user. How or whether the program reacts to this fact is quite arbitrary. For example, it may just keep a separate set of usage logs or append "debug" messages to email or web pages it makes.
METHODS FOR ERROR MESSAGES
These methods are accessors for the "error list" property of this object, which is designed to accumulate any error strings that should be printed to the program's error log or shown to the user before the program exits. What constitutes an error condition is up to you, but the suggested use is for things that are not the web user's fault, such as problems compiling or calling program modules, or problems using file system files for settings or data. The errors list is not intended to log invalid user input, which would be common activity. Since some errors are non-fatal and other parts of your program would still work, it is possible for several errors to happen in parallel; hence a list. At program start-up this list starts out empty.
An extension to this feature is the concept of "no error" messages (undefined strings) which if used indicate that the last operation *did* work. This gives you the flexability to always record the result of an operation for acting on later. If you use get_error() in a boolean context then it would be true if the last noted operation had an error and false if it didn't. You can also issue an add_no_error() to mask errors that have been dealt with so they don't continue to look unresolved.
get_errors()
This method returns a list of the stored error messages with any undefined strings (no error) filtered out.
get_error([ INDEX ])
This method returns a single error message. If the numerical argument INDEX is defined then the message is taken from that element in the error list. INDEX defaults to -1 if not defined, so the most recent message is returned.
add_error( MESSAGE )
This method appends the scalar argument MESSAGE to the error list.
add_no_error()
This message appends an undefined value to the error list, a "no error" message.
add_virtual_filename_error( UNIQUE_PART, FILENAME )
This message constructs a new error message using its arguments and appends it to the error list. You can call this after doing a file operation that failed where UNIQUE_PART is a sentence fragment like "open" or "read from" and FILENAME is the relative portion of the file name. The new message looks like "can't [UNIQUE_PART] file '[FILEPATH]': $!" where FILEPATH is defined as the return value of "virtual_filename( FILENAME )".
add_physical_filename_error( UNIQUE_PART, FILENAME )
This message constructs a new error message using its arguments and appends it to the error list. You can call this after doing a file operation that failed where UNIQUE_PART is a sentence fragment like "open" or "read from" and FILENAME is the relative portion of the file name. The new message looks like "can't [UNIQUE_PART] file '[FILEPATH]': $!" where FILEPATH is defined as the return value of "physical_filename( FILENAME )".
METHODS FOR THE VIRTUAL FILE SYSTEM
These methods are accessors for the "file path" property of this object, which is designed to facilitate easy portability of your application across multiple file systems or across different locations in the same file system. It maintains a "virtual file system" that you can use, within which your program core owns the root directory.
Your program core would take this virtual space and organize it how it sees fit for configuration and data files, including any use of subdirectories that is desired. This class will take care of mapping the virtual space onto the real one, in which your virtual root is actually a subdirectory and your path separators may or may not be UNIXy ones.
If this class is faithfully used to translate your file system operations, then you will stay safely within your project root directory at all times. Your core app will never have to know if the project is moved around since details of the actual file paths, including level delimiters, has been abstracted away. It will still be able to find its files. Only your program's thin instance startup shell needs to know the truth.
The file path property is a File::VirtualPath object so please see the POD for that class to learn about its features.
get_file_path_ref()
This method returns a reference to the file path object which you can then manipulate directly with File::VirtualPath methods.
file_path_root([ VALUE ])
This method is an accessor for the "physical root" string property of the file path, which it returns. If VALUE is defined then this property is set to it. This property says where your project directory is actually located in the current physical file system, and is used in translations from the virtual to the physical space. The only part of your program that should set this method is your thin startup shell; the rest should be oblivious to it.
file_path_delimiter([ VALUE ])
This method is an accessor for the "physical delimiter" string property of the file path, which it returns. If VALUE is defined then this property is set to it. This property says what character is used to delimit directory path levels in your current physical file system, and is used in translations from the virtual to the physical space. The only part of your program that should set this method is your thin startup shell; the rest should be oblivious to it.
file_path([ VALUE ])
This method is an accessor to the "virtual path" array property of the file path, which it returns. If VALUE is defined then this property is set to it; it can be an array of path levels or a string representation in the virtual space. This method returns an array ref having the current virtual file path.
file_path_string([ TRAILER ])
This method returns a string representation of the file path in the virtual space. If the optional argument TRAILER is true, then a virtual file path delimiter, "/" by default, is appended to the end of the returned value.
navigate_file_path( CHANGE_VECTOR )
This method updates the "virtual path" property of the file path by taking the current one and applying CHANGE_VECTOR to it using the FVP's chdir() method. This method returns an array ref having the changed virtual file path.
virtual_filename( CHANGE_VECTOR[, WANT_TRAILER] )
This method uses CHANGE_VECTOR to derive a new path in the virtual file-system relative to the current one and returns it as a string. If WANT_TRAILER is true then the string has a path delimiter appended; otherwise, there is none.
physical_filename( CHANGE_VECTOR[, WANT_TRAILER] )
This method uses CHANGE_VECTOR to derive a new path in the real file-system relative to the current one and returns it as a string. If WANT_TRAILER is true then the string has a path delimiter appended; otherwise, there is none.
METHODS FOR INSTANCE PREFERENCES
These methods are accessors for the "preferences" property of this object, which is designed to facilitate easy access to your application instance settings. The "preferences" is a hierarchical data structure which has a hash as its root and can be arbitrarily complex from that point on. A hash is used so that any settings can be accessed by name; the hierarchical nature comes from any setting values that are references to non-scalar values, or resolve to such.
HTML::Application makes it easy for your preferences structure to scale across any number of storage files, helping with memory and speed efficiency. At certain points in your program flow, branches of the preferences will be followed until a node is reached that your program wants to be a hash. At that point, this node can be given back to this class and resolved into a hash one way or another. If it already is a hash ref then it is given back as is; otherwise it is taken as a filename for a Perl file which when evaluated with "do" returns a hash ref. This filename would be a relative path in the virtual file system and this class would resolve it properly.
Since the fact of hash-ref-vs-filename is abstracted from your program, this makes it easy for your data itself to determine how the structure is segmented. The decision-making begins with the root preferences node that your thin config shell gives to HTML::Application at program start-up. What is resolved from that determines how any child nodes are gotten, and they determine their children. Since this class handles such details, it is much easier to make your program data-controlled rather than code-controlled. For instance, your startup shell may contain the entire preferences structure itself, meaning that you only need a single file to define a project instance. Or, your startup shell may just have a filename for where the preferences really are, making it minimalist. Depending how your preferences are segmented, only the needed parts actually get loaded, so we save resources.
resolve_prefs_node_to_hash( RAW_NODE )
This method takes a raw preferences node, RAW_NODE, and resolves it into a hash ref, which it returns. If RAW_NODE is a hash ref then this method performs a single-level copy of it and returns a new hash ref. Otherwise, this method takes the argument as a filename and tries to execute it. If the file fails to execute for some reason or it doesn't return a hash ref, then this method adds a file error message and returns an empty hash ref. The file is executed with "do [FILEPATH]" where FILEPATH is defined as the return value of "physical_filename( FILENAME )". The error message uses a virtual path.
resolve_prefs_node_to_array( RAW_NODE )
This method takes a raw preferences node, RAW_NODE, and resolves it into an array ref, which it returns. If RAW_NODE is a hash ref then this method performs a single-level copy of it and returns a new array ref. Otherwise, this method takes the argument as a filename and tries to execute it. If the file fails to execute for some reason or it doesn't return an array ref, then this method adds a file error message and returns an empty array ref. The file is executed with "do [FILEPATH]" where FILEPATH is defined as the return value of "physical_filename( FILENAME )". The error message uses a virtual path.
get_prefs_ref()
This method returns a reference to the internally stored "preferences" hash.
set_prefs( VALUE )
This method sets this object's preferences property with the return value of "resolve_prefs_node_to_hash( VALUE )", even if VALUE is not defined.
pref( KEY[, VALUE] )
This method is an accessor to individual settings in this object's preferences property, and returns the setting value whose name is defined in the scalar argument KEY. If the optional scalar argument VALUE is defined then it becomes the value for this setting. All values are set or fetched with a scalar copy.
METHODS FOR USER INPUT
These methods are accessors for the "user input" properties of this object, which include: "user path", "user query", "user post", and "user cookies". These properties store parsed copies of the various information that the web user provided when invoking this program instance. Note that you should not modify the user input in your program, since the recall methods depend on them.
This class does not gather any user input itself, but expects your thin program instance shell to do that and hand the data to this class prior to starting the program core. The rationale is both for keeping this class simpler and for keeping it compatible with all types of web servers instead of just the ones it knows about. So it works equally well with CGI under any server or mod_perl or when your Perl is its own web server or when you are debugging on the command line. This class does know how to *parse* some url-encoded strings, however.
The kind of input you need to gather depends on what your program uses, but it doesn't hurt to get more. If you are in a CGI environment then you often get user input from the following places: 1. $ENV{QUERY_STRING} for the query string -- pass to user_query(); 2. <STDIN> for the post data -- pass to user_post(); 3. $ENV{HTTP_COOKIE} for the raw cookies -- pass to user_cookies(); 4. either $ENV{PATH_INFO} or a query parameter for the virtual web resource path -- pass to user_path(). If you are in mod_perl then you call Apache methods to get the user input. If you are your own server then the incoming HTTP headers contain everything except the post data, which is in the HTTP body. If you are on the command line then you can look in @ARGV or <STDIN> as is your preference.
The virtual web resource path is a concept with HTML::Application designed to make it easy for different user interface pages of your program to be identified and call each other in the web environment. The idea is that all the interface components that the user sees have a unique uri and can be organized hierarchically like a tree; by invoking your program with a different "path", the user indicates what part of the program they want to use. It is analogous to choosing different html pages on a normal web site because each page has a separate uri on the server, and each page calls others by using different uris. What makes the virtual paths different is that each uri does not correspond to a different file; the user just pretends they do. Ultimately you have control over what your program does with any particular virtual "user path".
The user path property is a File::VirtualPath object, and the other user input properties are each CGI::MultiValuedHash objects, so please see the respective POD for those classes to learn about their features. Note that the user path always works in the virtual space and has no physical equivalent like file path.
get_user_path_ref()
This method returns a reference to the user path object which you can then manipulate directly with File::VirtualPath methods.
user_path([ VALUE ])
This method is an accessor to the user path, which it returns as an array ref. If VALUE is defined then this property is set to it; it can be an array of path levels or a string representation.
user_path_string([ TRAILER ])
This method returns a string representation of the user path. If the optional argument TRAILER is true, then a "/" is appended.
user_path_element( INDEX[, NEW_VALUE] )
This method is an accessor for individual segments of the "user path" property of this object, and it returns the one at INDEX. If NEW_VALUE is defined then the segment at INDEX is set to it. This method is useful if you want to examine user path segments one at a time. INDEX defaults to 0, meaning you are looking at the first segment, which happens to always be empty. That said, this method will let you change this condition if you want to.
current_user_path_level([ NEW_VALUE ])
This method is an accessor for the number "current path level" property of the user input, which it returns. If NEW_VALUE is defined, this property is set to it. If you want to examine the user path segments sequentially then this property tracks the index of the segment you are currently viewing. This property defaults to 0, the first segment, which always happens to be an empty string.
inc_user_path_level()
This method will increment the "current path level" property by 1 so you can view the next path segment. The new current value is returned.
dec_user_path_level()
This method will decrement the "current path level" property by 1 so you can view the previous path segment. The new current value is returned.
current_user_path_element([ NEW_VALUE ])
This method is an accessor for individual segments of the "user path" property of this object, the current one of which it returns. If NEW_VALUE is defined then the current segment is set to it. This method is useful if you want to examine user path segments one at a time in sequence. The segment you are looking at now is determined by the current_user_path_level() method; by default you are looking at the first segment, which is always an empty string. That said, this method will let you change this condition if you want to.
get_user_query_ref()
This method returns a reference to the user query object which you can then manipulate directly with CGI::MultiValuedHash methods.
user_query([ VALUE ])
This method is an accessor to the user query, which it returns as a cloned CGI::MultiValuedHash object. If VALUE is defined then it is used to initialize a new user query.
user_query_string()
This method url-encodes the user query and returns it as a string.
user_query_param( KEY[, VALUES] )
This method is an accessor for individual user query parameters. If there are any VALUES then this method stores them in the query under the name KEY and returns a count of values now associated with KEY. VALUES can be either an array ref or a literal list and will be handled correctly. If there are no VALUES then the current value(s) associated with KEY are returned instead. If this method is called in list context then all of the values are returned as a literal list; in scalar context, this method returns only the first value. The 3 cases that this method handles are implemented with the query object's [store( KEY, *), fetch( KEY ), fetch_value( KEY )] methods, respectively. (This method is designed to work like CGI.pm's param() method, if you like that sort of thing.)
get_user_post_ref()
This method returns a reference to the user post object which you can then manipulate directly with CGI::MultiValuedHash methods.
user_post([ VALUE ])
This method is an accessor to the user post, which it returns as a cloned CGI::MultiValuedHash object. If VALUE is defined then it is used to initialize a new user post.
user_post_string()
This method url-encodes the user post and returns it as a string.
user_post_param( KEY[, VALUES] )
This method is an accessor for individual user post parameters. If there are any VALUES then this method stores them in the post under the name KEY and returns a count of values now associated with KEY. VALUES can be either an array ref or a literal list and will be handled correctly. If there are no VALUES then the current value(s) associated with KEY are returned instead. If this method is called in list context then all of the values are returned as a literal list; in scalar context, this method returns only the first value. The 3 cases that this method handles are implemented with the post object's [store( KEY, *), fetch( KEY ), fetch_value( KEY )] methods, respectively. (This method is designed to work like CGI.pm's param() method, if you like that sort of thing.)
get_user_cookies_ref()
This method returns a reference to the user cookies object which you can then manipulate directly with CGI::MultiValuedHash methods.
user_cookies([ VALUE ])
This method is an accessor to the user cookies, which it returns as a cloned CGI::MultiValuedHash object. If VALUE is defined then it is used to initialize a new user query.
user_cookies_string()
This method cookie-url-encodes the user cookies and returns them as a string.
user_cookie( NAME[, VALUES] )
This method is an accessor for individual user cookies. If there are any VALUES then this method stores them in the cookie with the name NAME and returns a count of values now associated with NAME. VALUES can be either an array ref or a literal list and will be handled correctly. If there are no VALUES then the current value(s) associated with NAME are returned instead. If this method is called in list context then all of the values are returned as a literal list; in scalar context, this method returns only the first value. The 3 cases that this method handles are implemented with the query object's [store( NAME, *), fetch( NAME ), fetch_value( NAME )] methods, respectively. (This method is designed to work like CGI.pm's param() method, if you like that sort of thing.)
METHODS FOR MAKING NEW SELF-REFERENCING URLS
These methods are accessors for the "url constructor" properties of this object, which are designed to store components of the various information needed to make new urls that call this script back in order to change from one interface screen to another. When the program is reinvoked with one of these urls, this information becomes part of the user input, particularly the "user path" and "user query". You normally use the url_as_string() method to do the actual assembly of these components, but the various "recall" methods also pay attention to them.
url_base([ VALUE ])
This method is an accessor for the "url base" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. When new urls are made, the "url base" is used unchanged as its left end. Normally it would consist of a protocol, host domain, port (optional), script name, and would look like "protocol://host[:port][script]". For example, "http://aardvark.net/main.pl" or "http://aardvark.net:450/main.pl". This property defaults to "http://localhost/".
get_url_path_ref()
This method returns a reference to the url path object which you can then manipulate directly with File::VirtualPath methods.
url_path([ VALUE ])
This method is an accessor to the url path, which it returns as an array ref. If VALUE is defined then this property is set to it; it can be an array of path levels or a string representation.
url_path_string([ TRAILER ])
This method returns a string representation of the url path. If the optional argument TRAILER is true, then a "/" is appended.
navigate_url_path( CHANGE_VECTOR )
This method updates the url path by taking the current one and applying CHANGE_VECTOR to it using the FVP's chdir() method. This method returns an array ref having the changed url path.
child_url_path_string( CHANGE_VECTOR[, WANT_TRAILER] )
This method uses CHANGE_VECTOR to derive a new url path relative to the current one and returns it as a string. If WANT_TRAILER is true then the string has a path delimiter appended; otherwise, there is none.
get_url_query_ref()
This method returns a reference to the "url query" object which you can then manipulate directly with CGI::MultiValuedHash methods.
url_query([ VALUE ])
This method is an accessor to the "url query", which it returns as a cloned CGI::MultiValuedHash object. If VALUE is defined then it is used to initialize a new user query.
url_query_string()
This method url-encodes the url query and returns it as a string.
url_query_param( KEY[, VALUES] )
This method is an accessor for individual url query parameters. If there are any VALUES then this method stores them in the query under the name KEY and returns a count of values now associated with KEY. VALUES can be either an array ref or a literal list and will be handled correctly. If there are no VALUES then the current value(s) associated with KEY are returned instead. If this method is called in list context then all of the values are returned as a literal list; in scalar context, this method returns only the first value. The 3 cases that this method handles are implemented with the query object's [store( KEY, *), fetch( KEY ), fetch_value( KEY )] methods, respectively. (This method is designed to work like CGI.pm's param() method, if you like that sort of thing.)
url_path_is_in_path_info([ VALUE ])
This method is an accessor for the "url path is in path info" boolean property of this object, which it returns. If VALUE is defined, this property is set to it. If this property is true then the "url path" property will persist as part of the "path_info" portion of all self-referencing urls. This property defaults to true.
url_path_is_in_query([ VALUE ])
This method is an accessor for the "url path is in query" boolean property of this object, which it returns. If VALUE is defined, this property is set to it. If this property is true then the "url path" property will persist as part of the "query_string" portion of all self-referencing urls. This property defaults to false.
url_path_query_param_name([ VALUE ])
This method is an accessor for the "url path query param name" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. If the url path persists as part of a query string, this method defines the name of the query parameter that the url path is the value for. This property defaults to 'path'.
url_as_string([ CHANGE_VECTOR ])
This method assembles the various "url *" properties of this object into a complete HTTP url and returns it as a string. That is, it returns the cumulative string representation of those properties. This consists of a url_base(), "path info", "query string", and would look like "base[info][?query]". For example, "http://aardvark.net/main.pl/lookup/title?name=plant&cost=low". Depending on your settings, the url path may be in the path_info or the query_string or none or both. If the optional argument CHANGE_VECTOR is true then the result of applying it to the url path is used for the url path. The above example showed the url path, "/lookup/title", in the path_info. If it were in query_string instead then the url would look like "http://aardvark.net/main.pl?path=/lookup/title&name=plant&cost=low".
METHODS FOR MAKING RECALL URLS
These methods are designed to make HTML for the user to reinvoke this program with their input intact. They pay attention to both the current user input and the current url constructor properties. Specifically, these methods act like url_as_string() in the way they use most url constructor properties, but they use the user path and user query instead of the url path and url query.
recall_url()
This method creates a callback url that can be used to recall this program with all query information intact. It is intended for use as the "action" argument in forms, or as the url for "try again" hyperlinks on error pages. The format of this url is determined partially by the "url *" properties, including url_base() and anything describing where the "path" goes, if you use it. Post data is not replicated here; see the recall_button() method.
recall_hyperlink([ LABEL ])
This method creates an HTML hyperlink that can be used to recall this program with all query information intact. The optional scalar argument LABEL defines the text that the hyperlink surrounds, which is the blue text the user will see. LABEL defaults to "here" if not defined. Post data is not replicated. The url in the hyperlink is produced by recall_url().
recall_button([ LABEL ])
This method creates an HTML form out of a button and some hidden fields which can be used to recall this program with all query and post information intact. The optional scalar argument LABEL defines the button label that the user sees. LABEL defaults to "here" if not defined. This form submits with "post". Query and path information is replicated in the "action" url, produced by recall_url(), and the post information is replicated in the hidden fields.
recall_html([ LABEL ])
This method selectively calls recall_button() or recall_hyperlink() depending on whether there is any post information in the user input. This is useful when you want to use the least intensive option required to preserve your user input and you don't want to figure out the when yourself.
METHODS FOR MAKING NEW HTML PAGES
These methods are designed to accumulate and assemble the components of a new HTML page, complete with body, title, meta tags, and cascading style sheets. The intent is for your core program to use these to store its user output, and then your thin program config shell would actually send the page to the user. Note that the "http body" property should not be used at the same time as these.
page_title([ VALUE ])
This method is an accessor for the "page title" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. This property is used in the header of a new HTML document to define its title. Specifically, it goes between a <TITLE></TITLE> tag pair.
page_author([ VALUE ])
This method is an accessor for the "page author" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. This property is used in the header of a new HTML document to define its author. Specifically, it is used in a new '<LINK REV="made">' tag if defined.
get_page_meta_ref()
This method is an accessor for the "page meta" hash property of this object, a reference to which it returns. Meta information is used in the header of a new HTML document to say things like what the best keywords are for a search engine to index this page under. Each key/value pair in the hash would have a '<META NAME="k" VALUE="v">' tag made out of it.
get_page_meta([ KEY ])
This method allows you to get the "page meta" hash property of this object. If KEY is defined then it is taken as a key in the hash and the associated value is returned. If KEY is not defined then the entire hash is returned as a list; in scalar context this list is in a new hash ref.
set_page_meta( KEY[, VALUE] )
This method allows you to set the "page meta" hash property of this object. If KEY is a valid HASH ref then all the existing meta information is replaced with the new hash keys and values. If KEY is defined but it is not a Hash ref, then KEY and VALUE are inserted together into the existing hash.
get_page_style_sources_ref()
This method is an accessor for the "page style sources" array property of this object, a reference to which it returns. Cascading Style Sheet (CSS) definitions are used in the header of a new HTML document to allow precise control over the appearance of of page elements, something that HTML itself was not designed for. This property stores urls for external documents having stylesheet definitions that you want linked to the current document. If this property is defined, then a '<LINK REL="stylesheet" SRC="url">' tag would be made for each list element.
get_page_style_sources()
This method returns a list containing "page style sources" list elements. This list is returned literally in list context and as an array ref in scalar context.
set_page_style_sources( VALUE )
This method allows you to set or replace the current "page style sources" definitions. The argument VALUE can be either an array ref or literal list.
get_page_style_code_ref()
This method is an accessor for the "page style code" array property of this object, a reference to which it returns. Cascading Style Sheet (CSS) definitions are used in the header of a new HTML document to allow precise control over the appearance of of page elements, something that HTML itself was not designed for. This property stores CSS definitions that you want embedded in the HTML document itself. If this property is defined, then a "<STYLE><!-- code --></STYLE>" multi-line tag is made for them.
get_page_style_code()
This method returns a list containing "page style code" list elements. This list is returned literally in list context and as an array ref in scalar context.
set_page_style_code( VALUE )
This method allows you to set or replace the current "page style code" definitions. The argument VALUE can be either an array ref or literal list.
get_page_head_ref()
This method is an accessor for the "page head" array property of this object, a reference to which it returns. While this property actually represents a scalar value, it is stored as an array for possible efficiency, considering that new portions may be appended or prepended to it as the program runs. This property is inserted between the "<HEAD></HEAD>" tags of a new HTML page, following any other properties that go in that section.
get_page_head()
This method returns a string of the "page body" joined together.
set_page_head( VALUE )
This method allows you to set or replace the current "page head" with a new one. The argument VALUE can be either an array ref or scalar or literal list.
append_page_head( VALUE )
This method allows you to append content to the current "page head". The argument VALUE can be either an array ref or scalar or literal list.
prepend_page_head( VALUE )
This method allows you to prepend content to the current "page head". The argument VALUE can be either an array ref or scalar or literal list.
get_page_body_attributes_ref()
This method is an accessor for the "page body attributes" hash property of this object, a reference to which it returns. Each key/value pair in the hash would become an attribute key/value of the opening <BODY> tag of a new HTML document. With the advent of CSS there wasn't much need to have the BODY tag attributes, but you may wish to do this for older browsers. In the latter case you could use body attributes to define things like the page background color or picture.
get_page_body_attributes([ KEY ])
This method allows you to get the "page body attributes" hash property of this object. If KEY is defined then it is taken as a key in the hash and the associated value is returned. If KEY is not defined then the entire hash is returned as a list; in scalar context this list is in a new hash ref.
set_page_body_attributes( KEY[, VALUE] )
This method allows you to set the "page body attributes" hash property of this object. If KEY is a valid HASH ref then all the existing attrib information is replaced with the new hash keys and values. If KEY is defined but it is not a Hash ref, then KEY and VALUE are inserted together into the existing hash.
get_page_body_ref()
This method is an accessor for the "page body" array property of this object, a reference to which it returns. While this property actually represents a scalar value, it is stored as an array for possible efficiency, considering that new portions may be appended or prepended to it as the program runs. This property is inserted between the "<BODY></BODY>" tags of a new HTML page.
get_page_body()
This method returns a string of the "page body" joined together.
set_page_body( VALUE )
This method allows you to set or replace the current "page body" with a new one. The argument VALUE can be either an array ref or scalar or literal list.
append_page_body( VALUE )
This method allows you to append content to the current "page body". The argument VALUE can be either an array ref or scalar or literal list.
prepend_page_body( VALUE )
This method allows you to prepend content to the current "page body". The argument VALUE can be either an array ref or scalar or literal list.
page_as_string()
This method assembles the various "page *" properties of this object into a complete HTML page and returns it as a string. That is, it returns the cumulative string representation of those properties. This consists of a prologue tag, a pair of "html" tags, and everything in between. This method uses HTML::EasyTags to do the actual page assembly, and so the results are consistant with its abilities.
METHODS FOR MAKING NEW HTTP RESPONSES
These methods are designed to accumulate and assemble the components of an HTTP response, complete with status code, content type, other headers, and a body. The intent is for your core program to use these to store its user output, and then your thin program config shell would actually send the page to the user. These properties are initialized with values suitable for returning an HTML page. The "http body" property is intended for use when you want to return raw content of any type, whether it is text or image or other binary. It is a complement for the html assembling methods and should be left undefined if they are used.
http_status_code([ VALUE ])
This method is an accessor for the "status code" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. This property is used in a new HTTP header to give the result status of the HTTP request that this program is serving. It defaults to "200 OK" which means success and that the HTTP body contains the document they requested. Unlike other HTTP header content, this property is special and must be the very first thing that the HTTP server returns, on a line like "HTTP/1.0 200 OK". However, the property also may appear elsewhere in the header, on a line like "Status: 200 OK".
http_content_type([ VALUE ])
This method is an accessor for the "content type" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. This property is used in a new HTTP header to indicate the document type that the HTTP body is, such as text or image. It defaults to "text/html" which means we are returning an HTML page. This property would be used in a line like "Content-type: text/html".
http_redirect_url([ VALUE ])
This method is an accessor for the "redirect url" scalar property of this object, which it returns. If VALUE is defined, this property is set to it. This property is used in a new HTTP header to indicate that we don't have the document that the user wants, but we do know where they can get it. If this property is defined then it contains the url we redirect to.
get_http_cookie_refs()
This method returns a list of references for outgoing http cookies, each of which is a Data::MultiValuedHash object. The list is returned as a literal list in list context and in an array ref in scalar context.
get_http_cookies()
This method returns a list of clones of outgoing http cookies. The list is returned as a literal list in list context and in an array ref in scalar context.
add_http_cookies( COOKIE_LIST )
This method takes a literal list of initializers as COOKIE_LIST and creates a new Data::MultiValuedHash object from each one, appending them to the list of outgoing http cookies. Each of these objects will make a single cookie, and keys for it include name, value, date, valid domains, and so forth. This class doesn't interpret them itself, but rather the thin program config shell can take the DMVH objects and process, encode, deliver them as it sees fit.
delete_http_cookies()
This method deletes all of the internally stored outgoing http cookies.
get_http_cookie_ref([ INDEX ])
This method returns a reference to a single outgoing http cookie object, taken from index INDEX from the internal array of outgoing cookies. INDEX defaults to -1 if not defined, the most recently added cookie. If there is no object at INDEX then undef is returned.
get_http_cookie([ INDEX ])
This method returns a clone of a single outgoing http cookie object, taken from index INDEX from the internal array of outgoing cookies. INDEX defaults to -1 if not defined, the most recently added cookie. If there is no object at INDEX then undef is returned.
get_http_headers_ref()
This method is an accessor for the "misc http headers" hash property of this object, a reference to which it returns. HTTP headers constitute the first of two main parts of an HTTP response, and says things like the current date, server type, content type of the document, cookies to set, and more. Some of these have their own methods, above, if you wish to use them. Each key/value pair in the hash would be used in a line like "Key: value".
get_http_headers([ KEY ])
This method allows you to get the "misc http headers" hash property of this object. If KEY is defined then it is taken as a key in the hash and the associated value is returned. If KEY is not defined then the entire hash is returned as a list; in scalar context this list is in a new hash ref.
set_http_headers( KEY[, VALUE] )
This method allows you to set the "misc http headers" hash property of this object. If KEY is a valid HASH ref then all the existing headers information is replaced with the new hash keys and values. If KEY is defined but it is not a Hash ref, then KEY and VALUE are inserted together into the existing hash.
http_body([ VALUE ])
This method is an accessor for the "http body" scalar property of this object, which it returns. This contitutes the second of two main parts of an HTTP response, and contains the actual document that the user will view and/or can save to disk. If this property is defined, then it will be used literally as the HTTP body part of the output. If this property is not defined then a new HTTP body of type text/html will be assembled out of the various "page *" properties instead. This property defaults to undefined.
http_body_is_binary([ VALUE ])
This method is an accessor for the "http body is binary" boolean property of this object, which it returns. If this property is true then it indicates that the HTTP body is binary and should be output with binmode on. It defaults to false.
METHODS FOR MISCELLANEOUS OBJECT SERVICES
get_misc_objects_ref()
This method returns a reference to this object's "misc objects" hash property. This hash stores references to any objects you want to pass between program components with services that are beyond the scope of this class, such as persistent database handles. This hash ref is static across all objects of this class that are derived from one another.
replace_misc_objects( HASH_REF )
This method lets this object have a "misc objects" property in common with another object that it doesn't already. If the argument HASH_REF is a hash ref, then this property is set to it.
separate_misc_objects()
This method lets this object stop having a "misc objects" property in common with another, by replacing that property with a new empty hash ref.
METHODS FOR CONTEXT SWITCHING
These methods are designed to facilitate easy modularity of your application into multiple components by providing context switching functions for the parent component in a relationship. While you could still use this class effectively without using them, they are available for your convenience.
make_new_context([ CONTEXT ])
This method initializes a new object of the current class and returns it. This new object has some of the current object's properties but lacks others. Specifically, what does get copied is: debug state, file path, preferences, all types of user input, the url constructor properties, and misc objects. What does not get copied is: error messages, html page components, and http response components. As with clone(), the new object can be provided in the optional argument CONTEXT (if CONTEXT is an object of the same class); otherwise a brand new object is used. Only properties recognized by HTML::Application are set in this object; others are not touched.
take_context_output( CONTEXT[, APPEND_LISTS[, SKIP_SCALARS]] )
This method takes another HTML::Application (or subclass) object as its CONTEXT argument and copies some of its properties to this object, potentially overwriting any versions already in this object. If CONTEXT is not a valid HTML::Application (or subclass) object then this method returns without changing anything. The properties that get copied are the "output" properties that presumably need to work their way back to the user. Specifically, what does get copied is: error messages, html page components, and http response components. What does not get copied is: debug state, file path, preferences, all types of user input, the url constructor properties, and misc objects. In other words, this method copies everything that make_new_context() did not. If the optional boolean argument APPEND_LISTS is true then any list-type properties, including arrays and hashes, get appended to the existing values where possible rather than just replacing them. In the case of hashes, however, keys with the same names are still replaced. If the optional boolean argument SKIP_SCALARS is true then scalar properties are not copied over; otherwise they will always replace any that are in this object already.
call_component( COMP_NAME[, CANCEL_ON_ERROR] )
This method can be used by one component to invoke another. For this to work, the called component needs to be a Perl 5 module with a method called main(). The argument COMP_NAME is a string containing the name of the module to be invoked. This method will first "require [COMP_NAME]" and then invoke its dispatch method with a "[COMP_NAME]->main()". These statements are wrapped in an "eval" block and if there was a compile or runtime failure then this method will log an error message like "can't use module '[COMP_NAME]': $@". The call_component() method will pass a reference to the HTML::Application object it is invoked from as an argument to the main() method of the called module. If you want the called component to get a different HTML::Application object then you will need to create it in your caller using make_new_context() or new() or clone(). If the boolean argument CANCEL_ON_ERROR is true then this method checks if there are errors already logged and if so it returns prior to ever requiring COMP_NAME. Any errors existing now were probably set by set_prefs(), meaning the component would be missing its config data. CANCEL_ON_ERROR defaults to false, which means that your component will deal with its own startup error itself.
UTILITY_METHODS
These methods handle miscellaneous functionality that may be useful.
search_and_replace_page_body( DO_THIS )
This method performs a customizable search-and-replace of this object's "page body" property. The argument DO_THIS is a hash ref whose keys are tokens to look for and the corresponding values are what to replace the tokens with. Tokens can be any Perl 5 regular expression and they are applied using "s/[find]/[replace]/g". Perl will automatically throw an exception if your regular expressions don't compile, so you should check them for validity before use. If DO_THIS is not a valid hash ref then this method returns without changing anything.
AUTHOR
Copyright (c) 1999-2001, Darren R. Duncan. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. However, I do request that this copyright information remain attached to the file. If you modify this module and redistribute a changed version then please attach a note listing the modifications.
I am always interested in knowing how my work helps others, so if you put this module to use in any of your own code then please send me the URL. Also, if you make modifications to the module because it doesn't work the way you need, please send me a copy so that I can roll desirable changes into the main release.
Address comments, suggestions, and bug reports to perl@DarrenDuncan.net.
SEE ALSO
perl(1), File::VirtualPath, HTML::EasyTags, Data::MultiValuedHash, CGI::MultiValuedHash, HTML::FormTemplate, mod_perl, Apache, HTTP::Headers, CGI::Cookie, CGI, HTML::Mason, CGI::Application, CGI::Screen, the duncand-prerelease distribution.