]> git.decadent.org.uk Git - maypole.git/blobdiff - lib/Maypole/Manual/Inheritance.pod
Added dh_md5sums.
[maypole.git] / lib / Maypole / Manual / Inheritance.pod
index 2dd0eaf0f6e2048d2e6b4569eeebf9115c5afd68..bff339db3bd467b82f5cf6c59d90c3df1c573026 100644 (file)
@@ -16,8 +16,7 @@ application.
 \r
         +\r
         |\r
 \r
         +\r
         |\r
-    +--  --+\r
-        |\r
+     +-   -+\r
        |\r
        +\r
        \r
        |\r
        +\r
        \r
@@ -31,41 +30,42 @@ application.
 \r
 =back\r
 \r
 \r
 =back\r
 \r
-=head1 A standard Maypole application\r
+=head1 Structure of a standard Maypole application\r
+\r
+A minimal Maypole application (such as the Beer database example from the\r
+L<Maypole> synopsis) consists of a custom driver class (BeerDB.pm), a set of\r
+auto-generated model classes, and a view class:\r
 \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
 \r
-                  THE DRIVER\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
                                           +------- 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
+    |                     view_object(); -------+\r
     |    +--------------* setup();              |      Maypole::View::Base\r
     |    |                   +                  |              +\r
     |    |                   |                  |     1        |\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
+    |    |    PLUGINS    Apache::MVC *-----+    +-----> Maypole::View::TT\r
+    |    |       +           +             |             (or another view class)\r
+    |    |       |           |             |\r
+    |    |       +-----+-----+             |\r
+    |    |             |                   |\r
+    |    |           BeerDB                +----- or CGI::Maypole\r
+    |    |                                         or MasonX:::Maypole\r
     |    |\r
     |   setup() is a factory method,\r
     |     it sets up the model\r
     |         classes\r
     |\r
     |    |\r
     |   setup() is a factory method,\r
     |     it sets up the model\r
     |         classes\r
     |\r
-    |                                 THE MODEL\r
+    |                                             THE MODEL\r
     |\r
     |\r
-    |  Maypole::Model::Base   Class::DBI\r
-    |             +             +\r
-    |             |             |                             \r
-    +-------> Maypole::Model::CDBI                            \r
-                      +                                       \r
-                      |                                       \r
+    |  Maypole::Model::Base    Class::DBI\r
+    |             +             +      +\r
+    |             |             |      |\r
+    +-------> Maypole::Model::CDBI   Class::DBI::<db_driver>\r
+                      +                     +\r
+                      |                     |\r
            +------------+--------+-------+---------+\r
            |            |        |       |         |\r
        BeerDB::Pub      |   BeerDB::Beer | BeerDB::Brewery\r
            +------------+--------+-------+---------+\r
            |            |        |       |         |\r
        BeerDB::Pub      |   BeerDB::Beer | BeerDB::Brewery\r
@@ -76,45 +76,47 @@ view class:
           pub();                      BeerDB::Style\r
           beer();                     beers();\r
 \r
           pub();                      BeerDB::Style\r
           beer();                     beers();\r
 \r
-\r
 =head2 What about Maypole::Application - loading plugins\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
+The main job of L<Maypole::Application> is to insert the plugins into the\r
+hierarchy. It is also the responsibility of L<Maypole::Application> to decide\r
+which frontend to use. It builds the list of plugins, then pushes them onto the\r
+driver's C<@ISA>, then pushes the frontend onto the end of the driver's C<@ISA>.\r
+So method lookup first searches all the plugins, before searching the frontend\r
+and finally L<Maypole> itself.\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
 \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
 =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
+First, remember we are talking about the standard, unmodified Maypole here. It\r
+is possible, and common, to override some or all of this stage and build a\r
+customised model. See below - An advanced Maypole application - for one\r
+approach. Also, see L<Maypole's|Maypole> C<setup_model()> method. \r
 \r
 The standard model is built in 3 stages. \r
 \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
+First, C<Maypole::setup_model> calls C<setup_database> on the Maypole model\r
+class, in 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
 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
+L<Class::DBI::Loader> identifies the appropriate L<Class::DBI> subclass and\r
+inserts it into each of these table classes' C<@ISA> ( C<<\r
+Class::DBI::<db_driver> >> in the diagrams)..\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
 \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
+manually, using the standard L<Class::DBI> syntax for configuring table\r
+relationships, or try L<Class::DBI::Relationship> (which you can use via\r
+L<Maypole::Plugin::Relationship>). If you use the plugin, you need to set up the\r
+relationships configuration before calling C<setup()>. Be aware that some people\r
+like the convenience of L<Class::DBI::Relationship>, others dislike the\r
+abstraction. YMMV. \r
 \r
 =head1 An advanced Maypole application\r
 \r
 \r
 =head1 An advanced Maypole application\r
 \r
@@ -181,8 +183,8 @@ C<BeerDB2::Beer>, you would write:
     use base 'OfflineBeer::Beer';\r
     1;\r
     \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
+From Maypole 2.11, this package will be loaded automatically during C<setup()>,\r
+and 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
 \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
@@ -195,15 +197,16 @@ The resulting model looks like this:
                                           |\r
    Maypole::Model::Base                   |\r
            +                              |\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
+           |       |                 |                      |\r
+           |       |                 |                      |\r
+     Maypole::Model::CDBI            |                      |     OFFLINE\r
+             +                       |                      |        MODEL\r
+             |                       |                      |\r
+     BeerDB2::Maypole::Model  Class::DBI::<db_driver>  OfflineBeer\r
+       +                             +                      +\r
+       |                             |                      |\r
+       +-----------------------------+                      |\r
        |                                                    |\r
        +--- BeerDB2::Pub --------+ OfflineBeer::Pub --------+\r
        |                           beers();                 |\r
        |                                                    |\r
        +--- BeerDB2::Pub --------+ OfflineBeer::Pub --------+\r
        |                           beers();                 |\r
@@ -227,10 +230,10 @@ The resulting model looks like this:
 \r
 =head3 Features\r
 \r
 \r
 =head3 Features\r
 \r
-Non-Maypole applications using the Offline model are completely isolated from\r
+1. 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
 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
+2. 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
 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
@@ -238,13 +241,22 @@ C<BeerDB2::Beer>, then C<BeerDB2::Maypole::Model>, C<Maypole::Model::CDBI>,
 C<Maypole::Model::Base>, and C<Class::DBI>, before moving on to\r
 C<OfflineBeer::Beer> and finally C<OfflineBeer>.\r
 \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
+B<CAVEAT> - if your Offline model overrides L<Class::DBI> methods, these methods\r
+will B<not> be overridden when called from the Maypole application, because the\r
+Maypole model provides an alternative path to L<Class::DBI> which is searched\r
+first. The solution is to place such methods in a separate package, e.g.\r
+C<OfflineBeer::CDBI>. Place this B<first> in the C<@ISA> of both\r
+C<BeerDB2::Maypole::Model> and C<OfflineBeer>. Note that C<OfflineBeer::CDBI>\r
+does not itself need to inherit from L<Class::DBI>.\r
+\r
+3. 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
 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
+4. Relationships defined in the Offline classes are inherited by the Maypole\r
+model.\r
 \r
 \r
-The Maypole model has full access to the underlying Offline model. \r
+5. The Maypole model has full access to the underlying Offline model. \r
 \r
 =head3 Theory \r
 \r
 \r
 =head3 Theory \r
 \r
@@ -261,4 +273,31 @@ calls on the underlying model.
 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
 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
+=head1 Advanced applications - building the model by hand ** TODO\r
+\r
+- using Maypole::Model::CDBI::Plain or Maypole::FormBuilder::Model::Plain\r
+- setup_model() and load_model_subclass()\r
+- cutting out all those separate paths to CDBI - they're confusing \r
+\r
+\r
+=head1 Method inheritance ** TODO\r
+\r
+More description of Perl's left-to-right, depth-first method lookup, and where\r
+it's particularly important in Maypole.\r
+\r
+\r
           \r
           \r
+=head1 AUTHOR\r
+\r
+David Baird, C<< <cpan@riverside-cms.co.uk> >>\r
+\r
+=head1 COPYRIGHT & LICENSE\r
+\r
+Copyright 2005 David Baird, All Rights Reserved.\r
+\r
+This text is free documentation; you can redistribute it and/or modify it\r
+under the same terms as the Perl documentation itself.\r
+\r
+=cut\r
+\r