]> git.decadent.org.uk Git - maypole.git/blobdiff - lib/Maypole.pm
fixes to url tests to handle ordering of arguments and to fix horrid code in tests
[maypole.git] / lib / Maypole.pm
index 858c1eb608aa1dfa264b5e1206dedbad78399e9a..0d0250dfcbde82a88953658dab393326a57504dc 100644 (file)
@@ -12,7 +12,7 @@ use URI::QueryParam;
 use NEXT;
 use File::MMagic::XS qw(:compat);
 
-our $VERSION = '2.11';
+our $VERSION = '2.11_pre4';
 our $mmagic = File::MMagic::XS->new();
 
 # proposed privacy conventions:
@@ -275,7 +275,7 @@ documentation. However here is the most usage of setup where
 Maypole::Model::CDBI is the base class.
 
  My::App->setup($data_source, $user, $password,
-       {  opitons => {  # These are DB connection options
+       {  options => {  # These are DB connection options
                AutoCommit => 0,
                RaiseError => 1,
                ...
@@ -401,11 +401,16 @@ Constructs a very minimal new Maypole request object.
 sub new
 {
     my ($class) = @_;
-    
     my $self = bless {
-        template_args => {},
         config        => $class->config,
     }, $class;
+
+       $self->stash({});
+       $self->params({});
+       $self->query({});
+       $self->template_args({});
+       $self->args([]);
+       $self->objects([]);
     
     return $self;
 }
@@ -453,20 +458,14 @@ sub handler : method  {
   $self->status(Maypole::Constants::OK()); # set the default
   $self->__call_hook('start_request_hook');
   return $self->status unless $self->status == Maypole::Constants::OK();
-    
   die "status undefined after start_request_hook()" unless defined
     $self->status;
-    
   $self->get_session;
   $self->get_user;
-    
   my $status = $self->handler_guts;
-
   return $status unless $status == OK;
-
   # TODO: require send_output to return a status code
   $self->send_output;
-
   return $status;
 }
 
@@ -481,18 +480,31 @@ request. You'll need to set up actions and templates
 which return fragments of HTML rather than entire pages, but once you've
 done that, you can use the C<component> method of the Maypole request object
 to call those actions. You may pass a query string in the usual URL style.
+
 You should not fully qualify the Maypole URLs.
 
+Note: any HTTP POST or URL parameters passed to the parent are not passed to the
+component sub-request, only what is included in the url passed as an argyument
+to the method
+
 =cut
 
 sub component {
     my ( $r, $path ) = @_;
-    my $self = bless { parent => $r }, ref $r;
+    my $self = bless { parent => $r, config => $r->{config}, } , ref $r;
+       $self->stash({});
+       $self->params({});
+       $self->query({});
+       $self->template_args({});
+       $self->args([]);
+       $self->objects([]);
+
+    $self->get_user;
     my $url = URI->new($path);
+    warn "path : $path\n";
     $self->{path} = $url->path;
     $self->parse_path;
     $self->params( $url->query_form_hash );
-    $self->query( $r->params );
     $self->handler_guts;
     return $self->output;
 }
@@ -562,18 +574,13 @@ sub handler_guts
 
     my $applicable = $self->is_model_applicable == OK;
 
-    warn "applicable : $applicable";
-
-    $self->__setup_plain_template unless $applicable;
-
     my $status;
 
+    # handle authentication
     eval { $status = $self->call_authenticate };
-    
     if ( my $error = $@ ) 
     {
         $status = $self->call_exception($error, "authentication");
-        
         if ( $status != OK ) 
         {
             warn "caught authenticate error: $error";
@@ -581,7 +588,6 @@ sub handler_guts
                     $self->view_object->error($self, $error) : ERROR;
         }
     }
-    
     if ( $self->debug and $status != OK and $status != DECLINED ) 
     {
         $self->view_object->error( $self,
@@ -592,40 +598,32 @@ sub handler_guts
 
     # We run additional_data for every request
     $self->additional_data;
-    
-    if ($applicable) 
-    {
-        eval { $self->model_class->process($self) };
-        
-        if ( my $error = $@ ) 
+
+    if ($applicable) {
+      eval { $self->model_class->process($self) };
+      if ( my $error = $@ ) 
         {
-            $status = $self->call_exception($error, "model");
-            
-            if ( $status != OK ) 
+         $status = $self->call_exception($error, "model");
+         if ( $status != OK )
             {
-                warn "caught model error: $error";
-                return $self->debug ? 
-                    $self->view_object->error($self, $error) : ERROR;
+             warn "caught model error: $error";
+             return $self->debug ? 
+               $self->view_object->error($self, $error) : ERROR;
             }
         }
+    } else {
+      $self->__setup_plain_template;
     }
-    
+
     # less frequent path - perhaps output has been set to an error message
     return OK if $self->output;
-#    warn "output before processing view : ", $self->output;
 
     # normal path - no output has been generated yet
     my $processed_view_ok = $self->__call_process_view;
 
-    warn "output after processing view : ", $self->output;
-
-    warn "error after processing view : ", $self->{error};
-
     $self->{content_type}      ||= $self->__get_mime_type();
     $self->{document_encoding} ||= "utf-8";
 
-    warn "made it to end, processed_view_ok : $processed_view_ok";
 
     return $processed_view_ok;
 }
@@ -654,16 +652,24 @@ sub __get_mime_type {
 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. 
 sub __setup_plain_template
 {
     my ($self) = @_;
-    
+
     # It's just a plain template
     $self->model_class(undef);
     
@@ -930,7 +936,7 @@ processed.
 
 sub exception { 
     my ($self, $error, $when) = @_;
-    if ($self->view_object->can("report_error") and $self->debug) {
+    if (ref $self->view_object && $self->view_object->can("report_error") and $self->debug) {
         $self->view_object->report_error($self, $error, $when);
         return OK;
     }
@@ -957,8 +963,6 @@ sub send_output {
 }
 
 
-
-
 =back
 
 =head2 Path processing and manipulation
@@ -979,13 +983,12 @@ properties. Calls C<preprocess_path> before parsing path and setting properties.
 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');
 
@@ -1148,6 +1151,24 @@ If the first item in C<$self-E<gt>args> can be C<retrieve()>d by the model
 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';
@@ -1156,7 +1177,7 @@ Get/set a hash of template variables.
 
 =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