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
43 (Apache::Session::File backend, session and lock files in
44 "/tmp/sessions" and "/tmp/sessionlock"). Otherwise, you need to supply
45 some configuration:
46
47 __PACKAGE__->config->session( { class => "Apache::Session::Flex",
48 args => {
49 Store => 'DB_File',
50 Lock => 'Null',
51 Generate => 'MD5',
52 Serialize => 'Storable'
53 }
54 } );
55
56 The plugin module is responsible for adding slots to Maypole::Config,
57 in this case, the "session" accessor.
58
60 Modifying the Maypole request object
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 After loading plugins via Maypole::Application, setting configuration
84 variables in calls to "__PACKAGE__->config->foo( 'bar' )", and
85 optionally defining custom request methods, your application should
86 call its "setup" method, generally including arguments for the database
87 connection:
88
89 __PACKAGE__->setup( $dsn, $user, $pass, @more_args );
90
91 All of these arguments will be passed to the "setup_database" method of
92 the model class.
93
94 "Maypole::setup()" is responsible for loading the model class, calling
95 the "setup_database" method on the model class, and making each table
96 class in the application inherit from the model. It is therefore
97 recommended that you call "setup" after setting up all your
98 configuration options.
99
100 Plugins can intercept the call to "setup" to carry out their own
101 initialisation, as long as they propagate the call up through the
102 hierarchy. A common idiom for this is:
103
104 Maypole::Plugin::Foo;
105 use strict;
106 use warnings;
107
108 use NEXT;
109
110 sub setup
111 {
112 my $r = shift;
113
114 $r->NEXT::DISTINCT::setup(@_);
115
116 # Foo initialisation goes here
117 my $option = $r->config->foo_option;
118
119 # do something with $option
120 }
121
122 NEXT is a replacement for the built-in "SUPER" syntax. "SUPER"
123 dispatches a call to the superclass of the current package - but it
124 determines the superclass at compile time. At that time, the superclass
125 is something like "main::". NEXT does the superclass lookup at runtime,
126 after Maypole::Application has inserted the plugin into the request
127 class's inheritance chain.
128
129 The "DISTINCT" modifier ensures each plugin's "setup" method is only
130 called once, and protects against diamond inheritance. This may or may
131 not be an issue in your app - and if you always use the "DISTINCT"
132 syntax, it won't be.
133
134 Notice that the "setup" call is re-dispatched before running the
135 plugin's own initialisation code. This allows "Maypole::setup()" to set
136 up the database, model, and table classes, before your plugin starts
137 tweaking things.
138
139 You can use the "setup" method to load modules into the request class
140 namespace. Maypole::Plugin::I18N has:
141
142 sub setup {
143 my $r = shift;
144 $r->NEXT::DISTINCT::setup(@_);
145 require Locale::Maketext::Simple;
146 import Locale::Maketext::Simple
147 Class => $r,
148 Export => '_loc',
149 Path => $r->config->lexicon;
150 }
151
152 Now the application namespace has a "_loc" function (exported by
153 Locale::Maketext::Simple), (plus "lang" and "maketext" methods
154 inherited from Maypole::Plugin::I18N).
155
156 More initialisation with "init"
157
158 Maypole also defines an "init" method. It pulls the name of the view
159 class from the config, loads it, instantiates an object in the view
160 class, and sets this in the "view_object" config slot.
161
162 In CGI applications, "init" is called at the start of every request.
163
164 Under mod_perl, this method will only ever be called once per server
165 child, at the start of the first request after server startup. If
166 instead, you call this method in your application module (after the
167 call to "setup"), then the code loaded by this call will be shared by
168 all child servers.
169
170 See Hacking the view for a plugin that uses "init".
171
172 Adding configuration
173 The configuration object can be retrieved from the Maypole request
174 object ("$r->config") or as a class method on the application (e.g.
175 "BeerDB->config").
176
177 If your plugin needs some custom configuration settings, you can add
178 methods to the config object by saying
179
180 Maypole::Config->mk_accessors( qw/ foo bar baz / );
181
182 at the start of your plugin. In the application, after the
183 "Maypole::Application" call, these methods will be available on the
184 config object.
185
186 Modifying the Maypole model
187 Replacing the model
188 To load a different model, set "__PACKAGE__->config->model(
189 'Custom::Model' )" in the application before calling "setup". You
190 could instead set "$r->config->model" before re-dispatching the
191 "setup" call, but this is going to confuse and annoy your users.
192
193 Hacking the model
194 CAVEAT: the way I do this just seems dirty, so there must be a
195 Better Way.
196
197 Maypole::Plugin::FormBuilder (part of the Maypole::FormBuilder
198 distribution), in its "setup" method, loads a custom pager class
199 into the model by saying
200
201 eval "package $model; use $pager";
202
203 Yuk. Note that under mod_perl, you have just forced every
204 application using $model to also use $pager.
205
206 "Maypole::Plugin::AutoUntaint::setup()" loads an extra method into
207 the model by saying
208
209 no strict 'refs';
210 *{"$model\::auto_untaint"} = \&Class::DBI::Plugin::AutoUntaint::auto_untaint;
211
212 Yuk again. And again, under mod_perl, now every application using
213 $model has an "auto_untaint" method added to its model.
214
215 Same plugin, next line has
216
217 eval "package $model; use Class::DBI::Plugin::Type";
218
219 Same yuk, same mod_perl caveat.
220
221 Modifying the Maypole view
222 Replacing the view
223 Again, just specify a different view in the application
224 configuration.
225
226 Hacking the view
227 Maypole::Plugin::FormBuilder intercepts the "init" call to override
228 the "vars" method in the view class. First it re-dispatches the
229 "init" call, which will set up either a default view class and
230 object, or those configured in the application. Then it builds a
231 new view class on-the-fly, and makes this new class inherit from
232 Maypole::FormBuilder::View and from the original view class.
233 Finally it replaces the "view" and "view_object" in the
234 application's config object.
235
236 sub init
237 {
238 my ( $class ) = @_;
239
240 my $config = $class->config;
241
242 $class->NEXT::DISTINCT::init;
243
244 my $old_view = $class->config->view ||
245 die "Please configure a view in $class before calling init()";
246
247 my $virtual_view = "$class\::__::View";
248
249 eval <<VIEW;
250 package $virtual_view;
251 use base qw( Maypole::FormBuilder::View $old_view );
252 VIEW
253
254 die $@ if $@;
255
256 $config->view( $virtual_view );
257
258 $class->view_object( $virtual_view->new );
259 }
260
261 There really must be a Better Way.
262
264 David Baird, "<cpan@riverside-cms.co.uk>"
265
267 Copyright 2005 David Baird, All Rights Reserved.
268
269 This text is free documentation; you can redistribute it and/or modify
270 it under the same terms as the Perl documentation itself.
271
272
273
274perl v5.32.0 2020-07-28 Maypole::Manual::Plugins(3)