1Maypole::Manual::PluginUss(e3r)Contributed Perl DocumentMaatyipoonle::Manual::Plugins(3)
2
3
4
6 Maypole::Manual::Plugins - the Maypole Plugin API
7
9 This version written for Maypole 2.10
10
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
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
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)