1Maypole::Manual::InheriUtsaenrceC(o3n)tributed Perl DocuMmaeynptoaltei:o:nManual::Inheritance(3)
2
3
4
6 Maypole::Manual::Inheritance - structure of a Maypole application
7
9 Discusses the inheritance structure of a basic and a more advanced May‐
10 pole application.
11
13 inheritance
14 +
15 ⎪
16 +- -+
17 ⎪
18 +
19
20 notes
21 target *-------- note about the target
22
23 association
24 source ------> target
25
27 A minimal Maypole application (such as the Beer database example from
28 the Maypole synopsis) consists of a custom driver class (BeerDB.pm), a
29 set of auto-generated model classes, and a view class:
30
31 THE DRIVER
32 +------- init() is a factory method,
33 1 Maypole ⎪ it sets up the view
34 Maypole::Config <----- config(); ⎪ classes
35 model(); init(); *-------+ THE VIEW
36 ⎪ view_object(); -------+
37 ⎪ +--------------* setup(); ⎪ Maypole::View::Base
38 ⎪ ⎪ + ⎪ +
39 ⎪ ⎪ ⎪ ⎪ 1 ⎪
40 ⎪ ⎪ PLUGINS Apache::MVC *-----+ +-----> Maypole::View::TT
41 ⎪ ⎪ + + ⎪ (or another view class)
42 ⎪ ⎪ ⎪ ⎪ ⎪
43 ⎪ ⎪ +-----+-----+ ⎪
44 ⎪ ⎪ ⎪ ⎪
45 ⎪ ⎪ BeerDB +----- or CGI::Maypole
46 ⎪ ⎪ or MasonX:::Maypole
47 ⎪ ⎪
48 ⎪ setup() is a factory method,
49 ⎪ it sets up the model
50 ⎪ classes
51 ⎪
52 ⎪ THE MODEL
53 ⎪
54 ⎪ Maypole::Model::Base Class::DBI
55 ⎪ + + +
56 ⎪ ⎪ ⎪ ⎪
57 +-------> Maypole::Model::CDBI Class::DBI::<db_driver>
58 + +
59 ⎪ ⎪
60 +------------+--------+-------+---------+
61 ⎪ ⎪ ⎪ ⎪ ⎪
62 BeerDB::Pub ⎪ BeerDB::Beer ⎪ BeerDB::Brewery
63 beers(); ⎪ pubs(); ⎪ beers();
64 ⎪ brewery(); ⎪
65 ⎪ style(); ⎪
66 BeerDB::Handpump ⎪
67 pub(); BeerDB::Style
68 beer(); beers();
69
70 What about Maypole::Application - loading plugins
71
72 The main job of Maypole::Application is to insert the plugins into the
73 hierarchy. It is also the responsibility of Maypole::Application to
74 decide which frontend to use. It builds the list of plugins, then
75 pushes them onto the driver's @ISA, then pushes the frontend onto the
76 end of the driver's @ISA. So method lookup first searches all the
77 plugins, before searching the frontend and finally Maypole itself.
78
79 From Maypole 2.11, Maypole::Application makes no appearance in the
80 inheritance structure of a Maypole application. (In prior versions,
81 Maypole::Application would make itself inherit the plugins, and then
82 insert itself in the hierarchy, but this was unnecessary).
83
84 Who builds the model?
85
86 First, remember we are talking about the standard, unmodified Maypole
87 here. It is possible, and common, to override some or all of this stage
88 and build a customised model. See below - An advanced Maypole applica‐
89 tion - for one approach. Also, see Maypole's "setup_model()" method.
90
91 The standard model is built in 3 stages.
92
93 First, "Maypole::setup_model" calls "setup_database" on the Maypole
94 model class, in this case Maypole::Model::CDBI. "setup_database" then
95 uses Class::DBI::Loader to autogenerate individual Class::DBI classes
96 for each of the tables in the database ("BeerDB::Beer", "BeerDB::Pub"
97 etc). Class::DBI::Loader identifies the appropriate Class::DBI sub‐
98 class and inserts it into each of these table classes' @ISA ( "
99 Class::DBI::<db_driver>" in the diagrams)..
100
101 Next, "Maypole::setup" unshifts Maypole::Model::CDBI onto the @ISA
102 array of each of these classes.
103
104 Finally, the relationships among these tables are set up. Either do
105 this manually, using the standard Class::DBI syntax for configuring ta‐
106 ble relationships, or try Class::DBI::Relationship (which you can use
107 via Maypole::Plugin::Relationship). If you use the plugin, you need to
108 set up the relationships configuration before calling "setup()". Be
109 aware that some people like the convenience of Class::DBI::Relation‐
110 ship, others dislike the abstraction. YMMV.
111
113 We'll call it "BeerDB2".
114
115 Maypole is a framework, and you can replace different bits as you wish.
116 So what follows is one example of good practice, other people may do
117 things differently.
118
119 We assume this application is being built from the ground up, but it
120 will often be straightforward to adapt an existing Class::DBI applica‐
121 tion to this general model.
122
123 The main idea is that the autogenerated Maypole model is used as a
124 layer on top of a separate Class::DBI model. I am going to refer to
125 this model as the 'Offline' model, and the Maypole classes as the 'May‐
126 pole' model. The idea is that the Offline model can (potentially or in
127 actuality) be used as part of another application, perhaps a command
128 line program or a cron script, whatever. The Offline model does not
129 know about the Maypole model, whereas the Maypole model does know about
130 the Offline model.
131
132 Let's call the offline model "OfflineBeer". As a traditional Class::DBI
133 application, individual table classes in this model will inherit from a
134 common base ("OfflineBeer"), which inherits from Class::DBI).
135
136 One advantage of this approach is that you can still use Maypole's
137 autogenerated model. Another is that you do not mix online and offline
138 code in the same packages.
139
140 Building it
141
142 Build a driver in a similar way as for the basic app, calling "setup()"
143 after setting up all the configuration.
144
145 It is a good habit to use a custom Maypole model class for each appli‐
146 cation, as it's a likely first target for customisation. Start it like
147 this:
148
149 package BeerDB2::Maypole::Model;
150 use strict;
151 use warnings;
152 use base 'Maypole::Model::CDBI';
153 1;
154
155 You can add methods which should be shared by all table classes to this
156 package as and when required.
157
158 Configure it like this, before the "setup()" call in the driver class:
159
160 # in package BeerDB2
161 __PACKAGE__->config->model('BeerDB2::Maypole::Model');
162 __PACKAGE__->setup;
163
164 The "setup()" call will ensure your custom model is loaded via
165 "require".
166
167 Note: by default, this will create Maypole/CDBI classes for all the
168 tables in the database. You can control this by passing options for
169 Class::DBI::Loader in the call to "setup()".
170
171 For each class in the model, you need to create a separate file. So for
172 "BeerDB2::Beer", you would write:
173
174 package BeerDB2::Beer;
175 use strict;
176 use warnings;
177 use base 'OfflineBeer::Beer';
178 1;
179
180 From Maypole 2.11, this package will be loaded automatically during
181 "setup()", and "BeerDB2::Maypole::Model" is unshifted onto it's @ISA.
182
183 Configure relationships either in the individual "OfflineBeer::*"
184 classes, or else all together in "OfflineBeer" itself i.e. not in the
185 Maypole model. This way, you only define the relationships in one
186 place.
187
188 The resulting model looks like this:
189
190 Class::DBI
191 MAYPOLE 'MODEL' ⎪
192 ⎪
193 Maypole::Model::Base ⎪
194 + ⎪
195 ⎪ +-----------------+----+-----------------+
196 ⎪ ⎪ ⎪ ⎪
197 ⎪ ⎪ ⎪ ⎪
198 Maypole::Model::CDBI ⎪ ⎪ OFFLINE
199 + ⎪ ⎪ MODEL
200 ⎪ ⎪ ⎪
201 BeerDB2::Maypole::Model Class::DBI::<db_driver> OfflineBeer
202 + + +
203 ⎪ ⎪ ⎪
204 +-----------------------------+ ⎪
205 ⎪ ⎪
206 +--- BeerDB2::Pub --------+ OfflineBeer::Pub --------+
207 ⎪ beers(); ⎪
208 ⎪ ⎪
209 ⎪ OfflineBeer::Handpump ---+
210 ⎪ beer(); ⎪
211 ⎪ pub(); ⎪
212 ⎪ ⎪
213 +--- BeerDB2::Beer -------+ OfflineBeer::Beer -------+
214 ⎪ pubs(); ⎪
215 ⎪ brewery(); ⎪
216 ⎪ style(); ⎪
217 ⎪ ⎪
218 +--- BeerDB2::Style ------+ OfflineBeer::Style ------+
219 ⎪ beers(); ⎪
220 ⎪ ⎪
221 +--- BeerDB2::Brewery ----+ OfflineBeer::Brewery ----+
222 beers();
223
224 Features
225
226 1. Non-Maypole applications using the Offline model are completely iso‐
227 lated from the Maypole application, and need not know it exists at all.
228
229 2. Methods defined in the Maypole table classes, override methods
230 defined in the Offline table classes, because "BeerDB2::Maypole::Model"
231 was unshifted onto the beginning of each Maypole table class's @ISA.
232 Perl's depth first, left-to-right method lookup from e.g.
233 "BeerDB2::Beer" starts in "BeerDB2::Beer", then "BeerDB2::May‐
234 pole::Model", "Maypole::Model::CDBI", "Maypole::Model::Base", and
235 "Class::DBI", before moving on to "OfflineBeer::Beer" and finally
236 "OfflineBeer".
237
238 CAVEAT - if your Offline model overrides Class::DBI methods, these
239 methods will not be overridden when called from the Maypole applica‐
240 tion, because the Maypole model provides an alternative path to
241 Class::DBI which is searched first. The solution is to place such meth‐
242 ods in a separate package, e.g. "OfflineBeer::CDBI". Place this first
243 in the @ISA of both "BeerDB2::Maypole::Model" and "OfflineBeer". Note
244 that "OfflineBeer::CDBI" does not itself need to inherit from
245 Class::DBI.
246
247 3. Methods defined in the Maypole model base class ("BeerDB2::May‐
248 pole::Model"), override methods in the individual Offline table
249 classes, and in the Offline model base class ("Offline").
250
251 4. Relationships defined in the Offline classes are inherited by the
252 Maypole model.
253
254 5. The Maypole model has full access to the underlying Offline model.
255
256 Theory
257
258 This layout illustrates more clearly why the Maypole model may be
259 thought of as part of the controller, rather than part of the model of
260 MVC. Its function is to mediate web requests, translating them into
261 method calls on the Offline model, munging the results, and returning
262 them via the Maypole request object.
263
264 Another way of thinking about it is that Maypole implements a two-layer
265 controller. The first layer translates a raw request into a single
266 method call on the Maypole model layer, which then translates that call
267 into one or more calls on the underlying model.
268
269 Whatever label you prefer to use, this approach provides for clear sep‐
270 aration of concerns between the underlying model and the web/user
271 interface, and that's what it's all about.
272
274 - using Maypole::Model::CDBI::Plain or Maypole::Form‐
275 Builder::Model::Plain - setup_model() and load_model_subclass() - cut‐
276 ting out all those separate paths to CDBI - they're confusing
277
279 More description of Perl's left-to-right, depth-first method lookup,
280 and where it's particularly important in Maypole.
281
283 David Baird, "<cpan@riverside-cms.co.uk>"
284
286 Copyright 2005 David Baird, All Rights Reserved.
287
288 This text is free documentation; you can redistribute it and/or modify
289 it under the same terms as the Perl documentation itself.
290
291
292
293perl v5.8.8 2005-11-23 Maypole::Manual::Inheritance(3)