]> git.decadent.org.uk Git - maypole.git/commitdiff
Improved Maypole::load_model_subclass(). Added sequence
authorDavid Baird <cpan.zerofive@googlemail.com>
Fri, 4 Nov 2005 15:21:14 +0000 (15:21 +0000)
committerDavid Baird <cpan.zerofive@googlemail.com>
Fri, 4 Nov 2005 15:21:14 +0000 (15:21 +0000)
diagrams to illustrate workflow.

git-svn-id: http://svn.maypole.perl.org/Maypole/trunk@409 48953598-375a-da11-a14b-00016c27c3ee

ex/BeerDB.pm
lib/Maypole.pm
t/01basics.t

index 778185a0b7e657336dabe63b8c55a2e7cea3eefa..466aa5e8313fed88cfa42415a542e8356a530df9 100644 (file)
@@ -2,7 +2,7 @@ package BeerDB;
 use Maypole::Application;
 use Class::DBI::Loader::Relationship;
 
-sub debug { $ENV{BEERDB_DEBUG} }
+sub debug { $ENV{BEERDB_DEBUG} || 0 }
 # This is the sample application.  Change this to the path to your
 # database. (or use mysql or something)
 use constant DBI_DRIVER => 'SQLite';
index 6c6ff52c0fc8ef0cad989205b9925382ccb03014..d8e893dadb7693d141eee068e80032a215c69c88 100644 (file)
@@ -168,10 +168,47 @@ __PACKAGE__->config( Maypole::Config->new() );
 
 __PACKAGE__->init_done(0);
 
+=head1 HOOKABLE METHODS
+
+As a framework, Maypole provides a number of B<hooks> - methods that are
+intended to be overridden. Some of these methods come with useful default
+behaviour, others do nothing by default. Likely hooks include:
+
+    Class methods
+    -------------
+    debug 
+    setup 
+    setup_model 
+    load_model_subclass
+    init
+    
+    Instance methods
+    ----------------
+    start_request_hook
+    is_model_applicable
+    get_session
+    authenticate
+    exception
+    additional_data
+    preprocess_path
+
 =head1 CLASS METHODS
 
 =over 4
 
+=item debug
+
+    sub My::App::debug {1}
+
+Returns the debugging flag. Override this in your application class to
+enable/disable debugging.
+
+You can also set the C<debug> flag via L<Maypole::Application>.
+
+=cut
+
+sub debug { 0 }      
+
 =item config
 
 Returns the L<Maypole::Config> object
@@ -230,17 +267,54 @@ sub setup_model
     {
         no strict 'refs';
         unshift @{ $subclass . "::ISA" }, $config->model;
-        $config->model->adopt($subclass)
-          if $config->model->can("adopt");
-
-       # Load custom model code, if it exists - nb this must happen after the 
-       # unshift, to allow code attributes to work
-       eval "use $subclass"; 
-       die "Error loading $subclass: $@"  
-            if $@ and $@ !~ /Can\'t locate \S+ in \@INC/;
+        
+        # Load custom model code, if it exists - nb this must happen after the 
+        # unshift, to allow code attributes to work, but before adopt(),  
+        # in case adopt() calls overridden methods on $subclass
+        $class->load_model_subclass($subclass);
+        
+        $config->model->adopt($subclass) if $config->model->can("adopt");
+
+#      eval "use $subclass"; 
+#      die "Error loading $subclass: $@"  
+#            if $@ and $@ !~ /Can\'t locate \S+ in \@INC/;
     }
 }
 
+=item load_model_subclass($subclass)
+
+This method is called from C<setup_model()>. It attempts to load the
+C<$subclass> package, if one exists. So if you make a customized C<BeerDB::Beer>
+package, you don't need to explicitly load it. 
+
+If, perhaps during development, you don't want to load up custom classes, you 
+can override this method and load them manually. 
+
+=cut
+
+sub load_model_subclass
+{
+    my ($class, $subclass) = @_;
+    
+    my $config = $class->config;
+    
+    # Load any external files for the model base class or subclasses
+    # (e.g. BeerDB/DBI.pm or BeerDB/Beer.pm) based on code borrowed from
+    # Maypole::Plugin::Loader and Class::DBI.
+    if ( $subclass->require ) 
+    {
+        warn "Loaded external module for '$subclass'\n" if $class->debug > 1;
+    } 
+    else 
+    {
+        (my $filename = $subclass) =~ s!::!/!g;
+        die "Loading '$subclass' failed: $@\n"
+               unless $@ =~ /Can\'t locate \Q$filename\E\.pm/;
+        warn "Did not find external module for '$subclass'\n" 
+            if $class->debug > 1;
+   }
+}
+
 =item init
 
 Loads the view class and instantiates the view object.
@@ -285,30 +359,6 @@ sub new
 
 Get/set the Maypole::View object
 
-=item debug
-
-    sub My::App::debug {1}
-
-Returns the debugging flag. Override this in your application class to
-enable/disable debugging.
-
-You can also set the C<debug> flag via L<Maypole::Application>.
-
-=cut
-
-sub debug { 0 }      
-
-=item get_template_root
-
-Implementation-specific path to template root.
-
-You should only need to define this method if you are writing a new Maypole
-backend. Otherwise, see L<Maypole::Config/"template_root">
-
-=cut
-
-sub get_template_root {'.'}
-
 =back
 
 =head1 INSTANCE METHODS
@@ -377,7 +427,7 @@ sub handler_guts
 {
     my ($self) = @_;
     
-    $self->__load_model;
+    $self->__load_request_model;
 
     my $applicable = $self->is_model_applicable;
     
@@ -434,7 +484,7 @@ sub handler_guts
     return $self->__call_process_view;
 }
 
-sub __load_model
+sub __load_request_model
 {
     my ($self) = @_;
     $self->model_class( $self->config->model->class_of($self, $self->table) );
@@ -853,6 +903,25 @@ Turns post data and query string paramaters into a hash of C<params>.
 You should only need to define this method if you are writing a new Maypole
 backend.
 
+=cut 
+
+sub parse_args
+{
+    die "parse_args() is a virtual method. Do not use Maypole directly; ".
+            "use Apache::MVC or similar";
+}
+
+=item get_template_root
+
+Implementation-specific path to template root.
+
+You should only need to define this method if you are writing a new Maypole
+backend. Otherwise, see L<Maypole::Config/"template_root">
+
+=cut
+
+sub get_template_root {'.'}
+
 =back
 
 =head2 Request properties
@@ -1061,6 +1130,107 @@ sub make_random_id {
 
 =back
 
+=head1 SEQUENCE DIAGRAMS
+
+See L<Maypole::Manual::Workflow> for a detailed discussion of the sequence of 
+calls during processing of a request. This is a brief summary:
+
+    INITIALIZATION
+                               Model e.g.
+         BeerDB           Maypole::Model::CDBI
+           |                        |
+   setup   |                        |
+ o-------->||                       |
+           || setup_model           |     setup_database() creates
+           ||------+                |      a subclass of the Model
+           |||<----+                |        for each table
+           |||                      |                |
+           |||   setup_database     |                |
+           |||--------------------->|| 'create'      *
+           |||                      ||----------> $subclass
+           |||                      |                  |
+           ||| load_model_subclass  |                  |
+ foreach   |||------+  ($subclass)  |                  |
+ $subclass ||||<----+               |    require       |
+           ||||--------------------------------------->|
+           |||                      |                  |
+           |||   adopt($subclass)   |                  |
+           |||--------------------->||                 |
+           |                        |                  |
+           |                        |                  |
+           |-----+ init             |                  |
+           ||<---+                  |                  |
+           ||                       |     new          |     view_object: e.g
+           ||---------------------------------------------> Maypole::View::TT
+           |                        |                  |          |
+           |                        |                  |          |
+           |                        |                  |          |
+           |                        |                  |          |
+           |                        |                  |          |
+           
+
+
+    HANDLING A REQUEST
+
+
+          BeerDB                                Model  $subclass  view_object
+            |                                      |       |         |
+    handler |                                      |       |         |
+  o-------->| new                                  |       |         |
+            |-----> r:BeerDB                       |       |         |
+            |         |                            |       |         |
+            |         |                            |       |         |
+            |         ||                           |       |         |
+            |         ||-----+ parse_location      |       |         |
+            |         |||<---+                     |       |         |
+            |         ||                           |       |         |
+            |         ||-----+ start_request_hook  |       |         |
+            |         |||<---+                     |       |         |
+            |         ||                           |       |         |
+            |         ||-----+ get_session         |       |         |
+            |         |||<---+                     |       |         |
+            |         ||                           |       |         |
+            |         ||-----+ handler_guts        |       |         |
+            |         |||<---+                     |       |         |
+            |         |||     class_of($table)     |       |         |
+            |         |||------------------------->||      |         |
+            |         |||       $subclass          ||      |         |
+            |         |||<-------------------------||      |         |
+            |         |||                          |       |         |
+            |         |||-----+ is_model_applicable|       |         |
+            |         ||||<---+                    |       |         |
+            |         |||                          |       |         |
+            |         |||-----+ call_authenticate  |       |         |
+            |         ||||<---+                    |       |         |
+            |         |||                          |       |         |
+            |         |||-----+ additional_data    |       |         |
+            |         ||||<---+                    |       |         |
+            |         |||             process      |       |   fetch_objects
+            |         |||--------------------------------->||-----+  |
+            |         |||                          |       |||<---+  |
+            |         |||                          |       ||        |
+            |         |||                          |       ||   $action
+            |         |||                          |       ||-----+  |
+            |         |||                          |       |||<---+  |
+            |         |||                          |       |         |
+            |         |||         process          |       |         |
+            |         |||------------------------------------------->|| template
+            |         |||                          |       |         ||-----+
+            |         |||                          |       |         |||<---+
+            |         |||                          |       |         |
+            |         ||     send_output           |       |         |
+            |         ||-----+                     |       |         |
+            |         |||<---+                     |       |         |
+   $status  |         ||                           |       |         |
+   <------------------||                           |       |         |
+            |         |                            |       |         |
+            |         X                            |       |         |           
+            |                                      |       |         |
+            |                                      |       |         |
+            |                                      |       |         |
+           
+           
+
 =head1 SEE ALSO
 
 There's more documentation, examples, and a information on our mailing lists
index e40fa85f488725b000c26b80428cc70012c51779..5de19c837628c8a935a78f54281ca4f83f949b8c 100644 (file)
@@ -2,12 +2,15 @@
 use Test::More;
 use lib 'ex'; # Where BeerDB should live
 BEGIN {
+    #$ENV{BEERDB_DEBUG} = 2;
+
     eval { require BeerDB };
     Test::More->import( skip_all =>
         "SQLite not working or BeerDB module could not be loaded: $@"
     ) if $@;
 
     plan tests => 18;
+    
 }
 use Maypole::CLI qw(BeerDB);
 use Maypole::Constants;
@@ -42,7 +45,7 @@ is($classdata{list_columns}, 'score name price style brewery url',
    'classdata.list_columns');
 is ($classdata{related_accessors},'pubs','classdata.related_accessors');
 
-# test if successfully loaded customised model class
+# test Maypole::load_custom_class()
 can_ok(BeerDB::Beer => 'fooey');     # defined in BeerDB::Beer
 can_ok(BeerDB::Beer => 'floob');     # defined in BeerDB::Base
 is_deeply( [@BeerDB::Beer::ISA], [qw/Maypole::Model::CDBI Class::DBI::SQLite BeerDB::Base/] );