--- /dev/null
+\r
+=head1 NAME\r
+\r
+Maypole::Manual::Inheritance - structure of a Maypole application\r
+\r
+=head1 DESCRIPTION\r
+\r
+Discusses the inheritance structure of a basic and a more advanced Maypole\r
+application.\r
+\r
+=head1 CONVENTIONS\r
+ \r
+=over 4\r
+\r
+=item inheritance\r
+\r
+ +\r
+ |\r
+ +-- --+\r
+ |\r
+ |\r
+ +\r
+ \r
+=item notes\r
+\r
+ target *-------- note about the target\r
+\r
+=item association\r
+\r
+ source ------> target\r
+\r
+=back\r
+\r
+=head1 A standard Maypole application\r
+\r
+A minimal Maypole application (such as the Beer database) consists of a \r
+custom driver class (BeerDB.pm), a set of auto-generated model classes, and a \r
+view class: \r
+\r
+ THE DRIVER\r
+ +------- init() is a factory method,\r
+ 1 Maypole | it sets up the view\r
+ Maypole::Config <----- config(); | classes\r
+ model(); init(); *-------+ THE VIEW\r
+ | view_object(); -------+ \r
+ | +--------------* setup(); | Maypole::View::Base\r
+ | | + | +\r
+ | | | | 1 |\r
+ | | Apache::MVC *-----+ +-----> Maypole::View::TT\r
+ | | + | (or another view class)\r
+ | | | |\r
+ | | PLUGINS |\r
+ | | + |\r
+ | | | +----- or CGI::Maypole\r
+ | | BeerDB or MasonX:::Maypole\r
+ | |\r
+ | setup() is a factory method,\r
+ | it sets up the model\r
+ | classes\r
+ |\r
+ | THE MODEL\r
+ |\r
+ | Maypole::Model::Base Class::DBI\r
+ | + +\r
+ | | | \r
+ +-------> Maypole::Model::CDBI \r
+ + \r
+ | \r
+ +------------+--------+-------+---------+\r
+ | | | | |\r
+ BeerDB::Pub | BeerDB::Beer | BeerDB::Brewery\r
+ beers(); | pubs(); | beers();\r
+ | brewery(); |\r
+ | style(); |\r
+ BeerDB::Handpump |\r
+ pub(); BeerDB::Style\r
+ beer(); beers();\r
+\r
+\r
+=head2 What about Maypole::Application - loading plugins\r
+\r
+The main job of L<Maypole::Application> is to insert the plugins into the \r
+hierarchy. It ensures that L<BeerDB> inherits from the first plugin, which \r
+inherits from the next, etc., until the last plugin inherits from the frontend. \r
+\r
+It is also the responsibility of L<Maypole::Application> to decide which \r
+frontend to use. \r
+\r
+From Maypole 2.11, L<Maypole::Application> makes no appearance in the\r
+inheritance structure of a Maypole application. (In prior versions,\r
+L<Maypole::Application> would make itself inherit the plugins, and then insert\r
+itself in the hierarchy, but this was unnecessary).\r
+\r
+The order of inheritance is the same as the order in which plugins are supplied \r
+in the C<use Maypole::Application> statement. \r
+\r
+=head2 Who builds the model?\r
+\r
+First, remember we are talking about the standard, unmodified Maypole here. \r
+It is possible, and common, to override some or all of this stage and build a \r
+customised model.\r
+\r
+The standard model is built in 3 stages. \r
+\r
+First, C<Maypole::setup> calls C<setup_database> on the Maypole model class, in\r
+this case L<Maypole::Model::CDBI>. C<setup_database> then uses\r
+L<Class::DBI::Loader> to autogenerate individual L<Class::DBI> classes for each\r
+of the tables in the database (C<BeerDB::Beer>, C<BeerDB::Pub> etc).\r
+\r
+Next, C<Maypole::setup> B<unshifts> L<Maypole::Model::CDBI> onto the C<@ISA> \r
+array of each of these classes. \r
+\r
+Finally, the relationships among these tables are set up. Either do this\r
+manually, perhaps with the help of L<Class::DBI::Relationship>, or use\r
+L<Maypole::Plugin::Relationship>. In the latter case, you need to set up the\r
+relationships configuration before calling C<setup()>.\r
+\r
+\r
+=head1 An advanced Maypole application\r
+\r
+We'll call it C<BeerDB2>.\r
+\r
+Maypole is a framework, and you can replace different bits as you wish. So what \r
+follows is one example of good practice, other people may do things differently. \r
+\r
+We assume this application is being built from the ground up, but it will often\r
+be straightforward to adapt an existing L<Class::DBI> application to this\r
+general model.\r
+\r
+The main idea is that the autogenerated Maypole model is used as a layer on top\r
+of a separate L<Class::DBI> model. I am going to refer to this model as the\r
+'Offline' model, and the Maypole classes as the 'Maypole' model. The idea is\r
+that the Offline model can (potentially or in actuality) be used as part of\r
+another application, perhaps a command line program or a cron script, whatever.\r
+The Offline model does not know about the Maypole model, whereas the Maypole\r
+model does know about the Offline model.\r
+\r
+Let's call the offline model C<OfflineBeer>. As a traditional L<Class::DBI>\r
+application, individual table classes in this model will inherit from a common\r
+base (C<OfflineBeer>), which inherits from L<Class::DBI>).\r
+\r
+One advantage of this approach is that you can still use Maypole's autogenerated\r
+model. Another is that you do not mix online and offline code in the same\r
+packages.\r
+\r
+=head2 Building it\r
+\r
+Build a driver in a similar way as for the basic app, calling C<setup()> after\r
+setting up all the configuration. \r
+\r
+It is a good habit to use a custom Maypole model class for each application, as\r
+it's a likely first target for customisation. Start it like this:\r
+\r
+ package BeerDB2::Maypole::Model;\r
+ use strict;\r
+ use warnings;\r
+ use base 'Maypole::Model::CDBI';\r
+ 1;\r
+ \r
+You can add methods which should be shared by all table classes to this package \r
+as and when required.\r
+ \r
+Configure it like this, before the C<setup()> call in the driver class:\r
+\r
+ # in package BeerDB2\r
+ __PACKAGE__->config->model('BeerDB2::Maypole::Model');\r
+ __PACKAGE__->setup;\r
+\r
+The C<setup()> call will ensure your custom model is loaded via C<require>.\r
+\r
+B<Note>: by default, this will create Maypole/CDBI classes for all the tables in\r
+the database. You can control this by passing options for L<Class::DBI::Loader>\r
+in the call to C<setup()>.\r
+\r
+For each class in the model, you need to create a separate file. So for\r
+C<BeerDB2::Beer>, you would write:\r
+\r
+ package BeerDB2::Beer;\r
+ use strict;\r
+ use warnings;\r
+ use base 'OfflineBeer::Beer';\r
+ 1;\r
+ \r
+This package will be loaded automatically during C<setup()>, and\r
+C<BeerDB2::Maypole::Model> is B<unshifted> onto it's C<@ISA>. \r
+\r
+Configure relationships either in the individual C<OfflineBeer::*> classes, or\r
+else all together in C<OfflineBeer> itself i.e. not in the Maypole model. This \r
+way, you only define the relationships in one place.\r
+\r
+The resulting model looks like this:\r
+\r
+ Class::DBI\r
+ MAYPOLE 'MODEL' |\r
+ |\r
+ Maypole::Model::Base |\r
+ + |\r
+ | +----------------------+-----------------+\r
+ | | |\r
+ | | |\r
+ Maypole::Model::CDBI | OFFLINE\r
+ + | MODEL\r
+ | |\r
+ BeerDB2::Maypole::Model OfflineBeer\r
+ + +\r
+ | |\r
+ | |\r
+ +--- BeerDB2::Pub --------+ OfflineBeer::Pub --------+\r
+ | beers(); |\r
+ | |\r
+ | OfflineBeer::Handpump ---+\r
+ | beer(); |\r
+ | pub(); |\r
+ | |\r
+ +--- BeerDB2::Beer -------+ OfflineBeer::Beer -------+\r
+ | pubs(); |\r
+ | brewery(); |\r
+ | style(); |\r
+ | |\r
+ +--- BeerDB2::Style ------+ OfflineBeer::Style ------+\r
+ | beers(); |\r
+ | |\r
+ +--- BeerDB2::Brewery ----+ OfflineBeer::Brewery ----+\r
+ beers();\r
+\r
+\r
+\r
+=head3 Features\r
+\r
+Non-Maypole applications using the Offline model are completely isolated from\r
+the Maypole application, and need not know it exists at all.\r
+\r
+Methods defined in the Maypole table classes, override methods defined in the\r
+Offline table classes, because C<BeerDB2::Maypole::Model> was unshifted onto the\r
+beginning of each Maypole table class's C<@ISA>. Perl's depth first,\r
+left-to-right method lookup from e.g. C<BeerDB2::Beer> starts in\r
+C<BeerDB2::Beer>, then C<BeerDB2::Maypole::Model>, C<Maypole::Model::CDBI>,\r
+C<Maypole::Model::Base>, and C<Class::DBI>, before moving on to\r
+C<OfflineBeer::Beer> and finally C<OfflineBeer>.\r
+\r
+Methods defined in the Maypole model base class (C<BeerDB2::Maypole::Model>),\r
+override methods in the individual Offline table classes, and in the Offline\r
+model base class (C<Offline>). \r
+\r
+Relationships defined in the Offline classes are inherited by the Maypole model.\r
+\r
+The Maypole model has full access to the underlying Offline model. \r
+\r
+=head3 Theory \r
+\r
+This layout illustrates more clearly why the Maypole model may be thought of as\r
+part of the controller, rather than part of the model of MVC. Its function is to \r
+mediate web requests, translating them into method calls on the Offline model, \r
+munging the results, and returning them via the Maypole request object. \r
+\r
+Another way of thinking about it is that Maypole implements a two-layer\r
+controller. The first layer translates a raw request into a single method call\r
+on the Maypole model layer, which then translates that call into one or more\r
+calls on the underlying model.\r
+\r
+Whatever label you prefer to use, this approach provides for clear separation of\r
+concerns between the underlying model and the web/user interface, and that's\r
+what it's all about.\r
+ \r