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