]> git.decadent.org.uk Git - maypole.git/blob - lib/Maypole.pm
tested and it seems to work
[maypole.git] / lib / Maypole.pm
1 package Maypole;
2 use base qw(Class::Accessor::Fast Class::Data::Inheritable);
3 use UNIVERSAL::require;
4 use strict;
5 use warnings;
6 use Data::Dumper;
7 use Maypole::Config;
8 use Maypole::Constants;
9 use Maypole::Headers;
10 use URI();
11 use URI::QueryParam;
12 use NEXT;
13 use File::MMagic::XS qw(:compat);
14
15 our $VERSION = '2.11';
16 our $mmagic = File::MMagic::XS->new();
17
18 # proposed privacy conventions:
19 # - no leading underscore     - public to custom application code and plugins
20 # - single leading underscore - private to the main Maypole stack - *not*
21 #     including plugins
22 # - double leading underscore - private to the current package
23
24 =head1 NAME
25
26 Maypole - MVC web application framework
27
28 =head1 SYNOPSIS
29
30 The canonical example used in the Maypole documentation is the beer database:
31
32     package BeerDB;
33     use strict;
34     use warnings; 
35     
36     # choose a frontend, initialise the config object, and load a plugin
37     use Maypole::Application qw/Relationship/;
38
39     # set everything up
40     __PACKAGE__->setup("dbi:SQLite:t/beerdb.db");
41     
42     # get the empty config object created by Maypole::Application
43     my $config = __PACKAGE__->config;
44     
45     # basic settings
46     $config->uri_base("http://localhost/beerdb");
47     $config->template_root("/path/to/templates");
48     $config->rows_per_page(10);
49     $config->display_tables([qw/beer brewery pub style/]);
50
51     # table relationships
52     $config->relationships([
53         "a brewery produces beers",
54         "a style defines beers",
55         "a pub has beers on handpumps",
56         ]);
57         
58     # validation
59     BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
60     BeerDB::Pub->untaint_columns( printable => [qw/name notes url/] );
61     BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
62     BeerDB::Beer->untaint_columns(
63         printable => [qw/abv name price notes/],
64         integer => [qw/style brewery score/],
65         date => [ qw/date/],
66     );
67
68     # note : set up model before calling this method
69     BeerDB::Beer->required_columns([qw/name/]); 
70
71     1;    
72
73 =head1 DESCRIPTION
74
75 This documents the Maypole request object. See the L<Maypole::Manual>, for a
76 detailed guide to using Maypole.
77
78 Maypole is a Perl web application framework similar to Java's struts. It is 
79 essentially completely abstracted, and so doesn't know anything about
80 how to talk to the outside world.
81
82 To use it, you need to create a driver package which represents your entire
83 application. This is the C<BeerDB> package used as an example in the manual.
84
85 This needs to first use L<Maypole::Application> which will make your package
86 inherit from the appropriate platform driver such as C<Apache::MVC> or
87 C<CGI::Maypole>. Then, the driver calls C<setup>. This sets up the model classes
88 and configures your application. The default model class for Maypole uses
89 L<Class::DBI> to map a database to classes, but this can be changed by altering
90 configuration (B<before> calling setup.)
91
92
93 =head1 DOCUMENTATION AND SUPPORT
94
95 Note that some details in some of these resources may be out of date.
96
97 =over 4
98
99 =item The Maypole Manual
100
101 The primary documentation is the Maypole manual. This lives in the 
102 C<Maypole::Manual> pod documents included with the distribution. 
103
104 =item Embedded POD
105
106 Individual packages within the distribution contain (more or less) detailed
107 reference documentation for their API.
108
109 =item Mailing lists
110
111 There are two mailing lists - maypole-devel and maypole-users - see
112 http://maypole.perl.org/?MailingList
113
114 =item The Maypole Wiki
115
116 The Maypole wiki provides a useful store of extra documentation -
117 http://maypole.perl.org
118
119 In particular, there's a FAQ (http://maypole.perl.org/?FAQ) and a cookbook
120 (http://maypole.perl.org/?Cookbook). Again, certain information on these pages
121 may be out of date.
122
123 =item Web applications with Maypole
124
125 A tutorial written by Simon Cozens for YAPC::EU 2005 -
126 http://www.aarontrevena.co.uk/opensource/maypole/maypole-tutorial.pdf [228KB].
127
128 =item A Database-Driven Web Application in 18 Lines of Code
129
130 By Paul Barry, published in Linux Journal, March 2005.
131
132 http://www.linuxjournal.com/article/7937
133
134 "From zero to Web-based database application in eight easy steps".
135
136 Maypole won a 2005 Linux Journal Editor's Choice Award
137 (http://www.linuxjournal.com/article/8293) after featuring in this article. 
138
139 =item Build Web apps with Maypole
140
141 By Simon Cozens, on IBM's DeveloperWorks website, May 2004.
142
143 http://www-128.ibm.com/developerworks/linux/library/l-maypole/
144
145 =item Rapid Web Application Deployment with Maypole
146
147 By Simon Cozens, on O'Reilly's Perl website, April 2004.
148
149 http://www.perl.com/pub/a/2004/04/15/maypole.html
150
151 =item Authentication
152
153 Some notes written by Simon Cozens. A little bit out of date, but still 
154 very useful: http://www.aarontrevena.co.uk/opensource/maypole/authentication.html
155
156 =item CheatSheet
157
158 There's a refcard for the Maypole (and Class::DBI) APIs on the wiki -
159 http://maypole.perl.org/?CheatSheet. Probably a little out of date now - it's a
160 wiki, so feel free to fix any errors!
161
162 =item Plugins and add-ons
163
164 There are a large and growing number of plugins and other add-on modules
165 available on CPAN - http://search.cpan.org/search?query=maypole&mode=module
166
167 =item del.icio.us
168
169 You can find a range of useful Maypole links, particularly to several thoughtful
170 blog entries, starting here: http://del.icio.us/search/?all=maypole
171
172 =item CPAN ratings
173
174 There are a couple of short reviews here:
175 http://cpanratings.perl.org/dist/Maypole
176
177 =back
178
179 =cut
180
181 __PACKAGE__->mk_classdata($_) for qw( config init_done view_object model_classes_loaded);
182
183 __PACKAGE__->mk_accessors(
184     qw( params query objects model_class template_args output path
185         args action template error document_encoding content_type table
186         headers_in headers_out stash status parent)
187 );
188
189 __PACKAGE__->config( Maypole::Config->new() );
190
191 __PACKAGE__->init_done(0);
192
193 __PACKAGE__->model_classes_loaded(0);
194
195 =head1 HOOKABLE METHODS
196
197 As a framework, Maypole provides a number of B<hooks> - methods that are
198 intended to be overridden. Some of these methods come with useful default
199 behaviour, others do nothing by default. Hooks include:
200
201     Class methods
202     -------------
203     debug 
204     setup 
205     setup_model 
206     load_model_subclass
207     init
208     
209     Instance methods
210     ----------------
211     start_request_hook
212     is_model_applicable
213     get_session
214     authenticate
215     exception
216     additional_data
217     preprocess_path
218
219 =head1 CLASS METHODS
220
221 =over 4
222
223 =item debug
224
225     sub My::App::debug {1}
226
227 Returns the debugging flag. Override this in your application class to
228 enable/disable debugging.
229
230 You can also set the C<debug> flag via L<Maypole::Application>.
231
232 Some packages respond to higher debug levels, try increasing it to 2 or 3.
233
234
235 =cut
236
237 sub debug { 0 }
238
239 =item config
240
241 Returns the L<Maypole::Config> object
242
243 =item setup
244
245    My::App->setup($data_source, $user, $password, \%attr);
246
247 Initialise the Maypole application and plugins and model classes.
248 Your application should call this B<after> setting up configuration data via
249 L<"config">.
250
251 It calls the hook  C<setup_model> to setup the model. The %attr hash contains
252 options and arguments used to set up the model. See the particular model's
253 documentation. However here is the most usage of setup where
254 Maypole::Model::CDBI is the base class.
255
256  My::App->setup($data_source, $user, $password,
257        {  options => {  # These are DB connection options
258                AutoCommit => 0,
259                RaiseError => 1,
260                ...
261           },
262           # These are Class::DBI::Loader arguments.
263           relationships  => 1,
264           ...
265        }
266  );
267
268 Also, see  L<Maypole::Manual::Plugins>.
269
270 =cut
271
272
273 sub setup
274 {
275     my $class = shift;
276     
277     $class->setup_model(@_);    
278 }
279
280 =item setup_model
281
282 Called by C<setup>. This method builds the Maypole model hierarchy. 
283
284 A likely target for over-riding, if you need to build a customised model.
285
286 This method also ensures any code in custom model classes is loaded, so you
287 don't need to load them in the driver.
288
289 =cut
290
291 sub setup_model {
292   my $class = shift;
293   $class = ref $class if ref $class;
294   my $config = $class->config;
295   $config->model || $config->model('Maypole::Model::CDBI');
296   $config->model->require or die sprintf
297     "Couldn't load the model class %s: %s", $config->model, $@;
298
299   # among other things, this populates $config->classes
300   $config->model->setup_database($config, $class, @_);
301
302   foreach my $subclass ( @{ $config->classes } ) {
303     next if $subclass->isa("Maypole::Model::Base");
304     no strict 'refs';
305     unshift @{ $subclass . "::ISA" }, $config->model;
306   }
307
308   # Load custom model code, if it exists - nb this must happen after the
309   # unshift, to allow code attributes to work, but before adopt(),
310   # in case adopt() calls overridden methods on $subclass
311   foreach my $subclass ( @{ $config->classes } ) {
312     $class->load_model_subclass($subclass) unless ($class->model_classes_loaded());
313     $config->model->adopt($subclass) if $config->model->can("adopt");
314   }
315
316 }
317
318 =item load_model_subclass($subclass)
319
320 This method is called from C<setup_model()>. It attempts to load the
321 C<$subclass> package, if one exists. So if you make a customized C<BeerDB::Beer>
322 package, you don't need to explicitly load it. 
323
324 If automatic loading causes problems, Override load_model_subclass in your driver.
325
326 sub load_model_subclass {};
327
328 Or perhaps during development, if you don't want to load up custom classes, you 
329 can override this method and load them manually. 
330
331 =cut
332
333 sub load_model_subclass {
334   my ($class, $subclass) = @_;
335
336   my $config = $class->config;
337
338   # Load any external files for the model base class or subclasses
339   # (e.g. BeerDB/DBI.pm or BeerDB/Beer.pm) based on code borrowed from
340   # Maypole::Plugin::Loader and Class::DBI.
341   if ( $subclass->require ) {
342     warn "Loaded external module for '$subclass'\n" if $class->debug > 1;
343   } else {
344     (my $filename = $subclass) =~ s!::!/!g;
345     die "Loading '$subclass' failed: $@\n"
346       unless $@ =~ /Can\'t locate \Q$filename\E\.pm/;
347     warn "No external module for '$subclass'"
348       if $class->debug > 1;
349   }
350 }
351
352 =item init
353
354 Loads the view class and instantiates the view object.
355
356 You should not call this directly, but you may wish to override this to add
357 application-specific initialisation - see L<Maypole::Manual::Plugins>.
358
359 =cut
360
361 sub init 
362 {
363     my $class  = shift;
364     my $config = $class->config;
365     $config->view || $config->view("Maypole::View::TT");
366     $config->view->require;
367     die "Couldn't load the view class " . $config->view . ": $@" if $@;
368     $config->display_tables
369       || $config->display_tables( $class->config->tables );
370     $class->view_object( $class->config->view->new );
371     $class->init_done(1);
372 }
373
374 =item new
375
376 Constructs a very minimal new Maypole request object.
377
378 =cut
379
380 sub new
381 {
382     my ($class) = @_;
383     my $self = bless {
384         config        => $class->config,
385     }, $class;
386
387         $self->stash({});
388         $self->params({});
389         $self->query({});
390         $self->template_args({});
391         $self->args([]);
392         $self->objects([]);
393     
394     return $self;
395 }
396
397 =item view_object
398
399 Get/set the Maypole::View object
400
401 =back
402
403 =head1 INSTANCE METHODS
404
405 =head2 Workflow
406
407 =over 4
408
409 =item handler
410
411 This method sets up the class if it's not done yet, sets some defaults and
412 leaves the dirty work to C<handler_guts>.
413
414 =cut
415
416 # handler() has a method attribute so that mod_perl will invoke
417 # BeerDB->handler() as a method rather than a plain function
418 # BeerDB::handler() and so this inherited implementation will be
419 # found. See e.g. "Practical mod_perl" by Bekman & Cholet for
420 # more information <http://modperlbook.org/html/ch25_01.html>
421 sub handler : method  {
422   # See Maypole::Workflow before trying to understand this.
423   my ($class, $req) = @_;
424     
425   $class->init unless $class->init_done;
426
427   my $self = $class->new;
428     
429   # initialise the request
430   $self->headers_out(Maypole::Headers->new);
431   $self->get_request($req);
432
433   $self->parse_location;
434
435   # hook useful for declining static requests e.g. images, or perhaps for 
436   # sanitizing request parameters
437   $self->status(Maypole::Constants::OK()); # set the default
438   $self->__call_hook('start_request_hook');
439   return $self->status unless $self->status == Maypole::Constants::OK();
440   die "status undefined after start_request_hook()" unless defined
441     $self->status;
442   $self->get_session;
443   $self->get_user;
444   my $status = $self->handler_guts;
445   return $status unless $status == OK;
446   # TODO: require send_output to return a status code
447   $self->send_output;
448   return $status;
449 }
450
451 =item component
452
453   Run Maypole sub-requests as a component of the request
454
455   [% request.component("/beer/view_as_component/20") %]
456
457   Allows you to integrate the results of a Maypole request into an existing
458 request. You'll need to set up actions and templates
459 which return fragments of HTML rather than entire pages, but once you've
460 done that, you can use the C<component> method of the Maypole request object
461 to call those actions. You may pass a query string in the usual URL style.
462
463 You should not fully qualify the Maypole URLs.
464
465 Note: any HTTP POST or URL parameters passed to the parent are not passed to the
466 component sub-request, only what is included in the url passed as an argyument
467 to the method
468
469 =cut
470
471 sub component {
472     my ( $r, $path ) = @_;
473     my $self = bless { parent => $r, config => $r->{config}, } , ref $r;
474         $self->stash({});
475         $self->params({});
476         $self->query({});
477         $self->template_args({});
478         $self->args([]);
479         $self->objects([]);
480
481     $self->get_user;
482     my $url = URI->new($path);
483     warn "path : $path\n";
484     $self->{path} = $url->path;
485     $self->parse_path;
486     $self->params( $url->query_form_hash );
487     $self->handler_guts;
488     return $self->output;
489 }
490
491 sub get_template_root {
492     my $self = shift;
493     my $r    = shift;
494     return $r->parent->get_template_root if $r->{parent};
495     return $self->NEXT::DISTINCT::get_template_root( $r, @_ );
496 }
497
498 sub view_object {
499     my $self = shift;
500     my $r    = shift;
501     return $r->parent->view_object if $r->{parent};
502     return $self->NEXT::DISTINCT::view_object( $r, @_ );
503 }
504
505 # Instead of making plugin authors use the NEXT::DISTINCT hoopla to ensure other 
506 # plugins also get to call the hook, we can cycle through the application's 
507 # @ISA and call them all here. Doesn't work for setup() though, because it's 
508 # too ingrained in the stack. We could add a run_setup() method, but we'd break 
509 # lots of existing code.
510 sub __call_hook
511 {
512     my ($self, $hook) = @_;
513     
514     my @plugins;
515     {
516         my $class = ref($self);
517         no strict 'refs';
518         @plugins = @{"$class\::ISA"};
519     }
520     
521     # this is either a custom method in the driver, or the method in the 1st 
522     # plugin, or the 'null' method in the frontend (i.e. inherited from 
523     # Maypole.pm) - we need to be careful to only call it once
524     my $first_hook = $self->can($hook);
525     $self->$first_hook;  
526     
527     my %seen = ( $first_hook => 1 );
528
529     # @plugins includes the frontend
530     foreach my $plugin (@plugins)
531     {
532         next unless my $plugin_hook = $plugin->can($hook);
533         next if $seen{$plugin_hook}++;
534         $self->$plugin_hook;
535     }
536 }
537
538 =item handler_guts
539
540 This is the main request handling method and calls various methods to handle the
541 request/response and defines the workflow within Maypole.
542
543 B<Currently undocumented and liable to be refactored without warning>.
544
545 =cut
546
547 # The root of all evil
548 sub handler_guts 
549 {
550     my ($self) = @_;
551     
552     $self->__load_request_model;
553
554     my $applicable = $self->is_model_applicable == OK;
555
556     my $status;
557
558     # handle authentication
559     eval { $status = $self->call_authenticate };
560     if ( my $error = $@ ) 
561     {
562         $status = $self->call_exception($error, "authentication");
563         if ( $status != OK ) 
564         {
565             warn "caught authenticate error: $error";
566             return $self->debug ? 
567                     $self->view_object->error($self, $error) : ERROR;
568         }
569     }
570     if ( $self->debug and $status != OK and $status != DECLINED ) 
571     {
572         $self->view_object->error( $self,
573             "Got unexpected status $status from calling authentication" );
574     }
575
576     return $status unless $status == OK;
577
578     # We run additional_data for every request
579     $self->additional_data;
580
581     if ($applicable) {
582       eval { $self->model_class->process($self) };
583       if ( my $error = $@ ) 
584         {
585           $status = $self->call_exception($error, "model");
586           if ( $status != OK )
587             {
588               warn "caught model error: $error";
589               return $self->debug ? 
590                 $self->view_object->error($self, $error) : ERROR;
591             }
592         }
593     } else {
594       $self->__setup_plain_template;
595     }
596
597     # less frequent path - perhaps output has been set to an error message
598     return OK if $self->output;
599
600     # normal path - no output has been generated yet
601     my $processed_view_ok = $self->__call_process_view;
602
603     $self->{content_type}      ||= $self->__get_mime_type();
604     $self->{document_encoding} ||= "utf-8";
605
606
607     return $processed_view_ok;
608 }
609
610 my %filetypes = (
611                  'js' => 'text/javascript',
612                  'css' => 'text/css',
613                  'htm' => 'text/html',
614                  'html' => 'text/html',
615                 );
616
617 sub __get_mime_type {
618   my $self = shift;
619   my $type = 'text/html';
620   if ($self->path =~ m/.*\.(\w{3,4})$/) {
621     $type = $filetypes{$1};
622   } else {
623     my $output = $self->output;
624     if (defined $output) {
625       $type = $mmagic->checktype_contents($output);
626     }
627   }
628   return $type;
629 }
630
631 sub __load_request_model
632 {
633     my ($self) = @_;
634         # We may get a made up class from class_of
635     my $mclass = $self->config->model->class_of($self, $self->table);
636     if ( eval {$mclass->isa('Maypole::Model::Base')} ) {
637         $self->model_class( $mclass );
638     }
639     elsif ($self->debug) {
640       warn "***Warning:  No $mclass class appropriate for model. @_"; 
641     }
642 }
643
644
645 # is_applicable() returned false, so set up a plain template. Model processing 
646 # will be skipped, but need to remove the model anyway so the template can't 
647 # access it. 
648 sub __setup_plain_template
649 {
650     my ($self) = @_;
651
652     # It's just a plain template
653     $self->model_class(undef);
654     
655     my $path = $self->path;
656     $path =~ s{/$}{};    # De-absolutify
657     $self->path($path);
658     
659     $self->template($self->path);
660 }
661
662 # The model has been processed or skipped (if is_applicable returned false), 
663 # any exceptions have been handled, and there's no content in $self->output
664 sub __call_process_view {
665   my ($self) = @_;
666
667   my $status = eval { $self->view_object->process($self) };
668
669   my $error = $@ || $self->{error};
670
671   if ( $error ) {
672     $status = $self->call_exception($error, "view");
673
674     if ( $status != OK ) {
675       warn "caught view error: $error" if $self->debug;
676       return $self->debug ? 
677         $self->view_object->error($self, $error) : ERROR;
678     }
679   }
680
681   return $status;
682 }
683
684 =item get_request
685
686 You should only need to define this method if you are writing a new
687 Maypole backend. It should return something that looks like an Apache
688 or CGI request object, it defaults to blank.
689
690 =cut
691
692 sub get_request { }
693
694 =item parse_location
695
696 Turns the backend request (e.g. Apache::MVC, Maypole, CGI) into a Maypole
697 request. It does this by setting the C<path>, and invoking C<parse_path> and
698 C<parse_args>.
699
700 You should only need to define this method if you are writing a new Maypole
701 backend.
702
703 =cut
704
705 sub parse_location 
706 {
707     die "parse_location is a virtual method. Do not use Maypole directly; " . 
708                 "use Apache::MVC or similar";
709 }
710
711 =item start_request_hook
712
713 This is called immediately after setting up the basic request. The default
714 method does nothing. 
715
716 The value of C<< $r->status >> is set to C<OK> before this hook is run. Your 
717 implementation can change the status code, or leave it alone. 
718
719 After this hook has run, Maypole will check the value of C<status>. For any
720 value other than C<OK>, Maypole returns the C<status> immediately. 
721
722 This is useful for filtering out requests for static files, e.g. images, which
723 should not be processed by Maypole or by the templating engine:
724
725     sub start_request_hook
726     {
727         my ($r) = @_;
728         
729         $r->status(DECLINED) if $r->path =~ /\.jpg$/;
730     }
731     
732 Multiple plugins, and the driver, can define this hook - Maypole will call all
733 of them. You should check for and probably not change any non-OK C<status>
734 value:
735
736     package Maypole::Plugin::MyApp::SkipFavicon;
737     
738     sub start_request_hook
739     {
740         my ($r) = @_;
741         
742         # check if a previous plugin has already DECLINED this request
743         # - probably unnecessary in this example, but you get the idea
744         return unless $r->status == OK;
745         
746         # then do our stuff
747         $r->status(DECLINED) if $r->path =~ /favicon\.ico/;
748     }        
749      
750 =cut
751
752 sub start_request_hook { }
753
754 =item is_applicable
755
756 B<This method is deprecated> as of version 2.11. If you have overridden it,
757 please override C<is_model_applicable> instead, and change the return type
758 from a Maypole:Constant to a true/false value.
759
760 Returns a Maypole::Constant to indicate whether the request is valid.
761
762 =cut
763
764 sub is_applicable { return shift->is_model_applicable(@_); }
765
766 =item is_model_applicable
767
768 Returns true or false to indicate whether the request is valid.
769
770 The default implementation checks that C<< $r->table >> is publicly
771 accessible and that the model class is configured to handle the
772 C<< $r->action >>.
773
774 =cut
775
776 sub is_model_applicable {
777     my ($self) = @_;
778
779     # Establish which tables should be processed by the model
780     my $config = $self->config;
781     
782     $config->ok_tables || $config->ok_tables( $config->display_tables );
783     
784     $config->ok_tables( { map { $_ => 1 } @{ $config->ok_tables } } )
785         if ref $config->ok_tables eq "ARRAY";
786         
787     my $ok_tables = $config->ok_tables;
788       
789     # Does this request concern a table to be processed by the model?
790     my $table = $self->table;
791     
792     my $ok = 0;
793     
794     if (exists $ok_tables->{$table}) 
795     {
796         $ok = 1;
797     } 
798
799     if (not $ok) 
800     {
801         warn "We don't have that table ($table).\n"
802             . "Available tables are: "
803             . join( ",", keys %$ok_tables )
804                 if $self->debug and not $ok_tables->{$table};
805                 
806         return DECLINED;
807     }
808     
809     # Is the action public?
810     my $action = $self->action;
811     return OK if $self->model_class->is_public($action);
812     
813     warn "The action '$action' is not applicable to the table '$table'"
814          if $self->debug;
815     
816     return DECLINED;
817 }
818
819 =item get_session
820
821 Called immediately after C<start_request_hook()>.
822
823 This method should return a session, which will be stored in the request's
824 C<session> attribute.
825
826 The default method is empty. 
827
828 =cut
829
830 sub get_session { }
831
832 =item get_user
833
834 Called immediately after C<get_session>.
835
836 This method should return a user, which will be stored in the request's C<user>
837 attribute.
838
839 The default method is empty.
840
841 =cut
842
843 sub get_user {}
844
845 =item call_authenticate
846
847 This method first checks if the relevant model class
848 can authenticate the user, or falls back to the default
849 authenticate method of your Maypole application.
850
851 =cut
852
853 sub call_authenticate 
854 {
855     my ($self) = @_;
856
857     # Check if we have a model class with an authenticate() to delegate to
858     return $self->model_class->authenticate($self) 
859         if $self->model_class and $self->model_class->can('authenticate');
860     
861     # Interface consistency is a Good Thing - 
862     # the invocant and the argument may one day be different things 
863     # (i.e. controller and request), like they are when authenticate() 
864     # is called on a model class (i.e. model and request)
865     return $self->authenticate($self);   
866 }
867
868 =item authenticate
869
870 Returns a Maypole::Constant to indicate whether the user is authenticated for
871 the Maypole request.
872
873 The default implementation returns C<OK>
874
875 =cut
876
877 sub authenticate { return OK }
878
879
880 =item call_exception
881
882 This model is called to catch exceptions, first after authenticate, then after
883 processing the model class, and finally to check for exceptions from the view
884 class.
885
886 This method first checks if the relevant model class
887 can handle exceptions the user, or falls back to the default
888 exception method of your Maypole application.
889
890 =cut
891
892 sub call_exception 
893 {
894     my ($self, $error, $when) = @_;
895
896     # Check if we have a model class with an exception() to delegate to
897     if ( $self->model_class && $self->model_class->can('exception') )
898     {
899         my $status = $self->model_class->exception( $self, $error, $when );
900         return $status if $status == OK;
901     }
902     
903     return $self->exception($error, $when);
904 }
905
906
907 =item exception
908
909 This method is called if any exceptions are raised during the authentication or
910 model/view processing. It should accept the exception as a parameter and return
911 a Maypole::Constant to indicate whether the request should continue to be
912 processed.
913
914 =cut
915
916 sub exception { 
917     my ($self, $error, $when) = @_;
918     if (ref $self->view_object && $self->view_object->can("report_error") and $self->debug) {
919         $self->view_object->report_error($self, $error, $when);
920         return OK;
921     }
922     return ERROR;
923 }
924
925 =item additional_data
926
927 Called before the model processes the request, this method gives you a chance to
928 do some processing for each request, for example, manipulating C<template_args>.
929
930 =cut
931
932 sub additional_data { }
933
934 =item send_output
935
936 Sends the output and additional headers to the user.
937
938 =cut
939
940 sub send_output {
941     die "send_output is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
942 }
943
944
945 =back
946
947 =head2 Path processing and manipulation
948
949 =over 4
950
951 =item path
952
953 Returns the request path
954
955 =item parse_path
956
957 Parses the request path and sets the C<args>, C<action> and C<table>
958 properties. Calls C<preprocess_path> before parsing path and setting properties.
959
960 =cut
961
962 sub parse_path 
963 {
964     my ($self) = @_;
965
966     # Previous versions unconditionally set table, action and args to whatever 
967     # was in @pi (or else to defaults, if @pi is empty).
968     # Adding preprocess_path(), and then setting table, action and args 
969     # conditionally, broke lots of tests, hence this:
970     $self->$_(undef) for qw/action table args/;
971     $self->preprocess_path;
972     $self->path || $self->path('frontpage');
973
974     my @pi = grep {length} split '/', $self->path;
975
976
977     $self->table  || $self->table(shift @pi);
978     $self->action || $self->action( shift @pi or 'index' );
979     $self->args   || $self->args(\@pi);
980 }
981
982 =item preprocess_path
983
984 Sometimes when you don't want to rewrite or over-ride parse_path but
985 want to rewrite urls or extract data from them before it is parsed.
986
987 This method is called after parse_location has populated the request
988 information and before parse_path has populated the model and action
989 information, and is passed the request object.
990
991 You can set action, args or table in this method and parse_path will
992 then leave those values in place or populate them if not present
993
994 =cut
995
996 sub preprocess_path { };
997
998 =item make_path( %args or \%args or @args )
999
1000 This is the counterpart to C<parse_path>. It generates a path to use
1001 in links, form actions etc. To implement your own path scheme, just override
1002 this method and C<parse_path>.
1003
1004     %args = ( table      => $table,
1005               action     => $action,        
1006               additional => $additional,    # optional - generally an object ID
1007               );
1008               
1009     \%args = as above, but a ref
1010     
1011     @args = ( $table, $action, $additional );   # $additional is optional
1012
1013 C<id> can be used as an alternative key to C<additional>.
1014
1015 C<$additional> can be a string, an arrayref, or a hashref. An arrayref is
1016 expanded into extra path elements, whereas a hashref is translated into a query
1017 string. 
1018
1019 =cut
1020
1021 sub make_path
1022 {
1023     my $r = shift;
1024     
1025     my %args;
1026     
1027     if (@_ == 1 and ref $_[0] and ref $_[0] eq 'HASH')
1028     {
1029         %args = %{$_[0]};
1030     }
1031     elsif ( @_ > 1 and @_ < 4 )
1032     {
1033         $args{table}      = shift;
1034         $args{action}     = shift;
1035         $args{additional} = shift;
1036     }
1037     else
1038     {
1039         %args = @_;
1040     }
1041     
1042     do { die "no $_" unless $args{$_} } for qw( table action );    
1043
1044     my $additional = $args{additional} || $args{id};
1045     
1046     my @add = ();
1047     
1048     if ($additional)
1049     {
1050         # if $additional is a href, make_uri() will transform it into a query
1051         @add = (ref $additional eq 'ARRAY') ? @$additional : ($additional);
1052     }    
1053     
1054     my $uri = $r->make_uri($args{table}, $args{action}, @add);
1055     
1056     return $uri->as_string;
1057 }
1058
1059
1060
1061 =item make_uri( @segments )
1062
1063 Make a L<URI> object given table, action etc. Automatically adds
1064 the C<uri_base>. 
1065
1066 If the final element in C<@segments> is a hash ref, C<make_uri> will render it
1067 as a query string.
1068
1069 =cut
1070
1071 sub make_uri
1072 {
1073     my ($r, @segments) = @_;
1074
1075     my $query = (ref $segments[-1] eq 'HASH') ? pop(@segments) : undef;
1076     
1077     my $base = $r->config->uri_base; 
1078     $base =~ s|/$||;
1079     
1080     my $uri = URI->new($base);
1081     $uri->path_segments($uri->path_segments, grep {length} @segments);
1082     
1083     my $abs_uri = $uri->abs('/');
1084     $abs_uri->query_form($query) if $query;
1085     return $abs_uri;
1086 }
1087
1088 =item parse_args
1089
1090 Turns post data and query string paramaters into a hash of C<params>.
1091
1092 You should only need to define this method if you are writing a new Maypole
1093 backend.
1094
1095 =cut 
1096
1097 sub parse_args
1098 {
1099     die "parse_args() is a virtual method. Do not use Maypole directly; ".
1100             "use Apache::MVC or similar";
1101 }
1102
1103 =item get_template_root
1104
1105 Implementation-specific path to template root.
1106
1107 You should only need to define this method if you are writing a new Maypole
1108 backend. Otherwise, see L<Maypole::Config/"template_root">
1109
1110 =cut
1111
1112 =back
1113
1114 =head2 Request properties
1115
1116 =over 4
1117
1118 =item model_class
1119
1120 Returns the perl package name that will serve as the model for the
1121 request. It corresponds to the request C<table> attribute.
1122
1123
1124 =item objects
1125
1126 Get/set a list of model objects. The objects will be accessible in the view
1127 templates.
1128
1129 If the first item in C<$self-E<gt>args> can be C<retrieve()>d by the model
1130 class, it will be removed from C<args> and the retrieved object will be added to
1131 the C<objects> list. See L<Maypole::Model> for more information.
1132
1133
1134 =item object
1135
1136 Alias to get/set the first/only model object. The object will be accessible
1137 in the view templates.
1138
1139 When used to set the object, will overwrite the request objects
1140 with a single object.
1141
1142 =cut
1143
1144 sub object {
1145   my ($r,$object) = @_;
1146   $r->objects([$object]) if ($object);
1147   return undef unless $r->objects();
1148   return $r->objects->[0];
1149 }
1150
1151 =item template_args
1152
1153     $self->template_args->{foo} = 'bar';
1154
1155 Get/set a hash of template variables.
1156
1157 Maypole reserved words for template variables will over-ride values in template_variables.
1158
1159 Reserved words are : r, request, object, objects, base, config and errors, as well as the
1160 current class or object name.
1161
1162 =item stash
1163
1164 A place to put custom application data. Not used by Maypole itself.
1165
1166 =item template
1167
1168 Get/set the template to be used by the view. By default, it returns
1169 C<$self-E<gt>action>
1170
1171
1172 =item error
1173
1174 Get/set a request error
1175
1176 =item output
1177
1178 Get/set the response output. This is usually populated by the view class. You
1179 can skip view processing by setting the C<output>.
1180
1181 =item table
1182
1183 The table part of the Maypole request path
1184
1185 =item action
1186
1187 The action part of the Maypole request path
1188
1189 =item args
1190
1191 A list of remaining parts of the request path after table and action
1192 have been
1193 removed
1194
1195 =item headers_in
1196
1197 A L<Maypole::Headers> object containing HTTP headers for the request
1198
1199 =item headers_out
1200
1201 A L<HTTP::Headers> object that contains HTTP headers for the output
1202
1203 =item document_encoding
1204
1205 Get/set the output encoding. Default: utf-8.
1206
1207 =item content_type
1208
1209 Get/set the output content type. Default: text/html
1210
1211 =item get_protocol
1212
1213 Returns the protocol the request was made with, i.e. https
1214
1215 =cut
1216
1217 sub get_protocol {
1218   die "get_protocol is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
1219 }
1220
1221 =back
1222
1223 =head2 Request parameters
1224
1225 The source of the parameters may vary depending on the Maypole backend, but they
1226 are usually populated from request query string and POST data.
1227
1228 Maypole supplies several approaches for accessing the request parameters. Note
1229 that the current implementation (via a hashref) of C<query> and C<params> is
1230 likely to change in a future version of Maypole. So avoid direct access to these
1231 hashrefs:
1232
1233     $r->{params}->{foo}      # bad
1234     $r->params->{foo}        # better
1235
1236     $r->{query}->{foo}       # bad
1237     $r->query->{foo}         # better
1238
1239     $r->param('foo')         # best
1240
1241 =over 4
1242
1243 =item param
1244
1245 An accessor (get or set) for request parameters. It behaves similarly to
1246 CGI::param() for accessing CGI parameters, i.e.
1247
1248     $r->param                   # returns list of keys
1249     $r->param($key)             # returns value for $key
1250     $r->param($key => $value)   # returns old value, sets to new value
1251
1252 =cut
1253
1254 sub param 
1255
1256     my ($self, $key) = (shift, shift);
1257     
1258     return keys %{$self->params} unless defined $key;
1259     
1260     return unless exists $self->params->{$key};
1261     
1262     my $val = $self->params->{$key};
1263     
1264     if (@_)
1265     {
1266         my $new_val = shift;
1267         $self->params->{$key} = $new_val;
1268     }
1269     
1270     return ref $val ? @$val : ($val) if wantarray;
1271         
1272     return ref $val ? $val->[0] : $val;
1273 }
1274
1275
1276 =item params
1277
1278 Returns a hashref of request parameters. 
1279
1280 B<Note:> Where muliple values of a parameter were supplied, the C<params> value
1281 will be an array reference.
1282
1283 =item query
1284
1285 Alias for C<params>.
1286
1287 =back
1288
1289 =head3 Utility methods
1290
1291 =over 4
1292
1293 =item redirect_request
1294
1295 Sets output headers to redirect based on the arguments provided
1296
1297 Accepts either a single argument of the full url to redirect to, or a hash of
1298 named parameters :
1299
1300 $r->redirect_request('http://www.example.com/path');
1301
1302 or
1303
1304 $r->redirect_request(protocol=>'https', domain=>'www.example.com', path=>'/path/file?arguments', status=>'302', url=>'..');
1305
1306 The named parameters are protocol, domain, path, status and url
1307
1308 Only 1 named parameter is required but other than url, they can be combined as
1309 required and current values (from the request) will be used in place of any
1310 missing arguments. The url argument must be a full url including protocol and
1311 can only be combined with status.
1312
1313 =cut
1314
1315 sub redirect_request {
1316   die "redirect_request is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
1317 }
1318
1319 =item redirect_internal_request 
1320
1321 =cut
1322
1323 sub redirect_internal_request {
1324
1325 }
1326
1327
1328 =item make_random_id
1329
1330 returns a unique id for this request can be used to prevent or detect repeat
1331 submissions.
1332
1333 =cut
1334
1335 # Session and Repeat Submission Handling
1336 sub make_random_id {
1337     use Maypole::Session;
1338     return Maypole::Session::generate_unique_id();
1339 }
1340
1341 =back
1342
1343 =head1 SEQUENCE DIAGRAMS
1344
1345 See L<Maypole::Manual::Workflow> for a detailed discussion of the sequence of 
1346 calls during processing of a request. This is a brief summary:
1347
1348     INITIALIZATION
1349                                Model e.g.
1350          BeerDB           Maypole::Model::CDBI
1351            |                        |
1352    setup   |                        |
1353  o-------->||                       |
1354            || setup_model           |     setup_database() creates
1355            ||------+                |      a subclass of the Model
1356            |||<----+                |        for each table
1357            |||                      |                |
1358            |||   setup_database     |                |
1359            |||--------------------->|| 'create'      *
1360            |||                      ||----------> $subclass
1361            |||                      |                  |
1362            ||| load_model_subclass  |                  |
1363  foreach   |||------+  ($subclass)  |                  |
1364  $subclass ||||<----+               |    require       |
1365            ||||--------------------------------------->|
1366            |||                      |                  |
1367            |||   adopt($subclass)   |                  |
1368            |||--------------------->||                 |
1369            |                        |                  |
1370            |                        |                  |
1371            |-----+ init             |                  |
1372            ||<---+                  |                  |
1373            ||                       |     new          |     view_object: e.g.
1374            ||---------------------------------------------> Maypole::View::TT
1375            |                        |                  |          |
1376            |                        |                  |          |
1377            |                        |                  |          |
1378            |                        |                  |          |
1379            |                        |                  |          |
1380            
1381
1382
1383     HANDLING A REQUEST
1384
1385
1386           BeerDB                                Model  $subclass  view_object
1387             |                                      |       |         |
1388     handler |                                      |       |         |
1389   o-------->| new                                  |       |         |
1390             |-----> r:BeerDB                       |       |         |
1391             |         |                            |       |         |
1392             |         |                            |       |         |
1393             |         ||                           |       |         |
1394             |         ||-----+ parse_location      |       |         |
1395             |         |||<---+                     |       |         |
1396             |         ||                           |       |         |
1397             |         ||-----+ start_request_hook  |       |         |
1398             |         |||<---+                     |       |         |
1399             |         ||                           |       |         |
1400             |         ||-----+ get_session         |       |         |
1401             |         |||<---+                     |       |         |
1402             |         ||                           |       |         |
1403             |         ||-----+ get_user            |       |         |
1404             |         |||<---+                     |       |         |
1405             |         ||                           |       |         |
1406             |         ||-----+ handler_guts        |       |         |
1407             |         |||<---+                     |       |         |
1408             |         |||     class_of($table)     |       |         |
1409             |         |||------------------------->||      |         |
1410             |         |||       $subclass          ||      |         |
1411             |         |||<-------------------------||      |         |
1412             |         |||                          |       |         |
1413             |         |||-----+ is_model_applicable|       |         |
1414             |         ||||<---+                    |       |         |
1415             |         |||                          |       |         |
1416             |         |||-----+ call_authenticate  |       |         |
1417             |         ||||<---+                    |       |         |
1418             |         |||                          |       |         |
1419             |         |||-----+ additional_data    |       |         |
1420             |         ||||<---+                    |       |         |
1421             |         |||             process      |       |         |
1422             |         |||--------------------------------->||  fetch_objects
1423             |         |||                          |       ||-----+  |
1424             |         |||                          |       |||<---+  |
1425             |         |||                          |       ||        |
1426             |         |||                          |       ||   $action
1427             |         |||                          |       ||-----+  |
1428             |         |||                          |       |||<---+  |            
1429             |         |||         process          |       |         |
1430             |         |||------------------------------------------->|| template
1431             |         |||                          |       |         ||-----+
1432             |         |||                          |       |         |||<---+
1433             |         |||                          |       |         |
1434             |         ||     send_output           |       |         |
1435             |         ||-----+                     |       |         |
1436             |         |||<---+                     |       |         |
1437    $status  |         ||                           |       |         |
1438    <------------------||                           |       |         |
1439             |         |                            |       |         |
1440             |         X                            |       |         |           
1441             |                                      |       |         |
1442             |                                      |       |         |
1443             |                                      |       |         |
1444            
1445            
1446
1447 =head1 SEE ALSO
1448
1449 There's more documentation, examples, and information on our mailing lists
1450 at the Maypole web site:
1451
1452 L<http://maypole.perl.org/>
1453
1454 L<Maypole::Application>, L<Apache::MVC>, L<CGI::Maypole>.
1455
1456 =head1 AUTHOR
1457
1458 Maypole is currently maintained by Aaron Trevena.
1459
1460 =head1 AUTHOR EMERITUS
1461
1462 Simon Cozens, C<simon#cpan.org>
1463
1464 Simon Flack maintained Maypole from 2.05 to 2.09
1465
1466 Sebastian Riedel, C<sri#oook.de> maintained Maypole from 1.99_01 to 2.04
1467
1468 =head1 THANKS TO
1469
1470 Sebastian Riedel, Danijel Milicevic, Dave Slack, Jesse Sheidlower, Jody Belka,
1471 Marcus Ramberg, Mickael Joanne, Randal Schwartz, Simon Flack, Steve Simms,
1472 Veljko Vidovic and all the others who've helped.
1473
1474 =head1 LICENSE
1475
1476 You may distribute this code under the same terms as Perl itself.
1477
1478 =cut
1479
1480 1;
1481
1482 __END__
1483
1484  =item register_cleanup($coderef)
1485
1486 Analogous to L<Apache>'s C<register_cleanup>. If an Apache request object is
1487 available, this call simply redispatches there. If not, the cleanup is
1488 registered in the Maypole request, and executed when the request is
1489 C<DESTROY>ed.
1490
1491 This method is only useful in persistent environments, where you need to ensure
1492 that some code runs when the request finishes, no matter how it finishes (e.g.
1493 after an unexpected error). 
1494
1495  =cut
1496
1497 {
1498     my @_cleanups;
1499
1500     sub register_cleanup
1501     {
1502         my ($self, $cleanup) = @_;
1503         
1504         die "register_cleanup() is an instance method, not a class method" 
1505             unless ref $self;
1506         die "Cleanup must be a coderef" unless ref($cleanup) eq 'CODE';
1507         
1508         if ($self->can('ar') && $self->ar)
1509         {
1510             $self->ar->register_cleanup($cleanup);
1511         }
1512         else
1513         {
1514             push @_cleanups, $cleanup;
1515         }
1516     }
1517
1518     sub DESTROY
1519     {
1520         my ($self) = @_;
1521         
1522         while (my $cleanup = shift @_cleanups)
1523         {
1524             eval { $cleanup->() };
1525             if ($@)
1526             {
1527                 warn "Error during request cleanup: $@";
1528             }
1529         }        
1530     }    
1531 }
1532