NAME
Maypole - MVC web application framework
SYNOPSIS
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;
DESCRIPTION
This documents the Maypole request object. See the Maypole::Manual, 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 Maypole::Application 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 Class::DBI to map a database to classes, but this can be changed by altering configuration (before calling setup.)
DOCUMENTATION AND SUPPORT
Note that some details in some of these resources may be out of date.
- The Maypole Manual
The primary documentation is the Maypole manual. This lives in the
Maypole::Manual
pod documents included with the distribution.- Embedded POD
Individual packages within the distribution contain (more or less) detailed reference documentation for their API.
- Mailing lists
There are two mailing lists - maypole-devel and maypole-users - see http://maypole.perl.org/?MailingList
- The Maypole Wiki
The Maypole wiki provides a useful store of extra documentation - http://maypole.perl.org
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.
- Web applications with Maypole
A tutorial written by Simon Cozens for YAPC::EU 2005 - http://www.aarontrevena.co.uk/opensource/maypole/maypole-tutorial.pdf [228KB].
- A Database-Driven Web Application in 18 Lines of Code
By Paul Barry, published in Linux Journal, March 2005.
http://www.linuxjournal.com/article/7937
"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.
- Build Web apps with Maypole
By Simon Cozens, on IBM's DeveloperWorks website, May 2004.
http://www-128.ibm.com/developerworks/linux/library/l-maypole/
- Rapid Web Application Deployment with Maypole
By Simon Cozens, on O'Reilly's Perl website, April 2004.
http://www.perl.com/pub/a/2004/04/15/maypole.html
- Authentication
Some notes written by Simon Cozens. A little bit out of date, but still very useful: http://www.aarontrevena.co.uk/opensource/maypole/authentication.html
- CheatSheet
There's a refcard for the Maypole (and Class::DBI) APIs on the wiki - http://maypole.perl.org/?CheatSheet. Probably a little out of date now - it's a wiki, so feel free to fix any errors!
- Plugins and add-ons
There are a large and growing number of plugins and other add-on modules available on CPAN - http://search.cpan.org/search?query=maypole&mode=module
- del.icio.us
You can find a range of useful Maypole links, particularly to several thoughtful blog entries, starting here: http://del.icio.us/search/?all=maypole
- CPAN ratings
There are a couple of short reviews here: http://cpanratings.perl.org/dist/Maypole
HOOKABLE METHODS
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
CLASS METHODS
- debug
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 Maypole::Application.Some packages respond to higher debug levels, try increasing it to 2 or 3.
- config
Returns the Maypole::Config object
- setup
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 Maypole::Manual::Plugins.
- setup_model
Called by
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)
This method is called from
setup_model()
. It attempts to load the$subclass
package, if one exists. So if you make a customizedBeerDB::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.
- init
Loads the view class and instantiates the view object.
You should not call this directly, but you may wish to override this to add application-specific initialisation - see Maypole::Manual::Plugins.
- new
Constructs a very minimal new Maypole request object.
- view_object
Get/set the Maypole::View object
INSTANCE METHODS
Workflow
- handler
This method sets up the class if it's not done yet, sets some defaults and leaves the dirty work to
handler_guts
.- component
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 argument to the method
- handler_guts
This is the main request handling method and calls various methods to handle the request/response and defines the workflow within Maypole.
- warn
$r->warn('its all gone pete tong');
Warn must be implemented by the backend, i.e. Apache::MVC and warn to stderr or appropriate logfile.
You can also over-ride this in your Maypole driver, should you want to use something like Log::Log4perl instead.
- build_form_elements
$r->build_form_elements(0);
Specify (in an action) whether to build HTML form elements and populate the cgi element of classmetadata in the view.
You can set this globally using the accessor of the same name in Maypole::Config, this method allows you to over-ride that setting per action.
- get_request
You should only need to define this method if you are writing a new Maypole backend. It should return something that looks like an Apache or CGI request object, it defaults to blank.
- parse_location
Turns the backend request (e.g. Apache::MVC, Maypole, CGI) into a Maypole request. It does this by setting the
path
, and invokingparse_path
andparse_args
.You should only need to define this method if you are writing a new Maypole backend.
- start_request_hook
This is called immediately after setting up the basic request. The default method does nothing.
The value of
$r->status
is set toOK
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 thanOK
, Maypole returns thestatus
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
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/; }
- is_applicable
This method is deprecated as of version 2.11. If you have overridden it, please override
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.
- is_model_applicable
Returns true or false 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
.- get_session
Called immediately after
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_user
Called immediately after
get_session
.This method should return a user, which will be stored in the request's
user
attribute.The default method is empty.
- call_authenticate
This method first checks if the relevant model class can authenticate the user, or falls back to the default authenticate method of your Maypole application.
- authenticate
Returns a Maypole::Constant to indicate whether the user is authenticated for the Maypole request.
The default implementation returns
OK
- call_exception
This model is called to catch exceptions, first after authenticate, then after processing the model class, and finally to check for exceptions from the view class.
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.
- exception
This method is called if any exceptions are raised during the authentication or model/view processing. It should accept the exception as a parameter and return a Maypole::Constant to indicate whether the request should continue to be processed.
- additional_data
Called before the model processes the request, this method gives you a chance to do some processing for each request, for example, manipulating
template_args
.- send_output
Sends the output and additional headers to the user.
Path processing and manipulation
- path
Returns the request path
- parse_path
Parses the request path and sets the
args
,action
andtable
properties. Callspreprocess_path
before parsing path and setting properties.- preprocess_path
Sometimes when you don't want to rewrite or over-ride parse_path but want to rewrite urls or extract data from them before it is parsed, the preprocess_path/location methods allow you to munge paths and urls before maypole maps them to actions, classes, etc.
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 based on the current value of the path attribute if they are not present.
- preprocess_location
This method is called at the start of parse_location, after the headers in, and allows you to rewrite the url used by maypole, or dynamically set configuration like the base_uri based on the hostname or path.
- make_path( %args or \%args or @args )
This is the counterpart to
parse_path
. It generates a path to use in links, form actions etc. To implement your own path scheme, just override this method andparse_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 toadditional
.$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.- make_uri( @segments )
Make a URI object given table, action etc. Automatically adds the
uri_base
.If the final element in
@segments
is a hash ref,make_uri
will render it as a query string.- parse_args
Turns post data and query string paramaters into a hash of
params
.You should only need to define this method if you are writing a new Maypole backend.
- get_template_root
Implementation-specific path to template root.
You should only need to define this method if you are writing a new Maypole backend. Otherwise, see "template_root" in Maypole::Config
Request properties
- model_class
Returns the perl package name that will serve as the model for the request. It corresponds to the request
table
attribute.- objects
Get/set a list of model objects. The objects will be accessible in the view templates.
If the first item in
$self->args
can beretrieve()
d by the model class, it will be removed fromargs
and the retrieved object will be added to theobjects
list. See Maypole::Model for more information.- object
Alias to get/set the first/only model object. The object will be accessible in the view templates.
When used to set the object, will overwrite the request objects with a single object.
- template_args
$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.
- stash
A place to put custom application data. Not used by Maypole itself.
- template
Get/set the template to be used by the view. By default, it returns
$self->action
- error
Get/set a request error
- output
Get/set the response output. This is usually populated by the view class. You can skip view processing by setting the
output
.- table
The table part of the Maypole request path
- action
The action part of the Maypole request path
- args
A list of remaining parts of the request path after table and action have been removed
- headers_in
A Maypole::Headers object containing HTTP headers for the request
- headers_out
A HTTP::Headers object that contains HTTP headers for the output
- document_encoding
Get/set the output encoding. Default: utf-8.
- content_type
Get/set the output content type. Default: text/html
- get_protocol
Returns the protocol the request was made with, i.e. https
Request parameters
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
- param
An accessor (get or set) for request parameters. It behaves similarly to CGI::param() for accessing CGI parameters, i.e.
$r->param # returns list of keys $r->param($key) # returns value for $key $r->param($key => $value) # returns old value, sets to new value
- params
Returns a hashref of request parameters.
Note: Where muliple values of a parameter were supplied, the
params
value will be an array reference.- query
Alias for
params
.
Utility methods
- redirect_request
Sets output headers to redirect based on the arguments provided
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.
- make_random_id
returns a unique id for this request can be used to prevent or detect repeat submissions.
SEQUENCE DIAGRAMS
See Maypole::Manual::Workflow 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 | | | | | | | | | | | | | | |
SEE ALSO
There's more documentation, examples, and information on our mailing lists at the Maypole web site:
Maypole::Application, Apache::MVC, CGI::Maypole.
AUTHOR
Maypole is currently maintained by Aaron Trevena.
AUTHOR EMERITUS
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
THANKS TO
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.
LICENSE
You may distribute this code under the same terms as Perl itself.