package Maypole;
+use Class::C3;
use base qw(Class::Accessor::Fast Class::Data::Inheritable);
use UNIVERSAL::require;
use strict;
use NEXT;
use File::MMagic::XS qw(:compat);
-our $VERSION = '2.11';
+our $VERSION = '2.12';
our $mmagic = File::MMagic::XS->new();
# proposed privacy conventions:
# choose a frontend, initialise the config object, and load a plugin
use Maypole::Application qw/Relationship/;
+
+ # set everything up
+ __PACKAGE__->setup("dbi:SQLite:t/beerdb.db");
# get the empty config object created by Maypole::Application
my $config = __PACKAGE__->config;
date => [ qw/date/],
);
- # set everything up
- __PACKAGE__->setup("dbi:SQLite:t/beerdb.db");
+ # note : set up model before calling this method
+ BeerDB::Beer->required_columns([qw/name/]);
1;
Note that some details in some of these resources may be out of date.
-=over 4
+=over 4
=item The Maypole Manual
=item Web applications with Maypole
A tutorial written by Simon Cozens for YAPC::EU 2005 -
-http://www.droogs.org/perl/maypole/maypole-tutorial.pdf [228KB].
+http://www.aarontrevena.co.uk/opensource/maypole/maypole-tutorial.pdf [228KB].
=item A Database-Driven Web Application in 18 Lines of Code
=item Authentication
Some notes written by Simon Cozens. A little bit out of date, but still
-very useful: http://www.droogs.org/perl/maypole/authentication.html
+very useful: http://www.aarontrevena.co.uk/opensource/maypole/authentication.html
=item CheatSheet
=back
-=head1 DEMOS
-
-A couple of demos are available, sometimes with source code and configs.
-
-=over 4
-
-=item http://maypole.perl.org/beerdb/
-
-The standard BeerDB example, using the TT factory templates supplied in the
-distribution.
-
-=item beerdb.riverside-cms.co.uk
-
-The standard BeerDB example, running on Mason, using the factory templates
-supplied in the L<MasonX::Maypole> distribution.
-
-=item beerfb.riverside-cms.co.uk
-
-A demo of L<Maypole::FormBuilder>. This site is running on the set of Mason
-templates included in the L<Maypole::FormBuilder> distribution. See the
-synopsis of L<Maypole::Plugin::FormBuilder> for an example driver
-
-=back
-
=cut
__PACKAGE__->mk_classdata($_) for qw( config init_done view_object model_classes_loaded);
__PACKAGE__->mk_accessors(
qw( params query objects model_class template_args output path
args action template error document_encoding content_type table
- headers_in headers_out stash status parent)
+ headers_in headers_out stash status parent build_form_elements)
);
__PACKAGE__->config( Maypole::Config->new() );
=cut
-sub debug { 1 }
+sub debug { 0 }
=item config
# among other things, this populates $config->classes
$config->model->setup_database($config, $class, @_);
- foreach my $subclass ( @{ $config->classes } ) {
- next if $subclass->isa("Maypole::Model::Base");
- no strict 'refs';
- unshift @{ $subclass . "::ISA" }, $config->model;
- }
+ $config->model->add_model_superclass($config);
# Load custom model code, if it exists - nb this must happen after the
- # unshift, to allow code attributes to work, but before adopt(),
+ # adding the model superclass, to allow code attributes to work, but before adopt(),
# in case adopt() calls overridden methods on $subclass
foreach my $subclass ( @{ $config->classes } ) {
$class->load_model_subclass($subclass) unless ($class->model_classes_loaded());
config => $class->config,
}, $class;
- $self->stash({});
- $self->params({});
- $self->query({});
- $self->template_args({});
- $self->args([]);
- $self->objects([]);
-
+ $self->stash({});
+ $self->params({});
+ $self->query({});
+ $self->template_args({});
+ $self->args([]);
+ $self->objects([]);
return $self;
}
This is the main request handling method and calls various methods to handle the
request/response and defines the workflow within Maypole.
-B<Currently undocumented and liable to be refactored without warning>.
-
=cut
# The root of all evil
sub handler_guts
{
my ($self) = @_;
-
+ $self->build_form_elements(1);
$self->__load_request_model;
my $applicable = $self->is_model_applicable == OK;
sub __load_request_model
{
my ($self) = @_;
- $self->model_class( $self->config->model->class_of($self, $self->table) );
+ # We may get a made up class from class_of
+ my $mclass = $self->config->model->class_of($self, $self->table);
+ if ( eval {$mclass->isa('Maypole::Model::Base')} ) {
+ $self->model_class( $mclass );
+ }
+ elsif ($self->debug) {
+ warn "***Warning: No $mclass class appropriate for model. @_";
+ }
}
+
# is_applicable() returned false, so set up a plain template. Model processing
# will be skipped, but need to remove the model anyway so the template can't
# access it.
return $status;
}
+=item warn
+
+$r->warn('its all gone pete tong');
+
+Warn must be implemented by the backend, i.e. Apache::MVC
+and warn to stderr or appropriate logfile.
+
+You can also over-ride this in your Maypole driver, should you
+want to use something like Log::Log4perl instead.
+
+=cut
+
+sub warn { }
+
+=item build_form_elements
+
+$r->build_form_elements(0);
+
+Specify whether to build HTML form elements and populate
+the cgi element of classmetadata.
+
+=cut
+
=item get_request
You should only need to define this method if you are writing a new
if (not $ok)
{
- warn "We don't have that table ($table).\n"
+ $self->warn ("We don't have that table ($table).\n"
. "Available tables are: "
- . join( ",", keys %$ok_tables )
+ . join( ",", keys %$ok_tables ))
if $self->debug and not $ok_tables->{$table};
return DECLINED;
my $action = $self->action;
return OK if $self->model_class->is_public($action);
- warn "The action '$action' is not applicable to the table '$table'"
+ $self->warn("The action '$action' is not applicable to the table '$table'")
if $self->debug;
return DECLINED;
}
-
-
=back
=head2 Path processing and manipulation
sub parse_path
{
my ($self) = @_;
-
+
# Previous versions unconditionally set table, action and args to whatever
# was in @pi (or else to defaults, if @pi is empty).
# Adding preprocess_path(), and then setting table, action and args
# conditionally, broke lots of tests, hence this:
$self->$_(undef) for qw/action table args/;
-
$self->preprocess_path;
$self->path || $self->path('frontpage');
class, it will be removed from C<args> and the retrieved object will be added to
the C<objects> list. See L<Maypole::Model> for more information.
+
+=item object
+
+Alias to get/set the first/only model object. The object will be accessible
+in the view templates.
+
+When used to set the object, will overwrite the request objects
+with a single object.
+
+=cut
+
+sub object {
+ my ($r,$object) = @_;
+ $r->objects([$object]) if ($object);
+ return undef unless $r->objects();
+ return $r->objects->[0];
+}
+
=item template_args
$self->template_args->{foo} = 'bar';
Get/set a hash of template variables.
+Maypole reserved words for template variables will over-ride values in template_variables.
+
+Reserved words are : r, request, object, objects, base, config and errors, as well as the
+current class or object name.
+
=item stash
-A place to put custom application data. Not used by Maypole itself.
+A place to put custom application data. Not used by Maypole itself.
=item template