1Maypole::Manual::PluginUss(e3r)Contributed Perl DocumentMaatyipoonle::Manual::Plugins(3)
2
3
4

NAME

6       Maypole::Manual::Plugins - the Maypole Plugin API
7

VERSION

9       This version written for Maypole 2.10
10

LOADING PLUGINS

12       Plugins occupy the "Maypole::Plugin::*" namespace on CPAN. At time of
13       writing, there are 16 plugin modules available - see
14       http://search.cpan.org/search?query=Maypole%3A%3APlugin&mode=module
15
16       Plugins are loaded into a Maypole application by Maypole::Application.
17       For instance, to add HTML::QuickTable support to the BeerDB example
18       application:
19
20          package BeerDB;
21          use strict;
22          use warnings;
23
24          use Maypole::Application( 'QuickTable' );
25
26       Note that the leading "Maypole::Plugin::*" is omitted.
27
28       For some plugins, that's it. You probably have a bunch of new methods
29       available on your Maypole request objects - see the documentation for
30       the plugin.
31
32       For others, you will need to set configuration variables or customise
33       other parts of the application. For instance, to add sessions to your
34       application, you can use Maypole::Plugin::Session:
35
36          package BeerDB;
37          use strict;
38          use warnings;
39
40          use Maypole::Application( 'Session' );
41
42       That's all, if you're willing to stick with the defaults (Apache::Ses‐
43       sion::File backend, session and lock files in "/tmp/sessions" and
44       "/tmp/sessionlock"). Otherwise, you need to supply some configuration:
45
46          __PACKAGE__->config->session( { class => "Apache::Session::Flex",
47                                          args  => {
48                                              Store     => 'DB_File',
49                                              Lock      => 'Null',
50                                              Generate  => 'MD5',
51                                              Serialize => 'Storable'
52                                              }
53                                          } );
54
55       The plugin module is responsible for adding slots to Maypole::Config,
56       in this case, the "session" accessor.
57

WRITING PLUGINS

59       Modifying the Maypole request object
60
61       Plugins are inserted into the @ISA of the Maypole request object. So
62       method calls on the request object will first search the plugin
63       classes, before looking in Maypole. Methods defined in the plugin are
64       therefore directly available on the request. That also goes for methods
65       inherited by the plugin. I'm not aware of any plugins that currently
66       inherit from another package, but there's no reason not to.
67
68       Note that if you need simple accessor methods on the request, you can
69       add them by saying
70
71          Maypole->mk_accessors( qw/ fee fi fo / );
72
73       at the start of your plugin. Under mod_perl, you've just added these
74       accessors to all Maypole applications on the server, even ones that do
75       not use this plugin. You could instead make the call inside the "setup"
76       method:
77
78          $r->mk_accessors( qw/ fee fi fo / );
79
80       Now the accessors are only added to applications that use this plugin.
81
82       Initialisation with "setup"
83
84       After loading plugins via Maypole::Application, setting configuration
85       variables in calls to "__PACKAGE__->config->foo( 'bar' )", and option‐
86       ally defining custom request methods, your application should call its
87       "setup" method, generally including arguments for the database connec‐
88       tion:
89
90          __PACKAGE__->setup( $dsn, $user, $pass, @more_args );
91
92       All of these arguments will be passed to the "setup_database" method of
93       the model class.
94
95       "Maypole::setup()" is responsible for loading the model class, calling
96       the "setup_database" method on the model class, and making each table
97       class in the application inherit from the model. It is therefore recom‐
98       mended that you call "setup" after setting up all your configuration
99       options.
100
101       Plugins can intercept the call to "setup" to carry out their own ini‐
102       tialisation, as long as they propagate the call up through the hierar‐
103       chy. A common idiom for this is:
104
105          Maypole::Plugin::Foo;
106          use strict;
107          use warnings;
108
109          use NEXT;
110
111          sub setup
112          {
113              my $r = shift;
114
115              $r->NEXT::DISTINCT::setup(@_);
116
117              # Foo initialisation goes here
118              my $option = $r->config->foo_option;
119
120              # do something with $option
121          }
122
123       NEXT is a replacement for the built-in "SUPER" syntax. "SUPER" dis‐
124       patches a call to the superclass of the current package - but it deter‐
125       mines the superclass at compile time. At that time, the superclass is
126       something like "main::". NEXT does the superclass lookup at runtime,
127       after Maypole::Application has inserted the plugin into the request
128       class's inheritance chain.
129
130       The "DISTINCT" modifier ensures each plugin's "setup" method is only
131       called once, and protects against diamond inheritance. This may or may
132       not be an issue in your app - and if you always use the "DISTINCT" syn‐
133       tax, it won't be.
134
135       Notice that the "setup" call is re-dispatched before running the plug‐
136       in's own initialisation code. This allows "Maypole::setup()" to set up
137       the database, model, and table classes, before your plugin starts
138       tweaking things.
139
140       You can use the "setup" method to load modules into the request class
141       namespace. Maypole::Plugin::I18N has:
142
143          sub setup {
144              my $r = shift;
145              $r->NEXT::DISTINCT::setup(@_);
146              require Locale::Maketext::Simple;
147              import Locale::Maketext::Simple
148                Class  => $r,
149                Export => '_loc',
150                Path   => $r->config->lexicon;
151       }
152
153       Now the application namespace has a "_loc" function (exported by
154       Locale::Maketext::Simple), (plus "lang" and "maketext" methods inher‐
155       ited from Maypole::Plugin::I18N).
156
157       More initialisation with "init"
158
159       Maypole also defines an "init" method. It pulls the name of the view
160       class from the config, loads it, instantiates an object in the view
161       class, and sets this in the "view_object" config slot.
162
163       In CGI applications, "init" is called at the start of every request.
164
165       Under mod_perl, this method will only ever be called once per server
166       child, at the start of the first request after server startup. If
167       instead, you call this method in your application module (after the
168       call to "setup"), then the code loaded by this call will be shared by
169       all child servers.
170
171       See Hacking the view for a plugin that uses "init".
172
173       Adding configuration
174
175       The configuration object can be retrieved from the Maypole request
176       object ("$r->config") or as a class method on the application (e.g.
177       "BeerDB->config").
178
179       If your plugin needs some custom configuration settings, you can add
180       methods to the config object by saying
181
182          Maypole::Config->mk_accessors( qw/ foo bar baz / );
183
184       at the start of your plugin. In the application, after the "May‐
185       pole::Application" call, these methods will be available on the config
186       object.
187
188       Modifying the Maypole model
189
190       Replacing the model
191           To load a different model, set "__PACKAGE__->config->model( 'Cus‐
192           tom::Model' )" in the application before calling "setup". You could
193           instead set "$r->config->model" before re-dispatching the "setup"
194           call, but this is going to confuse and annoy your users.
195
196       Hacking the model
197           CAVEAT: the way I do this just seems dirty, so there must be a Bet‐
198           ter Way.
199
200           Maypole::Plugin::FormBuilder (part of the Maypole::FormBuilder dis‐
201           tribution), in its "setup" method, loads a custom pager class into
202           the model by saying
203
204              eval "package $model; use $pager";
205
206           Yuk. Note that under mod_perl, you have just forced every applica‐
207           tion using $model to also use $pager.
208
209           "Maypole::Plugin::AutoUntaint::setup()" loads an extra method into
210           the model by saying
211
212              no strict 'refs';
213              *{"$model\::auto_untaint"} = \&Class::DBI::Plugin::AutoUntaint::auto_untaint;
214
215           Yuk again. And again, under mod_perl, now every application using
216           $model has an "auto_untaint" method added to its model.
217
218           Same plugin, next line has
219
220              eval "package $model; use Class::DBI::Plugin::Type";
221
222           Same yuk, same mod_perl caveat.
223
224       Modifying the Maypole view
225
226       Replacing the view
227           Again, just specify a different view in the application configura‐
228           tion.
229
230       Hacking the view
231           Maypole::Plugin::FormBuilder intercepts the "init" call to override
232           the "vars" method in the view class. First it re-dispatches the
233           "init" call, which will set up either a default view class and
234           object, or those configured in the application. Then it builds a
235           new view class on-the-fly, and makes this new class inherit from
236           Maypole::FormBuilder::View and from the original view class.
237           Finally it replaces the "view" and "view_object" in the applica‐
238           tion's config object.
239
240              sub init
241              {
242                  my ( $class ) = @_;
243
244                  my $config = $class->config;
245
246                  $class->NEXT::DISTINCT::init;
247
248                  my $old_view = $class->config->view ⎪⎪
249                      die "Please configure a view in $class before calling init()";
250
251                  my $virtual_view = "$class\::__::View";
252
253                  eval <<VIEW;
254              package $virtual_view;
255              use base qw( Maypole::FormBuilder::View $old_view );
256              VIEW
257
258                  die $@ if $@;
259
260                  $config->view( $virtual_view );
261
262                  $class->view_object( $virtual_view->new );
263              }
264
265           There really must be a Better Way.
266

AUTHOR

268       David Baird, "<cpan@riverside-cms.co.uk>"
269
271       Copyright 2005 David Baird, All Rights Reserved.
272
273       This text is free documentation; you can redistribute it and/or modify
274       it under the same terms as the Perl documentation itself.
275
276
277
278perl v5.8.8                       2005-11-23       Maypole::Manual::Plugins(3)
Impressum