NAME
Maypole::Manual::Workflow - Describes the progress of a request through Maypole
SYNOPSIS
config $h
|
Maypole $r
Apache::Request |
+---- $r->get_request ---+
$ar |
|
$r->parse_location
|
$r->is_applicable
|
BeerDB::Beer $r->call_authenticate
->authenticate ------------+------------ $r->authenticate
|
$r->additional_data
|
$r->model_class->process($r)
|
$r->view_object->process($r)
DESCRIPTION
An application based on Maypole
will provide an Apache handler, and eventually deliver a page. This document explains how that happens, and how to influence it. We'll use the BeerDB
project as our example.
Initialize class
When the first request comes in, the class will call its own init
method. This creates a new view object, sets up inheritance relationships between the model classes and their parent, and so on.
Construction
Once we have initialized, the handler obtains the configuration for your class, and puts it into a new object. We'll call this a request object for the purposes of this document; it will be a new BeerDB
object.
Getting the request
Next, the handler calls get_request
on the new object to have it store a copy of the Apache::Request
. Of course, if you're not using Apache, you might want to subclass this method to return something that looks like an Apache::Request
object, and possibly also subclass the next stage too to get more control over what methods are called on your A::R
-lookalike. get_request
is expected to put the object in the ar
slot of the request object.
Handling the URL
Typically, the details of the request will be passed in the URL. This is done with the parse_location
method, which is expected to populate several slots of the request object. First, table
and action
should be populated with the name of the table and the action parts of the URL. Any other arguments should be placed in a listref in the args
slot, and GET and POST parameters should be arranged into a hash and placed in the query
and params
slots, respectively.
Some people may not like the idea of passing everything around in the URL; this is the method to override for you. Of course, you'll also need to provide your own default templates to construct links using your preferred format.
Is this an applicable URL?
Next, the is_applicable
method works out if this is actually something that Maypole
should care about - whether the class exists in the application, whether it supports the given action, and so on. The action is "supported" if it exists in the model class (or its ancestors) and is marked with the :Exported
attribute; this stops web users from firing off random subroutines in your code.
This should return an Apache status code; OK
if the request should proceed, DECLINED
if it should be passed on to the default handlers, or whatever other codes for permissions problems.
Are we allowed to do this?
We then look for an appropriate authenticate
method to call; first it will try calling the authenticate
method of the model class, or, if that does not exist, the authenticate
method on itself. By default, this allows access to everyone for everything. Similarly, this should return an Apache status code.
Add any additional data to the request
The open-ended additional_data
method allows any additional fiddling with the request object before it is despatched. Specifically, it allows you to add to the template_args
slot, which is a hash of arguments to be added to the template.
Ask model for widget set
Asking the model class to process
the current request allows it to do any work it needs for the given command, and populate the objects
and template
slots of the request.
Ask view to process template
Now the view class has its process
method called, finds the appropriate templates, passes the objects
and any additional data to the template, and pushes the output to the web server.
We will go into more detail about these last two phases.
Model class processing
The model's process
method is usually a thin wrapper around the action that we have selected. It sets the template name to the name of the action, fills objects
with an object of that class whose ID comes from the URL arguments if there is one. For instance, /beer/foo/12
will do the moral equivalent of
$r->objects([ BeerDB::Beer->retrieve(12) ]);
Then it calls the right method: in this case, the foo
method with the request object. This method will usually do any actions which are required, including modifying the list of objects to be passed to the template, or the name of the template to be called.
Template class processing
Finally, the template processor is handed the objects, the template name, and various other bits and pieces, and tries to find the right template. It does this by looking first for /beer/foo
: that is, a specific template appropriate to the class. Next, it looks at /custom/foo
, a local modification, before looking for /factory/foo
, one of the default templates that came with Maypole
.
Default template arguments
The following things are passed to the Template Toolkit template by default:
- request
-
The whole
Maypole
request object, for people getting really dirty with the templates. - objects
-
The objects handed to us by the model.
- base
-
The base URL of the application.
- config
-
The whole configuration hash for the application.
- classmetadata
-
A hash consisting of:
name
- The name of the model class for the request: e.g.BeerDB::Beer
.columns
- The names of the columns in this class.colnames
- A hash mapping between the database's idea of a column name and a human-readable equivalent. (abv
should be mapped toA.B.V.
, perhaps.)related_accessors
- A list of accessors which are not exactly fields in the table but are related by a has-many relationship. For instance, breweries have many beers, sobeers
would appear in the list.moniker
- The human-readable name for the class:beer
.plural
- The same, only plural:beers
.cgi
- A hash mapping columns andHTML::Element
objects representing a form field for editing that column.description
- (Perhaps) a user-supplied description of the class.
Additionally, depending on the number of objects, there will be an alias for the objects
slot with the name of the moniker or plural moniker.
That sounds a bit tricky, but what it means is that if you look at /beer/view/4
then beer
will be populated with a BeerDB::Beer
object with ID 4. On the other hand, if you look at /beer/list
you can get all the beers in beers
as well as in objects
.