Maypole(3)

πŸ“¦
version 2.13 Β· 2 versions
, in fedora 43

πŸ’– Maypole πŸ’– β€” the Maypole(3) page, bestie edition

User Contributed Perl Documentation · Maypole(3) · part 1 of 3, stay tuned 🫢


✨ NAME ✨

Maypole β€” MVC web application framework 🌸


πŸŽ€ SYNOPSIS πŸŽ€

okay so the canonical example they use all over the Maypole docs is the beer database. iconic. here it is, verbatim, no cap:

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 πŸ¦‹

So this page documents the Maypole request object. If you want the actual detailed guide to using Maypole, that lives in Maypole::Manual. πŸ‘‘

Maypole is a Perl web application framework β€” think Java's struts but make it Perl. It's basically completely abstracted, which means it genuinely has no idea how to talk to the outside world. It's giving "main character who refuses to leave the house". πŸ’…

To actually use it, you need to build a driver package that represents your entire application. That's the "BeerDB" package they use as the example all through the manual.

That package first needs to use Maypole::Application, which makes your package inherit from whatever platform driver fits β€” like "Apache::MVC" or "CGI::Maypole". Then the driver calls "setup". That 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 you can change that by altering configuration (and you gotta do it before calling setup, bestie, order matters). 🌈


πŸ“š DOCUMENTATION AND SUPPORT πŸ“š

heads up: some details in some of these resources may be out of date. lowkey tragic but we move. 😭

πŸͺ HOOKABLE METHODS πŸͺ

As a framework, Maypole gives you a bunch of hooks β€” methods that are literally meant to be overridden by you. Some of them come with genuinely useful default behaviour, others do absolutely nothing by default (which is fine, it's a vibe). The 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 turn debugging on/off. ✨

You can also set the "debug" flag via Maypole::Application.

Some packages respond to higher debug levels β€” try bumping it up to 2 or 3. πŸ”₯

config

Returns the Maypole::Config object. simple as that.

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 set up the model. The %attr hash holds the options and arguments used to set up the model. See the particular model's documentation for those. But here's the most common 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, go look at 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 makes sure any code in custom model classes gets loaded, so you don't need to load them in the driver. one less thing, we love that. πŸ’…

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 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 maybe, during development, if you don't want to load up custom classes, you can override this method and load them manually instead.

init

Loads the view class and instantiates the view object.

You should not call this directly, but you may wish to override it 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 then 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 `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
not me fully qualifying the Maypole URL… don't. πŸ™ˆ

handler_guts

This is the main request handling method. It 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 the appropriate logfile.

You can also over-ride this in your Maypole driver, if you'd rather 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 lets you over-ride that setting per action. πŸŽ€

get_request

You should only need to define this method if you're 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 invoking "parse_path" and "parse_args".

You should only need to define this method if you're 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 to "OK" before this hook runs. Your implementation can change the status code, or leave it alone. whatever you want bestie ✨

After this hook has run, Maypole will check the value of "status". For any value other than "OK", Maypole returns the "status" immediately.


and yeah, this is so useful for filtering out requests for static files β€” think images and all that β€” because those should NOT be getting processed by Maypole or by the templating engine, bestie:

sub start_request_hook
{
    my ($r) = @_;

    $r->status(DECLINED) if $r->path =~ /\.jpg$/;
}

and here's the tea: multiple plugins, and the driver, can all define this hook β€” Maypole will call every single one of them. so you should check for any non-OK status value, and probably not change it:

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

ok so heads up bestie β€” this method is deprecated as of version 2.11 😭

If you've overridden it, please override is_model_applicable instead, and also switch the return type from a Maypole:Constant over to a true/false value.

It returns a Maypole:Constant to say whether the request is valid. ✨

is_model_applicable

Returns true or false, indicating whether the request is valid.

The default implementation checks that $r->table is publicly accessible, and that the model class is configured to handle $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 (no thoughts, head 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

First it checks whether the relevant model class can authenticate the user β€” and if it can't, it falls back to the default authenticate method of your Maypole application.

authenticate

Returns a Maypole::Constant telling you whether the user is authenticated for the Maypole request.

The default implementation returns OK.

call_exception

This one gets called to catch exceptions β€” first after authenticate, then after the model class is processed, and finally to check for exceptions coming out of the view class.

It first checks whether the relevant model class can handle exceptions, and if not, it falls back to the default exception method of your Maypole application.

exception

This method is called if any exceptions get raised during authentication or model/view processing. It should accept the exception as a parameter, and return a Maypole::Constant indicating whether the request should keep being processed.

additional_data

Called before the model processes the request β€” it's your lil moment to do some processing for each request, like 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 and table properties. It calls preprocess_path before parsing the path and setting the properties.

preprocess_path

Sometimes you don't wanna rewrite or over-ride parse_path, but you do wanna rewrite urls or pull data out of them before they get parsed β€” that's literally what the preprocess_path/location methods are for. They let you munge paths and urls before maypole maps them onto 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 it gets passed the request object.

You can set action, args or table in this method, and then parse_path will leave those values in place, or populate them based on the current value of the path attribute if they're not present. πŸŽ€

preprocess_location

Called at the start of parse_location, after the headers are in. It lets you rewrite the url maypole uses, 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 for you to use in links, form actions, etc. Wanna implement your own path scheme? Just override this method and parse_path, that's it, slay.

%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 gets expanded into extra path elements, while a hashref gets translated into a query string.

make_uri( @segments )

Makes 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 parameters into a hash of params.

You should only need to define this method if you're writing a new Maypole backend.

get_template_root

Implementation-specific path to template root.

You should only need to define this method if you're writing a new Maypole backend. Otherwise, go look at 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's 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 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 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 you use it to set the object, it overwrites 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, plus 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

An 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

Where the parameters come from may vary depending on your Maypole backend, but they're usually populated from the request query string and POST data.

Maypole supplies several approaches for accessing the request parameters. But note this: 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 multiple 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 you give it.

It accepts either a single argument β€” 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. It can be used to prevent or detect repeat submissions. πŸ¦‹

πŸ¦‹ SEQUENCE DIAGRAMS πŸ¦‹

Okay bestie, if you want the full tea on how a request flows through Maypole, you gotta read Maypole::Manual::Workflow β€” it's the detailed discussion of the sequence of calls during processing of a request. But here's the quick summary, the tl;dr, the vibe check. It's giving flowchart realness, no cap. πŸ’…

           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                            |       |         |
                   |                                      |       |         |
                   |                                      |       |         |
                   |                                      |       |         |
                   |                                      |       |         |

And that's the whole pipeline, bestie. Slay. πŸ’–


🌈 SEE ALSO 🌈

There's so much more documentation, examples, and info on our mailing lists at the Maypole web site, bestie:

<http://maypole.perl.org/>

Also, you should totally check out these modules: Maypole::Application, Apache::MVC, CGI::Maypole. They're like the extended universe. πŸ¦‹


πŸ‘‘ AUTHOR πŸ‘‘

Maypole is currently maintained by Aaron Trevena. He's the one holding the crown right now. πŸ’–


πŸ’œ AUTHOR EMERITUS πŸ’œ

Simon Cozens, "simon#cpan.org" β€” iconic.

Simon Flack maintained Maypole from 2.05 to 2.09. Respect. ✨

Sebastian Riedel, "sri#oook.de" maintained Maypole from 1.99_01 to 2.04. Legend behavior. 🌸


πŸŽ€ THANKS TO πŸŽ€

Huge shoutout 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. Y'all ate. πŸ’…


πŸ“œ LICENSE πŸ“œ

You may distribute this code under the same terms as Perl itself. So like, do your thing, just keep it Perl-licensed. Periodt. πŸ’–


This page is from perl v5.42.0, dated 2025-07-25, and it's Maypole(3). Byeee! 🫢

πŸ“¦ where this page comes from