App-Context
view release on metacpan or search on metacpan
lib/App/devguide.pod view on Meta::CPAN
By convention, "config.pl" is the config file for App CGI scripts.
However, the first file that is found is assumed to be the relevant config file.
If no config file is found or if it cannot be opened, an exception is thrown.
Otherwise, the text is read in from the file and deserialized into
a hash reference.
If the "configSerializerClass" was not specified in the arguments
(%main::conf, in this case), the file suffix for the config file
is used to determine the Serializer class to use for deserialization.
pl # use "eval" instead of a serializer
perl # App::Serializer::Dumper (like "pl" but use a serializer)
xml # App::Serializer::XMLSimple
ini # App::Serializer::Ini
properties # App::Serializer::Properties
conf # App::Serializer::Properties
stor # App::Serializer::Storable
If the file is a .pl file, no serializer is implied. It is just eval'ed.
(It must have "$var =" as the first non-whitespace text in the file,
where "var" is any variable name.)
If a Serializer is specified or implied, a serializer is instantiated
and the config file data is deserialized into a hash reference.
The resulting hash reference is returned and stored in $context->{config}.
=head2 App::Context::CGI->init()
The init() method is where the CGI object is created, parsing the
environment variables and STDIN which are
part of the CGI runtime environment.
For debugging purposes, a "debugmode" variable is checked in the
%args (i.e. %main::conf) to see if
special processing with the CGI object should be performed.
If "debugmode" is "record", the CGI objects and the %ENV hash will
be saved to files ("debug.vars" and "debug.env", respectively).
If "debugmode" is "replay", the current %ENV and CGI will be
cleared and loaded from the files from a previously recorded request.
Another sort of debugging is initialized if the "debug"
variable is supplied in the %args. This turns on a global debug
flag ($App::DEBUG) and sets the debug scope
(which classes or methods should produce debug output).
To support migration of code, the CGI object can also be passed into
the App->context() method as an argument, and it will be used rather
than trying to create a new one. However, this is not the execution
path being described here.
=head2 App::Session::HTMLHidden->new()
The constructor (new()) for App::Session::HTMLHidden is actually provided
by its grand-parent class, App::Reference.
It creates a hash reference by calling App::Reference->create(),
blesses it into the class, calls init()
(App::Session::HTMLHidden->init()),
and then returns the constructed Session::HTMLHidden object.
The init() method looks at the CGI variables in the request
and restores the session state information from the variable
named "app.sessiondata" (and "app.sessiondata[2..n]").
When the values of these variables are concatenated, they
form a Base64-encoded, gzipped, frozen multi-level hash of
session state data. To retrieve the state data, the text
is therefore decoded, gunzipped, and thawed (a la Storable).
This state is stored in $session->{state} and the session
cache is initialized to an empty hashref.
=head2 cgi-bin/app and dispatching events
The "app" program finally executes the following line.
$context->dispatch_events();
This does everything necessary to dispatch events which are
implied in the HTTP request, loading whatever data is needed,
modifying it, and saving it again to await the next request.
Please note that other Context implementations (i.e. Context::Modperl)
use the same API, but they may already have database connections
initialized, data already loaded, etc. However, the basic
CGI Context (Context::CGI) described here must initialize
everything at the outset and shut it all down at the completion
of each request.
=head2 App::Context::CGI->dispatch_events()
The CGI variables are examined. Variables which start with "app.event"
are identified as events to be handled, and they are saved for later.
These are called "event variables".
All other variables are understood to be widget attributes and they
are saved to their respective widgets.
Variables with any of the
"{}[]" "indexing" characters (such as "table_editor{data}[1][5]") are
called "indexed variables". The value is saved to the "table_editor"
widget, which evidently has an attribute called "data" which is a
two dimensional array.
Variables without the indexing characters but
with at least one dot (".") in them are "dotted variables"
of the form "widgetname.attributename". (This is a synonym for
"widgetname{attributename}", but it is handled more efficiently.)
Widget names may include dots, but attribute names may not.
Thus, the last dot separates the widget name from the attribute name.
So "app.toolbar.savebutton.width" is the "width" attribute on the
"app.toolbar.savebutton" widget.
Variables without indexing characters or dots are "plain variables".
If the special variable "wname" was also supplied, all plain variables
are understood to be attributes of the $wname widget. Otherwise,
all plain variables are stored in the "session" widget.
After all variables are stored in the Session, events are handled.
There are two kinds of events, "user events" (such as come from
<input type=submit> and <input type=image> tags) and "callback events"
(such as come from <input type=hidden> tags).
User events have a name that looks like one of the following.
app.event.widgetname.eventname
app.event.widgetname.eventname(arg1)
app.event.widgetname.eventname(arg1,arg2,...)
These events are parsed, the appropriate widget is summoned, and the
widget is instructed to handle the event (i.e. $w->handle_event()).
Callback events have a name that looks simply like "app.event".
The "widgetname.eventname(args)" is in the value of the variable.
After all events have been handled, the context calls
$self->display_current_widget() and then calls
$self->shutdown() which gracefully shuts down all connections
to repositories.
=head2 App::Context::CGI->display_current_widget()
The display_current_widget() method is implemented in the parent
class, App::Context::HTML.
A attribute "session.current_widget" contains the name of the current
widget to display.
If this is not set, check the CGI variable "wname"
(and set session.current_widget if found).
If this is not set, check the Initialization Config (i.e. the copy
of %main::conf, stored in the $context) for a variable named
"defaultWname".
If this is not set, use the $PATH_INFO, with internal "/'s"
converted to dots (i.e. "/app/selector" => "app.selector").
Otherwise, use "default" as the current widget
(and set session.current_widget).
Then the current widget is summoned and handed to the display_items()
method.
=head2 App::Context::CGI->display_items()
The job of display items is to take the list of args, convert them
to HTML, and print them to STDOUT with the appropriate HTTP headers
and wrapper HTML.
Also, depending on the %main::conf and the browser capabilities,
the content may be compressed (gzipped).
If the first argument to display_items() is a widget (which it is
in this flow of execution), the widget's attributes are checked to
see if any of the following are specified:
title
bgcolor
text
link
vlink
alink
leftmargin
topmargin
rightmargin
bottommargin
class
Any of those attributes which are set in the widget will be propagated
into the appropriate places in the <head> and <body> tags of the HTML
which wraps the widget HTML.
That's it. All of the processing for a single CGI request is complete.
All application code is wrapped up in user interface widgets
(App::Widget::HTML) and entity widgets (App::Widget::Entity).
The user interface widgets are mostly prepackaged, but are configured
( run in 0.887 second using v1.01-cache-2.11-cpan-39bf76dae61 )