]> git.decadent.org.uk Git - maypole.git/blobdiff - lib/Maypole.pm
Apache2::MVC, Maypole::Application, parse_args() and much more...
[maypole.git] / lib / Maypole.pm
index d5d932c4816a32c8e78c4650e6042ffc9b04f938..e3a92524a8f4a2d52bf458b0dc3c48f183f8b2d6 100644 (file)
@@ -4,16 +4,13 @@ use attributes ();
 use UNIVERSAL::require;
 use strict;
 use warnings;
-our $VERSION = "1.1";
+our $VERSION = "1.8";
 __PACKAGE__->mk_classdata($_) for qw( config init_done view_object );
 __PACKAGE__->mk_accessors ( qw( ar params query objects model_class
 args action template ));
 __PACKAGE__->config({});
 __PACKAGE__->init_done(0);
-
-# Ape Apache::Constants interface
-use constant OK => 0;
-use constant DECLINED => -1;
+use Maypole::Constants;
 
 sub debug { 0 }
 
@@ -28,6 +25,7 @@ sub setup {
     my $config = $calling_class->config;
     $config->{model} ||= "Maypole::Model::CDBI";
     $config->{model}->require;
+    die "Couldn't load the model class $config->{model}: $@" if $@;
     $config->{model}->setup_database($config, $calling_class, @_);
     for my $subclass (@{$config->{classes}}) {
         no strict 'refs';
@@ -42,6 +40,7 @@ sub init {
     my $config = $class->config;
     $config->{view}  ||= "Maypole::View::TT";
     $config->{view}->require;
+    die "Couldn't load the view class $config->{view}: $@" if $@;
     $config->{display_tables} ||= [ @{$class->config->{tables}} ];
     $class->view_object($class->config->{view}->new);
     $class->init_done(1);
@@ -55,38 +54,45 @@ sub handler {
     my $r = bless { config => $class->config }, $class;
     $r->get_request();
     $r->parse_location();
+    my $status = $r->handler_guts();
+    return $status unless $status == OK;
+    $r->send_output;
+    return $status;
+}
 
+sub handler_guts {
+    my $r = shift;
     $r->model_class($r->config->{model}->class_of($r, $r->{table}));
-    my $status = $r->is_applicable;
-    if ($status == OK) { 
-        $status = $r->call_authenticate;
-        if ($r->debug and $status != OK and $status != DECLINED) {
-            $r->view_object->error($r,
-                "Got unexpected status $status from calling authentication");
-        }
-        return $status unless $status == OK;
-        $r->additional_data();
-    
-        $r->model_class->process($r);
-    } else { 
-        # Otherwise, it's just a plain template.
-        $r->call_authenticate; # No harm in it
+    my $applicable = $r->is_applicable;
+    unless ($applicable == OK) {
+        # It's just a plain template
         delete $r->{model_class};
         $r->{path} =~ s{/}{}; # De-absolutify
         $r->template($r->{path});
     }
-    $status = OK;
-    if (!$r->{output}) { # You might want to do it yourself
-        $status = $r->view_object->process($r);
+    # We authenticate every request, needed for proper session management
+    my $status = $r->call_authenticate;
+    if ($r->debug and $status != OK and $status != DECLINED) {
+        $r->view_object->error($r,
+            "Got unexpected status $status from calling authentication");
     }
-    $r->send_output;
-    return $status;
+    return $status unless $status == OK;
+    # We run additional_data for every request
+    $r->additional_data;
+    if ($applicable == OK) {
+        $r->model_class->process($r);
+    }
+    if (!$r->{output}) { # You might want to do it yourself
+        return $r->view_object->process($r);
+    } else { return OK; }
 }
 
 sub is_applicable {
     my $self = shift;
     my $config = $self->config;
-    $config->{ok_tables} = {map {$_ => 1} @{$config->{display_tables}}};
+    $config->{ok_tables} ||= $config->{display_tables};
+    $config->{ok_tables} = {map {$_=>1} @{$config->{ok_tables}}}
+       if ref $config->{ok_tables} eq "ARRAY";
     warn "We don't have that table ($self->{table})"
         if $self->debug and not $config->{ok_tables}{$self->{table}};
     return DECLINED() unless exists $config->{ok_tables}{$self->{table}};
@@ -107,8 +113,11 @@ sub is_applicable {
 
 sub call_authenticate {
     my $self = shift;
-    return $self->model_class->authenticate($self) if 
-        $self->model_class->can("authenticate"); 
+    # Check if we have a model class
+    if ($self->{model_class}) {
+        return $self->model_class->authenticate($self) if 
+            $self->model_class->can("authenticate"); 
+    }
     return $self->authenticate($self); # Interface consistency is a Good Thing
 }
 
@@ -116,6 +125,16 @@ sub additional_data {}
 
 sub authenticate { return OK }
 
+sub parse_path {
+    my $self = shift;
+    $self->{path} ||= "frontpage";
+    my @pi = split /\//, $self->{path};
+    shift @pi while @pi and !$pi[0];
+    $self->{table} = shift @pi;
+    $self->{action} = shift @pi;
+    $self->{args} = \@pi;
+}
+
 =head1 NAME
 
 Maypole - MVC web application framework
@@ -208,7 +227,7 @@ subclass the model class, and configure your class slightly differently:
 Then your top-level application package should change the model class:
 (Before calling C<setup>)
 
-    ProductDatabase->config->{model_class} = "ProductDatabase::Model";
+    ProductDatabase->config->{model} = "ProductDatabase::Model";
 
 (The C<:Exported> attribute means that the method can be called via the
 URL C</I<table>/supersearch/...>.)
@@ -231,7 +250,8 @@ introduction to the process we're trying to automate.
 You should probably not use Maypole directly. Maypole is an abstract
 class which does not specify how to communicate with the outside world.
 The most popular subclass of Maypole is L<Apache::MVC>, which interfaces
-the Maypole framework to Apache mod_perl.
+the Maypole framework to Apache mod_perl; another important one is
+L<CGI::Maypole>.
 
 If you are implementing Maypole subclasses, you need to provide at least
 the C<parse_location> and C<send_output> methods. You may also want to
@@ -245,10 +265,26 @@ sub get_request { }
 sub parse_location { die "Do not use Maypole directly; use Apache::MVC or similar" }
 sub send_output{ die "Do not use Maypole directly; use Apache::MVC or similar" }
 
+=head1 SEE ALSO
+
+There's more documentation, examples, and a wiki at the Maypole web site:
+
+http://maypole.simon-cozens.org/
+
+L<Apache::MVC>, L<CGI::Maypole>.
+
+=head1 MAINTAINER
+
+Sebastian Riedel, c<sri@oook.de>
+
 =head1 AUTHOR
 
 Simon Cozens, C<simon@cpan.org>
 
+=head1 THANK YOU
+
+Jesse Scheildlower, Jody Belka, Markus Ramberg, Mickael Joanne, Simon Flack and all the others who've helped.
+
 =head1 LICENSE
 
 You may distribute this code under the same terms as Perl itself.
@@ -256,4 +292,3 @@ You may distribute this code under the same terms as Perl itself.
 =cut
 
 1;
-