1Maypole::Manual::InheriUtsaenrceC(o3n)tributed Perl DocuMmaeynptoaltei:o:nManual::Inheritance(3)
2
3
4

NAME

6       Maypole::Manual::Inheritance - structure of a Maypole application
7

DESCRIPTION

9       Discusses the inheritance structure of a basic and a more advanced May‐
10       pole application.
11

CONVENTIONS

13       inheritance
14                   +
15
16                +-   -+
17
18                   +
19
20       notes
21               target *-------- note about the target
22
23       association
24               source ------> target
25

Structure of a standard Maypole application

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

An advanced Maypole application

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

Advanced applications - building the model by hand ** TODO

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

Method inheritance ** TODO

279       More description of Perl's left-to-right, depth-first method lookup,
280       and where it's particularly important in Maypole.
281

AUTHOR

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)
Impressum