Maypole::Manual::Plugins - the Maypole Plugin API |
setup
Maypole::Manual::Plugins - the Maypole Plugin API
This version written for Maypole 2.10
Plugins occupy the Maypole::Plugin::*
namespace on CPAN. At time of writing,
there are 16 plugin modules available - see
http://search.cpan.org/search?query=Maypole%3A%3APlugin&mode=module
Plugins are loaded into a Maypole application by the Maypole::Application manpage. For instance, to add the HTML::QuickTable manpage support to the BeerDB example application:
package BeerDB; use strict; use warnings;
use Maypole::Application( 'QuickTable' );
Note that the leading Maypole::Plugin::*
is omitted.
For some plugins, that's it. You probably have a bunch of new methods available on your Maypole request objects - see the documentation for the plugin.
For others, you will need to set configuration variables or customise other parts of the application. For instance, to add sessions to your application, you can use the Maypole::Plugin::Session manpage:
package BeerDB; use strict; use warnings;
use Maypole::Application( 'Session' );
That's all, if you're willing to stick with the defaults
(the Apache::Session::File manpage backend, session and lock files in /tmp/sessions
and /tmp/sessionlock
). Otherwise, you need to supply some configuration:
__PACKAGE__->config->session( { class => "Apache::Session::Flex", args => { Store => 'DB_File', Lock => 'Null', Generate => 'MD5', Serialize => 'Storable' } } );
The plugin module is responsible for adding slots to the Maypole::Config manpage, in this
case, the session
accessor.
Plugins are inserted into the @ISA
of the Maypole request object. So method
calls on the request object will first search the plugin classes, before looking
in Maypole. Methods defined in the plugin are therefore directly available on
the request. That also goes for methods inherited by the plugin. I'm not aware
of any plugins that currently inherit from another package, but there's no
reason not to.
Note that if you need simple accessor methods on the request, you can add them by saying
Maypole->mk_accessors( qw/ fee fi fo / );
at the start of your plugin. Under mod_perl, you've just added these accessors
to all Maypole applications on the server, even ones that do not use this
plugin. You could instead make the call inside the setup
method:
$r->mk_accessors( qw/ fee fi fo / );
Now the accessors are only added to applications that use this plugin.
setup
After loading plugins via the Maypole::Application manpage, setting configuration
variables in calls to __PACKAGE__->config->foo( 'bar' )
, and optionally
defining custom request methods, your application should call its setup
method, generally including arguments for the database connection:
__PACKAGE__->setup( $dsn, $user, $pass, @more_args );
All of these arguments will be passed to the setup_database
method of the
model class.
Maypole::setup()
is responsible for loading the model class, calling the
setup_database
method on the model class, and making each table class in the
application inherit from the model. It is therefore recommended that you call
setup
after setting up all your configuration options.
Plugins can intercept the call to setup
to carry out their own
initialisation, as long as they propagate the call up through the hierarchy. A
common idiom for this is:
Maypole::Plugin::Foo; use strict; use warnings;
use NEXT;
sub setup { my $r = shift;
$r->NEXT::DISTINCT::setup(@_);
# Foo initialisation goes here my $option = $r->config->foo_option;
# do something with $option }
the NEXT manpage is a replacement for the built-in SUPER
syntax. SUPER
dispatches a
call to the superclass of the current package - but it determines the
superclass at compile time. At that time, the superclass is something like
main::
. the NEXT manpage does the superclass lookup at runtime, after
the Maypole::Application manpage has inserted the plugin into the request class's
inheritance chain.
The DISTINCT
modifier ensures each plugin's setup
method is only called
once, and protects against diamond inheritance. This may or may not be an issue
in your app - and if you always use the DISTINCT
syntax, it won't be.
Notice that the setup
call is re-dispatched before running the plugin's own
initialisation code. This allows Maypole::setup()
to set up the database,
model, and table classes, before your plugin starts tweaking things.
You can use the setup
method to load modules into the request class
namespace. the Maypole::Plugin::I18N manpage has:
sub setup { my $r = shift; $r->NEXT::DISTINCT::setup(@_); require Locale::Maketext::Simple; import Locale::Maketext::Simple Class => $r, Export => '_loc', Path => $r->config->lexicon; }
Now the application namespace has a _loc
function (exported by
the Locale::Maketext::Simple manpage), (plus lang
and maketext
methods inherited
from the Maypole::Plugin::I18N manpage).
init
Maypole also defines an init
method. It
pulls the name of the view class from the config, loads it, instantiates an
object in the view class, and sets this in the view_object
config slot.
In CGI applications, init
is called at the start of every request.
Under mod_perl, this method will only ever be called once per server child, at
the start of the first request after server startup. If instead, you call this
method in your application module (after the call to setup
), then the code
loaded by this call will be shared by all child servers.
See Hacking the view for a plugin that uses init
.
The configuration object can be retrieved from the Maypole request object
($r->config
) or as a class method on the application (e.g.
BeerDB->config
).
If your plugin needs some custom configuration settings, you can add methods to the config object by saying
Maypole::Config->mk_accessors( qw/ foo bar baz / );
at the start of your plugin. In the application, after the
Maypole::Application
call, these methods will be available on the config
object.
__PACKAGE__->config->model( 'Custom::Model' )
in the application
before calling setup
. You could instead set $r->config->model
before
re-dispatching the setup
call, but this is going to confuse and annoy your
users.
the Maypole::Plugin::FormBuilder manpage (part of the the Maypole::FormBuilder manpage
distribution), in its setup
method, loads a custom pager class into the model
by saying
eval "package $model; use $pager";
Yuk. Note that under mod_perl, you have just forced every application using
$model
to also use $pager
.
Maypole::Plugin::AutoUntaint::setup()
loads an extra method into the model by
saying
no strict 'refs'; *{"$model\::auto_untaint"} = \&Class::DBI::Plugin::AutoUntaint::auto_untaint;
Yuk again. And again, under mod_perl, now every application using $model
has
an auto_untaint
method added to its model.
Same plugin, next line has
eval "package $model; use Class::DBI::Plugin::Type";
Same yuk, same mod_perl caveat.
init
call to override the
vars
method in the view class. First it re-dispatches the init
call, which
will set up either a default view class and object, or those configured in the
application. Then it builds a new view class on-the-fly, and makes this new
class inherit from the Maypole::FormBuilder::View manpage and from the original view
class. Finally it replaces the view
and view_object
in the application's
config object.
sub init { my ( $class ) = @_;
my $config = $class->config;
$class->NEXT::DISTINCT::init;
my $old_view = $class->config->view || die "Please configure a view in $class before calling init()";
my $virtual_view = "$class\::__::View";
eval <<VIEW; package $virtual_view; use base qw( Maypole::FormBuilder::View $old_view ); VIEW
die $@ if $@;
$config->view( $virtual_view );
$class->view_object( $virtual_view->new ); }
There really must be a Better Way.
David Baird, <cpan@riverside-cms.co.uk>
Copyright 2005 David Baird, All Rights Reserved.
This text is free documentation; you can redistribute it and/or modify it under the same terms as the Perl documentation itself.
Maypole::Manual::Plugins - the Maypole Plugin API |