--- /dev/null
+package BeerDB::Base;
+use strict;
+use warnings;
+
+sub floob {}
+
+1;
--- /dev/null
+package BeerDB::Beer;
+use strict;
+use warnings;
+
+# do this to test we get the expected @ISA after setup_model()
+use base 'BeerDB::Base';
+
+sub fooey : Exported {}
+
+1;
A likely target for over-riding, if you need to build a customised model.
+This method also ensures any code in custom model classes is loaded, so you
+don't need to load them in the driver.
+
=cut
sub setup_model
{
- my $calling_class = shift;
+ my $class = shift;
- $calling_class = ref $calling_class if ref $calling_class;
+ $class = ref $class if ref $class;
- my $config = $calling_class->config;
+ my $config = $class->config;
$config->model || $config->model('Maypole::Model::CDBI');
$config->model->require or die sprintf
"Couldn't load the model class %s: %s", $config->model, $@;
- $config->model->setup_database($config, $calling_class, @_);
+ # among other things, this populates $config->classes
+ $config->model->setup_database($config, $class, @_);
foreach my $subclass ( @{ $config->classes } )
{
unshift @{ $subclass . "::ISA" }, $config->model;
$config->model->adopt($subclass)
if $config->model->can("adopt");
-
- # TODO: I think we should also load these classes, in case there is any
- # custom code. It would save the developer from needing to put
- # lots of use MyApp::SomeTable statements in the driver, and should
- # help eliminate some of those annoying silent errors if there's a
- # syntax error.
+
+ # 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/;
}
}
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
| it sets up the model\r
| classes\r
|\r
- | THE MODEL\r
+ | THE MODEL\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
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> 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
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
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
=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
-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
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
-Methods defined in the Maypole model base class (C<BeerDB2::Maypole::Model>),\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
-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
-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
=head1 DESCRIPTION
-This class provides session related methods for Maypole such as unique id's for requests.
+This class provides session related methods for Maypole such as unique id's for
+requests.
-Currently it provides only the generate_unique_id() function, by checking the id's generated by this function and included in submitted forms, it is possible to see if a form has been submitted before.. implementing these checks is left to the developer of that application.
+Currently it provides only the generate_unique_id() function, by checking the
+id's generated by this function and included in submitted forms, it is possible
+to see if a form has been submitted before.. implementing these checks is left
+to the developer of that application.
-Further functionality is to be added here in later versions to provide easy access to sessions, either through plugins or builtin methods.
+Further functionality is to be added here in later versions to provide easy
+access to sessions, either through plugins or builtin methods.
=head1 FUNCTIONS
my $uid = Maypole::Session::generate_unique_id()
-generates a unique id and returns it, requires no arguments but accepts size, default is 32.
+generates a unique id and returns it, requires no arguments but accepts size,
+default is 32.
=cut
}
-###################################################################################################
-###################################################################################################
+################################################################################
+################################################################################
=head1 TODO
-Currently implementing uniqueness tests of form submissions is left to the Maypole user, we plan to provide an optional default behaviour to automate this if required.
+Currently implementing uniqueness tests of form submissions is left to the
+Maypole user, we plan to provide an optional default behaviour to automate this
+if required.
=head1 SEE ALSO
-# vim:ft=perl
+#!/usr/bin/perl -w
use Test::More;
use lib 'ex'; # Where BeerDB should live
BEGIN {
"SQLite not working or BeerDB module could not be loaded: $@"
) if $@;
- plan tests => 15;
+ plan tests => 18;
}
use Maypole::CLI qw(BeerDB);
use Maypole::Constants;
'classdata.list_columns');
is ($classdata{related_accessors},'pubs','classdata.related_accessors');
+# test if successfully loaded customised model 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/] );