Maypole - MVC web application framework |
Maypole - MVC web application framework
The canonical example used in the Maypole documentation is the beer database:
package BeerDB; use strict; use warnings; # choose a frontend, initialise the config object, and load a plugin use Maypole::Application qw/Relationship/;
# set everything up __PACKAGE__->setup("dbi:SQLite:t/beerdb.db"); # get the empty config object created by Maypole::Application my $config = __PACKAGE__->config; # basic settings $config->uri_base("http://localhost/beerdb"); $config->template_root("/path/to/templates"); $config->rows_per_page(10); $config->display_tables([qw/beer brewery pub style/]);
# table relationships $config->relationships([ "a brewery produces beers", "a style defines beers", "a pub has beers on handpumps", ]); # validation BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] ); BeerDB::Pub->untaint_columns( printable => [qw/name notes url/] ); BeerDB::Style->untaint_columns( printable => [qw/name notes/] ); BeerDB::Beer->untaint_columns( printable => [qw/abv name price notes/], integer => [qw/style brewery score/], date => [ qw/date/], );
# note : set up model before calling this method BeerDB::Beer->required_columns([qw/name/]);
1;
This documents the Maypole request object. See the the Maypole::Manual manpage, for a detailed guide to using Maypole.
Maypole is a Perl web application framework similar to Java's struts. It is essentially completely abstracted, and so doesn't know anything about how to talk to the outside world.
To use it, you need to create a driver package which represents your entire
application. This is the BeerDB
package used as an example in the manual.
This needs to first use the Maypole::Application manpage which will make your package
inherit from the appropriate platform driver such as Apache::MVC
or
CGI::Maypole
. Then, the driver calls setup
. This sets up the model classes
and configures your application. The default model class for Maypole uses
the Class::DBI manpage to map a database to classes, but this can be changed by altering
configuration (before calling setup.)
Note that some details in some of these resources may be out of date.
Maypole::Manual
pod documents included with the distribution.
In particular, there's a FAQ (http://maypole.perl.org/?FAQ) and a cookbook (http://maypole.perl.org/?Cookbook). Again, certain information on these pages may be out of date.
``From zero to Web-based database application in eight easy steps''.
Maypole won a 2005 Linux Journal Editor's Choice Award (http://www.linuxjournal.com/article/8293) after featuring in this article.
http://www-128.ibm.com/developerworks/linux/library/l-maypole/
As a framework, Maypole provides a number of hooks - methods that are intended to be overridden. Some of these methods come with useful default behaviour, others do nothing by default. Hooks include:
Class methods ------------- debug setup setup_model load_model_subclass init Instance methods ---------------- start_request_hook is_model_applicable get_session authenticate exception additional_data preprocess_path
sub My::App::debug {1}
Returns the debugging flag. Override this in your application class to enable/disable debugging.
You can also set the debug
flag via the Maypole::Application manpage.
Some packages respond to higher debug levels, try increasing it to 2 or 3.
My::App->setup($data_source, $user, $password, \%attr);
Initialise the Maypole application and plugins and model classes. Your application should call this after setting up configuration data via config.
It calls the hook setup_model
to setup the model. The %attr hash contains
options and arguments used to set up the model. See the particular model's
documentation. However here is the most usage of setup where
Maypole::Model::CDBI is the base class.
My::App->setup($data_source, $user, $password, { options => { # These are DB connection options AutoCommit => 0, RaiseError => 1, ... }, # These are Class::DBI::Loader arguments. relationships => 1, ... } );
Also, see the Maypole::Manual::Plugins manpage.
setup
. This method builds the Maypole model hierarchy.
A likely target for over-riding, if you need to build a customised model.
This method also ensures any code in custom model classes is loaded, so you don't need to load them in the driver.
load_model_subclass($subclass)
setup_model()
. It attempts to load the
$subclass
package, if one exists. So if you make a customized BeerDB::Beer
package, you don't need to explicitly load it.
If automatic loading causes problems, Override load_model_subclass in your driver.
sub load_model_subclass {};
Or perhaps during development, if you don't want to load up custom classes, you can override this method and load them manually.
You should not call this directly, but you may wish to override this to add application-specific initialisation - see the Maypole::Manual::Plugins manpage.
handler_guts
.
Run Maypole sub-requests as a component of the request
[% request.component("/beer/view_as_component/20") %]
Allows you to integrate the results of a Maypole request into an existing request. You'll need to set up actions and templates which return fragments of HTML rather than entire pages, but once you've done that, you can use the C<component> method of the Maypole request object to call those actions. You may pass a query string in the usual URL style.
You should not fully qualify the Maypole URLs.
Note: any HTTP POST or URL parameters passed to the parent are not passed to the component sub-request, only what is included in the url passed as an argyument to the method
Currently undocumented and liable to be refactored without warning.
path
, and invoking parse_path
and
parse_args
.
You should only need to define this method if you are writing a new Maypole backend.
The value of $r->status
is set to OK
before this hook is run. Your
implementation can change the status code, or leave it alone.
After this hook has run, Maypole will check the value of status
. For any
value other than OK
, Maypole returns the status
immediately.
This is useful for filtering out requests for static files, e.g. images, which should not be processed by Maypole or by the templating engine:
sub start_request_hook { my ($r) = @_; $r->status(DECLINED) if $r->path =~ /\.jpg$/; } Multiple plugins, and the driver, can define this hook - Maypole will call all of them. You should check for and probably not change any non-OK C<status> value:
package Maypole::Plugin::MyApp::SkipFavicon; sub start_request_hook { my ($r) = @_; # check if a previous plugin has already DECLINED this request # - probably unnecessary in this example, but you get the idea return unless $r->status == OK; # then do our stuff $r->status(DECLINED) if $r->path =~ /favicon\.ico/; } =cut
sub start_request_hook { }
is_model_applicable
instead, and change the return type
from a Maypole:Constant to a true/false value.
Returns a Maypole::Constant to indicate whether the request is valid.
The default implementation checks that $r->table
is publicly
accessible and that the model class is configured to handle the
$r->action
.
start_request_hook()
.
This method should return a session, which will be stored in the request's
session
attribute.
The default method is empty.
get_session
.
This method should return a user, which will be stored in the request's user
attribute.
The default method is empty.
The default implementation returns OK
This method first checks if the relevant model class can handle exceptions the user, or falls back to the default exception method of your Maypole application.
template_args
.
args
, action
and table
properties. Calls preprocess_path
before parsing path and setting properties.
This method is called after parse_location has populated the request information and before parse_path has populated the model and action information, and is passed the request object.
You can set action, args or table in this method and parse_path will then leave those values in place or populate them if not present
parse_path
. It generates a path to use
in links, form actions etc. To implement your own path scheme, just override
this method and parse_path
.
%args = ( table => $table, action => $action, additional => $additional, # optional - generally an object ID ); \%args = as above, but a ref @args = ( $table, $action, $additional ); # $additional is optional
id
can be used as an alternative key to additional
.
$additional
can be a string, an arrayref, or a hashref. An arrayref is
expanded into extra path elements, whereas a hashref is translated into a query
string.
uri_base
.
If the final element in @segments
is a hash ref, make_uri
will render it
as a query string.
params
.
You should only need to define this method if you are writing a new Maypole backend.
You should only need to define this method if you are writing a new Maypole backend. Otherwise, see template_root in the Maypole::Config manpage
table
attribute.
If the first item in $self->args
can be retrieve()
d by the model
class, it will be removed from args
and the retrieved object will be added to
the objects
list. See the Maypole::Model manpage for more information.
When used to set the object, will overwrite the request objects with a single object.
$self->template_args->{foo} = 'bar';
Get/set a hash of template variables.
Maypole reserved words for template variables will over-ride values in template_variables.
Reserved words are : r, request, object, objects, base, config and errors, as well as the current class or object name.
$self->action
output
.
The source of the parameters may vary depending on the Maypole backend, but they are usually populated from request query string and POST data.
Maypole supplies several approaches for accessing the request parameters. Note
that the current implementation (via a hashref) of query
and params
is
likely to change in a future version of Maypole. So avoid direct access to these
hashrefs:
$r->{params}->{foo} # bad $r->params->{foo} # better
$r->{query}->{foo} # bad $r->query->{foo} # better
$r->param('foo') # best
$r->param # returns list of keys $r->param($key) # returns value for $key $r->param($key => $value) # returns old value, sets to new value
Note: Where muliple values of a parameter were supplied, the params
value
will be an array reference.
params
.
Accepts either a single argument of the full url to redirect to, or a hash of named parameters :
$r->redirect_request('http://www.example.com/path');
or
$r->redirect_request(protocol=>'https', domain=>'www.example.com', path=>'/path/file?arguments', status=>'302', url=>'..');
The named parameters are protocol, domain, path, status and url
Only 1 named parameter is required but other than url, they can be combined as required and current values (from the request) will be used in place of any missing arguments. The url argument must be a full url including protocol and can only be combined with status.
See the Maypole::Manual::Workflow manpage for a detailed discussion of the sequence of calls during processing of a request. This is a brief summary:
INITIALIZATION Model e.g. BeerDB Maypole::Model::CDBI | | setup | | o-------->|| | || setup_model | setup_database() creates ||------+ | a subclass of the Model |||<----+ | for each table ||| | | ||| setup_database | | |||--------------------->|| 'create' * ||| ||----------> $subclass ||| | | ||| load_model_subclass | | foreach |||------+ ($subclass) | | $subclass ||||<----+ | require | ||||--------------------------------------->| ||| | | ||| adopt($subclass) | | |||--------------------->|| | | | | | | | |-----+ init | | ||<---+ | | || | new | view_object: e.g. ||---------------------------------------------> Maypole::View::TT | | | | | | | | | | | | | | | | | | | |
HANDLING A REQUEST
BeerDB Model $subclass view_object | | | | handler | | | | o-------->| new | | | |-----> r:BeerDB | | | | | | | | | | | | | | || | | | | ||-----+ parse_location | | | | |||<---+ | | | | || | | | | ||-----+ start_request_hook | | | | |||<---+ | | | | || | | | | ||-----+ get_session | | | | |||<---+ | | | | || | | | | ||-----+ get_user | | | | |||<---+ | | | | || | | | | ||-----+ handler_guts | | | | |||<---+ | | | | ||| class_of($table) | | | | |||------------------------->|| | | | ||| $subclass || | | | |||<-------------------------|| | | | ||| | | | | |||-----+ is_model_applicable| | | | ||||<---+ | | | | ||| | | | | |||-----+ call_authenticate | | | | ||||<---+ | | | | ||| | | | | |||-----+ additional_data | | | | ||||<---+ | | | | ||| process | | | | |||--------------------------------->|| fetch_objects | ||| | ||-----+ | | ||| | |||<---+ | | ||| | || | | ||| | || $action | ||| | ||-----+ | | ||| | |||<---+ | | ||| process | | | | |||------------------------------------------->|| template | ||| | | ||-----+ | ||| | | |||<---+ | ||| | | | | || send_output | | | | ||-----+ | | | | |||<---+ | | | $status | || | | | <------------------|| | | | | | | | | | X | | | | | | | | | | | | | | |
There's more documentation, examples, and information on our mailing lists at the Maypole web site:
the Maypole::Application manpage, the Apache::MVC manpage, the CGI::Maypole manpage.
Maypole is currently maintained by Aaron Trevena.
Simon Cozens, simon#cpan.org
Simon Flack maintained Maypole from 2.05 to 2.09
Sebastian Riedel, sri#oook.de
maintained Maypole from 1.99_01 to 2.04
Sebastian Riedel, Danijel Milicevic, Dave Slack, Jesse Sheidlower, Jody Belka, Marcus Ramberg, Mickael Joanne, Randal Schwartz, Simon Flack, Steve Simms, Veljko Vidovic and all the others who've helped.
You may distribute this code under the same terms as Perl itself.
Maypole - MVC web application framework |