The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


Maypole::Plugin::FormBuilder - CGI::FormBuilder for Maypole


    package BeerFB;
    use warnings;
    use strict;
    use Class::DBI::Loader::Relationship;
    use Apache::Session::File();
    use Maypole::Application qw( FormBuilder QuickTable Session );
    BeerFB->config->model( 'Maypole::FormBuilder::Model' );
    BeerFB->config->session( { args => { Directory     => "/tmp/sessions/beerfb",
                                         LockDirectory => "/tmp/sessions/beerfb",
                               } );
    # note: the latest development version is broken
    #BeerFB->config->pager_class( 'Class::DBI::Plugin::Pager' );
    # global FormBuilder defaults
    BeerFB->config->form_builder_defaults( { method => 'post' } );
    # standard config
    BeerFB->config->{template_root}  = '/home/beerfb/www/www/htdocs';
    BeerFB->config->{uri_base}       = '/';
    BeerFB->config->{rows_per_page}  = 10;
    BeerFB->config->{display_tables} = [ qw( beer brewery pub style ) ];
    BeerFB->config->{application_name} = 'The BeerFB Database';

    BeerFB->setup( 'dbi:mysql:BeerDB', 'username', 'password' );
    BeerFB->config->loader->relationship( $_ ) for (
        'a brewery produces beers',
        'a style defines beers',
        'a pub has beers on handpumps',
    # ----- set up validation and other form defaults -----
    # has_a fields (style, brewery) are automatically required in CDBI::FormBuilder
    BeerFB::Beer->form_builder_defaults( { validate => { abv     => 'NUM',
                                                        style   => 'INT',
                                                        brewery => 'INT',
                                                        price   => 'NUM',
                                                        url     => 'VALUE',
                                                        notes   => 'VALUE',
                                                        name    => 'VALUE',
                                                        score   => [ qw( 1 2 3 4 5 ) ],
                                        options => { score => [ qw( 1 2 3 4 5 ) ],
                                        required => [ qw( name ) ],
                                        } );
    BeerFB::Brewery->form_builder_defaults( { validate => { name  => 'VALUE',
                                                            notes => 'VALUE',
                                                            url   => 'VALUE',
                                               required => [ qw( name ) ],
                                            } );
    BeerFB::Pub->form_builder_defaults( { validate => { name  => 'VALUE',
                                                        notes => 'VALUE',
                                                        url   => 'VALUE',
                                        required => [ qw( name ) ],
                                        } );
    BeerFB::Style->form_builder_defaults( { validate => { name  => 'VALUE',
                                                          notes => 'VALUE',
                                            required => [ qw( name ) ],
                                            } );    
    # -------------------------------------------------------------------------
    # --- in a Mason template (adapt syntax for your preferred template system)
    <% $request->as_form->render %>


Generate CGI::FormBuilder forms from Maypole objects, using Class::DBI::FormBuilder.

Includes an alternative Maypole model, which should be set up in your config:

    BeerFB->config->model( 'Maypole::FormBuilder::Model' );

Note that a new vars method is installed, which removes the classmetadata functionality. It just seemed like an extra level of API to learn, and we don't need the Class::DBI::AsForm stuff.


The demo application (shown in the synopsis) uses sessions to keep track of the user's preferred list view mode (editlist or plain list). The demo should work without sessions, but it will not show the editable list view.



Called automatically by Maypole during compilation.

Among other things, this method sets an empty hashref into each model's form_builder_defaults class data slot. This is done to prevent models inheriting each other's settings, but has the side-effect of clobbering anything set up during model compilation. So you can't populate form_builder_defaults in the subclass itself. Instead, set up each subclass's form_builder_defaults in the application driver, after the setup() call.


This returns a CGI::FormBuilder object. Accepts any parameters that CGI::FormBuilder->new() accepts.

Defaults are as in CGI::FormBuilder, you can alter them using the form_builder_default Maypole config slot.

There are a few additional Maypole-specific options:


The form generated depends on the mode. Defaults to the current action.

As a special case, you can pass this as a positional argument, instead of a named argument, i.e. these mean the same:

    my $form = $request->as_form( $mode );
    my $form = $request->as_form( mode => $mode );
    my $form = $request->as_form( { mode => $mode } );

as do these:

    my %args = ( whatever => whatever );
    my $form = $request->as_form( $mode, %args );
    my $form = $request->as_form( $mode, \%args );
    $args{mode} = $mode;
    my $form = $request->as_form( %args );
    my $form = $request->as_form( \%args );

Pass the mode argument to generate a different form from that specified by the current value of $r->action. For instance, to generate a search form to include on a list template, say

    print $r->as_form( mode => 'do_search' )->render;

You can add more modes by defining setup_form_mode methods in your model classes. See Maypole::FormBuilder::Model and Maypole::FormBuilder::Model::Base.


Normally, as_form builds a form based on the first object in $r->objects, or based on the current model ($r->model_class) if there are no objects. To use a different object or model, pass it in the entity argument:

    my $form = $r->as_form( entity => $class_or_object );

Wrapper for Class::DBI::FormBuilder::as_multiform().


Returns a search form, via Class::DBI::FormBuilder::search_form(). The mode defaults to do_search.

as_forms( %args )
    %args = ( objects => $object|$arrayref_of_objects,   # defaults to $r->objects

Generates multiple forms and returns them as a list.

You may want to reduce selectnum to generate popup menus rather than multiple radiobuttons or checkboxes ( see the list template in this distribution).

render_form_as_row( $form )

Returns a form marked up as a single row for a table.

This will probably get converted to a template some time.

Yes, it's bad XHTML - suggestions about how to do this legally would be good.


Defaults that apply to all forms.

    # make all forms POST their data
    BeerFB->config->form_builder_defaults->{method} = 'post';

A convenience method to allow the default templates to work without a session. With no session configured, always returns list. With a session, returns/sets the list view mode, which can be list or editlist.

Configuring custom actions

Custom actions may require custom configuration of the form object (in addition to providing an Exported method in your model class to support the new action). Write a setup_form_mode method in your model class. See Maypole::Plugin::FormBuilder::Model::Base.


Maypole::FormBuilder::Model and Maypole::FormBuilder::Model::Base.


David Baird, <>


The way the pager is loaded (in setup()) means that every Maypole app in the current interpreter that uses the same model, will be using the same pager. I've no immediate plans to fix this unless someone asks me.

Please report any bugs or feature requests to, or through the web interface at I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.


Copyright 2005 David Baird, All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.