X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=lib%2FMaypole%2FManual%2FInheritance.pod;h=76d76115626194e1f271cecb134edb02e33d1896;hb=ec6799b6896d23dd7bc7c2d7fc6cb2ba3703e231;hp=1c2fca93837bf4241cd341d1660fd0d2146a2dec;hpb=672f0445d8c46ff29b0c6ebf18d30791c017260a;p=maypole.git diff --git a/lib/Maypole/Manual/Inheritance.pod b/lib/Maypole/Manual/Inheritance.pod index 1c2fca9..76d7611 100644 --- a/lib/Maypole/Manual/Inheritance.pod +++ b/lib/Maypole/Manual/Inheritance.pod @@ -16,8 +16,7 @@ application. + | - +-- --+ - | + +- -+ | + @@ -31,41 +30,42 @@ application. =back -=head1 A standard Maypole application +=head1 Structure of a standard Maypole application + +A minimal Maypole application (such as the Beer database example from the +L synopsis) consists of a custom driver (or controller) class (BeerDB.pm), +a set of auto-generated model classes, and a view class: -A minimal Maypole application (such as the Beer database) consists of a -custom driver class (BeerDB.pm), a set of auto-generated model classes, and a -view class: - THE DRIVER + THE DRIVER +------- init() is a factory method, 1 Maypole | it sets up the view Maypole::Config <----- config(); | classes model(); init(); *-------+ THE VIEW - | view_object(); -------+ + | view_object(); -------+ | +--------------* setup(); | Maypole::View::Base | | + | + | | | | 1 | - | | Apache::MVC *-----+ +-----> Maypole::View::TT - | | + | (or another view class) - | | | | - | | PLUGINS | - | | + | - | | | +----- or CGI::Maypole - | | BeerDB or MasonX:::Maypole + | | PLUGINS Apache::MVC *-----+ +-----> Maypole::View::TT + | | + + | (or another view class) + | | | | | + | | +-----+-----+ | + | | | | + | | BeerDB +----- or CGI::Maypole + | | or MasonX:::Maypole | | | setup() is a factory method, | it sets up the model | classes | - | THE MODEL + | THE MODEL | - | Maypole::Model::Base Class::DBI - | + + - | | | - +-------> Maypole::Model::CDBI - + - | + | Maypole::Model::Base Class::DBI + | + + + + | | | | + +-------> Maypole::Model::CDBI Class::DBI:: + + + + | | +------------+--------+-------+---------+ | | | | | BeerDB::Pub | BeerDB::Beer | BeerDB::Brewery @@ -76,45 +76,52 @@ view class: pub(); BeerDB::Style beer(); beers(); +=head2 Ouch, that's a lot of inheritence! -=head2 What about Maypole::Application - loading plugins +Yes, that's a lot of inheritence, fortunately as of 2.12 Maypole uses +L to ensure sane method resolution. -The main job of L is to insert the plugins into the -hierarchy. It ensures that L inherits from the first plugin, which -inherits from the next, etc., until the last plugin inherits from the frontend. +=head2 What about Maypole::Application - loading plugins -It is also the responsibility of L to decide which -frontend to use. +The main job of L is to insert the plugins into the +hierarchy. It is also the responsibility of L to decide +which frontend to use. It builds the list of plugins, then pushes them onto the +driver's C<@ISA>, then pushes the frontend onto the end of the driver's C<@ISA>. +So method lookup first searches all the plugins, before searching the frontend +and finally L itself. From Maypole 2.11, L makes no appearance in the inheritance structure of a Maypole application. (In prior versions, L would make itself inherit the plugins, and then insert itself in the hierarchy, but this was unnecessary). -The order of inheritance is the same as the order in which plugins are supplied -in the C statement. - =head2 Who builds the model? -First, remember we are talking about the standard, unmodified Maypole here. -It is possible, and common, to override some or all of this stage and build a -customised model. +First, remember we are talking about the standard, unmodified Maypole here. It +is possible, and common, to override some or all of this stage and build a +customised model. See below - An advanced Maypole application - for one +approach. Also, see L C method. The standard model is built in 3 stages. -First, C calls C on the Maypole model class, in -this case L. C then uses +First, C calls C on the Maypole model +class, in this case L. C then uses L to autogenerate individual L classes for each of the tables in the database (C, C etc). +L identifies the appropriate L subclass and +inserts it into each of these table classes' C<@ISA> ( C<< +Class::DBI:: >> in the diagrams).. -Next, C B L onto the C<@ISA> +Next, C B L onto the C<@ISA> array of each of these classes. Finally, the relationships among these tables are set up. Either do this -manually, perhaps with the help of L, or use -L. In the latter case, you need to set up the -relationships configuration before calling C. - +manually, using the standard L syntax for configuring table +relationships, or try L (which you can use via +L). If you use the plugin, you need to set up the +relationships configuration before calling C. Be aware that some people +like the convenience of L, others dislike the +abstraction. YMMV. =head1 An advanced Maypole application @@ -181,8 +188,8 @@ C, you would write: use base 'OfflineBeer::Beer'; 1; -This package will be loaded automatically during C, and -C is B onto it's C<@ISA>. +From Maypole 2.11, this package will be loaded automatically during C, +and C is B onto it's C<@ISA>. Configure relationships either in the individual C classes, or else all together in C itself i.e. not in the Maypole model. This @@ -195,15 +202,16 @@ The resulting model looks like this: | Maypole::Model::Base | + | - | +----------------------+-----------------+ - | | | - | | | - Maypole::Model::CDBI | OFFLINE - + | MODEL - | | - BeerDB2::Maypole::Model OfflineBeer - + + - | | + | +-----------------+----+-----------------+ + | | | | + | | | | + Maypole::Model::CDBI | | OFFLINE + + | | MODEL + | | | + BeerDB2::Maypole::Model Class::DBI:: OfflineBeer + + + + + | | | + +-----------------------------+ | | | +--- BeerDB2::Pub --------+ OfflineBeer::Pub --------+ | beers(); | @@ -227,12 +235,14 @@ The resulting model looks like this: =head3 Features -Non-Maypole applications using the Offline model are completely isolated from +*REWRITE BASED ON C3 and push instead of shift* + +1. Non-Maypole applications using the Offline model are completely isolated from the Maypole application, and need not know it exists at all. -Methods defined in the Maypole table classes, override methods defined in the -Offline table classes, because C was unshifted onto the -beginning of each Maypole table class's C<@ISA>. Perl's depth first, +2. Methods defined in the Maypole table classes, override methods defined in the +Offline table classes, because C was pushed onto the +end of each Maypole table class's C<@ISA>. Perl's depth first, left-to-right method lookup from e.g. C starts in C, then C, C, C, and C, before moving on to @@ -246,13 +256,14 @@ C. Place this B in the C<@ISA> of both C and C. Note that C does not itself need to inherit from L. -Methods defined in the Maypole model base class (C), +3. Methods defined in the Maypole model base class (C), override methods in the individual Offline table classes, and in the Offline model base class (C). -Relationships defined in the Offline classes are inherited by the Maypole model. +4. Relationships defined in the Offline classes are inherited by the Maypole +model. -The Maypole model has full access to the underlying Offline model. +5. The Maypole model has full access to the underlying Offline model. =head3 Theory @@ -269,6 +280,20 @@ calls on the underlying model. Whatever label you prefer to use, this approach provides for clear separation of concerns between the underlying model and the web/user interface, and that's what it's all about. + +=head1 Advanced applications - building the model by hand ** TODO + +- using Maypole::Model::CDBI::Plain or Maypole::FormBuilder::Model::Plain +- setup_model() and load_model_subclass() +- cutting out all those separate paths to CDBI - they're confusing + + +=head1 Method inheritance ** TODO + +More description of Perl's left-to-right, depth-first method lookup, and where +it's particularly important in Maypole. + + =head1 AUTHOR