]> git.decadent.org.uk Git - maypole.git/blob - lib/Maypole.pm
fixing Components integration
[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 - see
267 L<Maypole::Manual::Plugins>.
268
269 If your model is based on L<Maypole::Model::CDBI>, the C<\%attr> hashref can 
270 contain options that are passed directly to L<Class::DBI::Loader>, to control 
271 how the model hierarchy is constructed. 
272
273 Your application should call this B<after> setting up configuration data via
274 L<"config">.
275
276 =cut
277
278 sub setup
279 {
280     my $class = shift;
281     
282     $class->setup_model(@_);    
283 }
284
285 =item setup_model
286
287 Called by C<setup>. This method builds the Maypole model hierarchy. 
288
289 A likely target for over-riding, if you need to build a customised model.
290
291 This method also ensures any code in custom model classes is loaded, so you
292 don't need to load them in the driver.
293
294 =cut
295
296 sub setup_model 
297 {
298     my $class = shift;
299     
300     $class = ref $class if ref $class;
301     
302     my $config = $class->config;
303     
304     $config->model || $config->model('Maypole::Model::CDBI');
305     
306     $config->model->require or die sprintf 
307         "Couldn't load the model class %s: %s", $config->model, $@;
308     
309     # among other things, this populates $config->classes
310     $config->model->setup_database($config, $class, @_);
311     
312     foreach my $subclass ( @{ $config->classes } ) 
313     {
314       next if $subclass->isa("Maypole::Model::Base");
315       no strict 'refs';
316       unshift @{ $subclass . "::ISA" }, $config->model;
317       
318       # Load custom model code, if it exists - nb this must happen after the 
319       # unshift, to allow code attributes to work, but before adopt(),  
320       # in case adopt() calls overridden methods on $subclass
321       $class->load_model_subclass($subclass) unless ($class->model_classes_loaded());
322       
323       $config->model->adopt($subclass) if $config->model->can("adopt");
324     }
325 }
326
327 =item load_model_subclass($subclass)
328
329 This method is called from C<setup_model()>. It attempts to load the
330 C<$subclass> package, if one exists. So if you make a customized C<BeerDB::Beer>
331 package, you don't need to explicitly load it. 
332
333 If, perhaps during development, you don't want to load up custom classes, you 
334 can override this method and load them manually. 
335
336 =cut
337
338 sub load_model_subclass
339 {
340     my ($class, $subclass) = @_;
341     
342     my $config = $class->config;
343     
344     # Load any external files for the model base class or subclasses
345     # (e.g. BeerDB/DBI.pm or BeerDB/Beer.pm) based on code borrowed from
346     # Maypole::Plugin::Loader and Class::DBI.
347     if ( $subclass->require ) 
348     {
349         warn "Loaded external module for '$subclass'\n" if $class->debug > 1;
350     } 
351     else 
352     {
353         (my $filename = $subclass) =~ s!::!/!g;
354         die "Loading '$subclass' failed: $@\n"
355                unless $@ =~ /Can\'t locate \Q$filename\E\.pm/;
356         warn "No external module for '$subclass'" 
357             if $class->debug > 1;
358    }
359 }
360
361 =item init
362
363 Loads the view class and instantiates the view object.
364
365 You should not call this directly, but you may wish to override this to add
366 application-specific initialisation - see L<Maypole::Manual::Plugins>.
367
368 =cut
369
370 sub init 
371 {
372     my $class  = shift;
373     my $config = $class->config;
374     $config->view || $config->view("Maypole::View::TT");
375     $config->view->require;
376     die "Couldn't load the view class " . $config->view . ": $@" if $@;
377     $config->display_tables
378       || $config->display_tables( $class->config->tables );
379     $class->view_object( $class->config->view->new );
380     $class->init_done(1);
381 }
382
383 =item new
384
385 Constructs a very minimal new Maypole request object.
386
387 =cut
388
389 sub new
390 {
391     my ($class) = @_;
392     
393     my $self = bless {
394         template_args => {},
395         config        => $class->config,
396     }, $class;
397     
398     return $self;
399 }
400
401 =item view_object
402
403 Get/set the Maypole::View object
404
405 =back
406
407 =head1 INSTANCE METHODS
408
409 =head2 Workflow
410
411 =over 4
412
413 =item handler
414
415 This method sets up the class if it's not done yet, sets some defaults and
416 leaves the dirty work to C<handler_guts>.
417
418 =cut
419
420 # handler() has a method attribute so that mod_perl will invoke
421 # BeerDB->handler() as a method rather than a plain function
422 # BeerDB::handler() and so this inherited implementation will be
423 # found. See e.g. "Practical mod_perl" by Bekman & Cholet for
424 # more information <http://modperlbook.org/html/ch25_01.html>
425 sub handler : method  {
426   # See Maypole::Workflow before trying to understand this.
427   my ($class, $req) = @_;
428     
429   $class->init unless $class->init_done;
430
431   my $self = $class->new;
432     
433   # initialise the request
434   $self->headers_out(Maypole::Headers->new);
435   $self->get_request($req);
436   $self->parse_location;
437     
438   # hook useful for declining static requests e.g. images, or perhaps for 
439   # sanitizing request parameters
440   $self->status(Maypole::Constants::OK()); # set the default
441   $self->__call_hook('start_request_hook');
442   return $self->status unless $self->status == Maypole::Constants::OK();
443     
444   die "status undefined after start_request_hook()" unless defined
445     $self->status;
446     
447   $self->get_session;
448   $self->get_user;
449     
450   my $status = $self->handler_guts;
451   return $status unless $status == OK;
452
453   # TODO: require send_output to return a status code
454   $self->send_output;
455
456   return $status;
457 }
458
459 sub component {
460   my ($r,$path) = @_;
461   my $component = Maypole::Components->new(@_);
462   return $component->handler($path);
463 }
464
465
466 # Instead of making plugin authors use the NEXT::DISTINCT hoopla to ensure other 
467 # plugins also get to call the hook, we can cycle through the application's 
468 # @ISA and call them all here. Doesn't work for setup() though, because it's 
469 # too ingrained in the stack. We could add a run_setup() method, but we'd break 
470 # lots of existing code.
471 sub __call_hook
472 {
473     my ($self, $hook) = @_;
474     
475     my @plugins;
476     {
477         my $class = ref($self);
478         no strict 'refs';
479         @plugins = @{"$class\::ISA"};
480     }
481     
482     # this is either a custom method in the driver, or the method in the 1st 
483     # plugin, or the 'null' method in the frontend (i.e. inherited from 
484     # Maypole.pm) - we need to be careful to only call it once
485     my $first_hook = $self->can($hook);
486     $self->$first_hook;  
487     
488     my %seen = ( $first_hook => 1 );
489
490     # @plugins includes the frontend
491     foreach my $plugin (@plugins)
492     {
493         next unless my $plugin_hook = $plugin->can($hook);
494         next if $seen{$plugin_hook}++;
495         $self->$plugin_hook;
496     }
497 }
498
499 =item handler_guts
500
501 This is the main request handling method and calls various methods to handle the
502 request/response and defines the workflow within Maypole.
503
504 B<Currently undocumented and liable to be refactored without warning>.
505
506 =cut
507
508 # The root of all evil
509 sub handler_guts 
510 {
511     my ($self) = @_;
512     
513     $self->__load_request_model;
514
515     my $applicable = $self->is_model_applicable;
516     
517     $self->__setup_plain_template unless $applicable;
518
519     my $status;
520
521     eval { $status = $self->call_authenticate };
522     
523     if ( my $error = $@ ) 
524     {
525         $status = $self->call_exception($error, "authentication");
526         
527         if ( $status != OK ) 
528         {
529             warn "caught authenticate error: $error";
530             return $self->debug ? 
531                     $self->view_object->error($self, $error) : ERROR;
532         }
533     }
534     
535     if ( $self->debug and $status != OK and $status != DECLINED ) 
536     {
537         $self->view_object->error( $self,
538             "Got unexpected status $status from calling authentication" );
539     }
540     
541     return $status unless $status == OK;
542
543     # We run additional_data for every request
544     $self->additional_data;
545     
546     if ($applicable) 
547     {
548         eval { $self->model_class->process($self) };
549         
550         if ( my $error = $@ ) 
551         {
552             $status = $self->call_exception($error, "model");
553             
554             if ( $status != OK ) 
555             {
556                 warn "caught model error: $error";
557                 return $self->debug ? 
558                     $self->view_object->error($self, $error) : ERROR;
559             }
560         }
561     }
562     
563     # less frequent path - perhaps output has been set to an error message
564     return OK if $self->output;
565
566     # normal path - no output has been generated yet
567     my $processed_view_ok = $self->__call_process_view;
568
569     $self->{content_type}      ||= $self->__get_mime_type();
570     $self->{document_encoding} ||= "utf-8";
571
572     return $processed_view_ok;
573 }
574
575 my %filetypes = (
576                  'js' => 'text/javascript',
577                  'css' => 'text/css',
578                  'htm' => 'text/html',
579                  'html' => 'text/html',
580                 );
581
582 sub __get_mime_type {
583   my $self = shift;
584   my $type;
585   if ($self->path =~ m/.*\.(\w{3,4})$/) {
586     $type = $filetypes{$1};
587   } else {
588     $type = $mmagic->checktype_contents($self->output);
589   }
590   return $type;
591 }
592
593 sub __load_request_model
594 {
595     my ($self) = @_;
596     $self->model_class( $self->config->model->class_of($self, $self->table) );
597 }
598
599 # is_applicable() returned false, so set up a plain template. Model processing 
600 # will be skipped, but need to remove the model anyway so the template can't 
601 # access it. 
602 sub __setup_plain_template
603 {
604     my ($self) = @_;
605     
606     # It's just a plain template
607     $self->model_class(undef);
608     
609     my $path = $self->path;
610     $path =~ s{/$}{};    # De-absolutify
611     $self->path($path);
612     
613     $self->template($self->path);
614 }
615
616 # The model has been processed or skipped (if is_applicable returned false), 
617 # any exceptions have been handled, and there's no content in $self->output
618 sub __call_process_view
619 {
620     my ($self) = @_;
621     
622     my $status;
623     
624     eval { $status = $self->view_object->process($self) };
625     
626     if ( my $error = $@ ) 
627     {
628         $status = $self->call_exception($error, "view");
629         
630         if ( $status != OK ) 
631         {
632             warn "caught view error: $error" if $self->debug;
633             return $self->debug ? 
634                 $self->view_object->error($self, $error) : ERROR;
635         }
636     }
637     
638     return $status;
639 }
640
641 =item get_request
642
643 You should only need to define this method if you are writing a new
644 Maypole backend. It should return something that looks like an Apache
645 or CGI request object, it defaults to blank.
646
647 =cut
648
649 sub get_request { }
650
651 =item parse_location
652
653 Turns the backend request (e.g. Apache::MVC, Maypole, CGI) into a Maypole
654 request. It does this by setting the C<path>, and invoking C<parse_path> and
655 C<parse_args>.
656
657 You should only need to define this method if you are writing a new Maypole
658 backend.
659
660 =cut
661
662 sub parse_location 
663 {
664     die "parse_location is a virtual method. Do not use Maypole directly; " . 
665                 "use Apache::MVC or similar";
666 }
667
668 =item start_request_hook
669
670 This is called immediately after setting up the basic request. The default
671 method does nothing. 
672
673 The value of C<< $r->status >> is set to C<OK> before this hook is run. Your 
674 implementation can change the status code, or leave it alone. 
675
676 After this hook has run, Maypole will check the value of C<status>. For any
677 value other than C<OK>, Maypole returns the C<status> immediately. 
678
679 This is useful for filtering out requests for static files, e.g. images, which
680 should not be processed by Maypole or by the templating engine:
681
682     sub start_request_hook
683     {
684         my ($r) = @_;
685         
686         $r->status(DECLINED) if $r->path =~ /\.jpg$/;
687     }
688     
689 Multiple plugins, and the driver, can define this hook - Maypole will call all
690 of them. You should check for and probably not change any non-OK C<status>
691 value:
692
693     package Maypole::Plugin::MyApp::SkipFavicon;
694     
695     sub start_request_hook
696     {
697         my ($r) = @_;
698         
699         # check if a previous plugin has already DECLINED this request
700         # - probably unnecessary in this example, but you get the idea
701         return unless $r->status == OK;
702         
703         # then do our stuff
704         $r->status(DECLINED) if $r->path =~ /favicon\.ico/;
705     }        
706      
707 =cut
708
709 sub start_request_hook { }
710
711 =item is_applicable
712
713 B<This method is deprecated> as of version 2.11. If you have overridden it,
714 please override C<is_model_applicable> instead, and change the return type
715 from a Maypole:Constant to a true/false value.
716
717 Returns a Maypole::Constant to indicate whether the request is valid.
718
719 =item is_model_applicable
720
721 Returns true or false to indicate whether the request is valid.
722
723 The default implementation checks that C<< $r->table >> is publicly
724 accessible and that the model class is configured to handle the
725 C<< $r->action >>.
726
727 =cut
728
729 sub is_model_applicable 
730 {
731     my ($self) = @_;
732     
733     # cater for applications that are using obsolete version
734     if ($self->can('is_applicable')) 
735     {
736         warn "DEPRECATION WARNING: rewrite is_applicable to the interface ".
737                 "of Maypole::is_model_applicable\n";
738         return $self->is_applicable == OK;
739     }
740
741     # Establish which tables should be processed by the model
742     my $config = $self->config;
743     
744     $config->ok_tables || $config->ok_tables( $config->display_tables );
745     
746     $config->ok_tables( { map { $_ => 1 } @{ $config->ok_tables } } )
747         if ref $config->ok_tables eq "ARRAY";
748         
749     my $ok_tables = $config->ok_tables;
750       
751     # Does this request concern a table to be processed by the model?
752     my $table = $self->table;
753     
754     my $ok = 0;
755     
756     if (exists $ok_tables->{$table}) 
757     {
758         $ok = 1;
759     } 
760
761     if (not $ok) 
762     {
763         warn "We don't have that table ($table).\n"
764             . "Available tables are: "
765             . join( ",", keys %$ok_tables )
766                 if $self->debug and not $ok_tables->{$table};
767                 
768         return 0;
769     }
770     
771     # Is the action public?
772     my $action = $self->action;
773     return 1 if $self->model_class->is_public($action);
774     
775     warn "The action '$action' is not applicable to the table '$table'"
776          if $self->debug;
777     
778     return 0;
779 }
780
781 =item get_session
782
783 Called immediately after C<start_request_hook()>.
784
785 This method should return a session, which will be stored in the request's
786 C<session> attribute.
787
788 The default method is empty. 
789
790 =cut
791
792 sub get_session { }
793
794 =item get_user
795
796 Called immediately after C<get_session>.
797
798 This method should return a user, which will be stored in the request's C<user>
799 attribute.
800
801 The default method is empty.
802
803 =cut
804
805 sub get_user {}
806
807 =item call_authenticate
808
809 This method first checks if the relevant model class
810 can authenticate the user, or falls back to the default
811 authenticate method of your Maypole application.
812
813 =cut
814
815 sub call_authenticate 
816 {
817     my ($self) = @_;
818
819     # Check if we have a model class with an authenticate() to delegate to
820     return $self->model_class->authenticate($self) 
821         if $self->model_class and $self->model_class->can('authenticate');
822     
823     # Interface consistency is a Good Thing - 
824     # the invocant and the argument may one day be different things 
825     # (i.e. controller and request), like they are when authenticate() 
826     # is called on a model class (i.e. model and request)
827     return $self->authenticate($self);   
828 }
829
830 =item authenticate
831
832 Returns a Maypole::Constant to indicate whether the user is authenticated for
833 the Maypole request.
834
835 The default implementation returns C<OK>
836
837 =cut
838
839 sub authenticate { return OK }
840
841
842 =item call_exception
843
844 This model is called to catch exceptions, first after authenticate, then after
845 processing the model class, and finally to check for exceptions from the view
846 class.
847
848 This method first checks if the relevant model class
849 can handle exceptions the user, or falls back to the default
850 exception method of your Maypole application.
851
852 =cut
853
854 sub call_exception 
855 {
856     my ($self, $error, $when) = @_;
857
858     # Check if we have a model class with an exception() to delegate to
859     if ( $self->model_class && $self->model_class->can('exception') )
860     {
861         my $status = $self->model_class->exception( $self, $error, $when );
862         return $status if $status == OK;
863     }
864     
865     return $self->exception($error, $when);
866 }
867
868
869 =item exception
870
871 This method is called if any exceptions are raised during the authentication or
872 model/view processing. It should accept the exception as a parameter and return
873 a Maypole::Constant to indicate whether the request should continue to be
874 processed.
875
876 =cut
877
878 sub exception { 
879     my ($self, $error, $when) = @_;
880     if ($self->view_object->can("report_error") and $self->debug) {
881         $self->view_object->report_error($self, $error, $when);
882         return OK;
883     }
884     return ERROR;
885 }
886
887 =item additional_data
888
889 Called before the model processes the request, this method gives you a chance to
890 do some processing for each request, for example, manipulating C<template_args>.
891
892 =cut
893
894 sub additional_data { }
895
896 =item send_output
897
898 Sends the output and additional headers to the user.
899
900 =cut
901
902 sub send_output {
903     die "send_output is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
904 }
905
906
907
908
909 =back
910
911 =head2 Path processing and manipulation
912
913 =over 4
914
915 =item path
916
917 Returns the request path
918
919 =item parse_path
920
921 Parses the request path and sets the C<args>, C<action> and C<table>
922 properties. Calls C<preprocess_path> before parsing path and setting properties.
923
924 =cut
925
926 sub parse_path 
927 {
928     my ($self) = @_;
929     
930     # Previous versions unconditionally set table, action and args to whatever 
931     # was in @pi (or else to defaults, if @pi is empty).
932     # Adding preprocess_path(), and then setting table, action and args 
933     # conditionally, broke lots of tests, hence this:
934     $self->$_(undef) for qw/action table args/;
935     
936     $self->preprocess_path;
937     $self->path || $self->path('frontpage');
938
939     my @pi = grep {length} split '/', $self->path;
940
941
942     $self->table  || $self->table(shift @pi);
943     $self->action || $self->action( shift @pi or 'index' );
944     $self->args   || $self->args(\@pi);
945 }
946
947 =item preprocess_path
948
949 Sometimes when you don't want to rewrite or over-ride parse_path but
950 want to rewrite urls or extract data from them before it is parsed.
951
952 This method is called after parse_location has populated the request
953 information and before parse_path has populated the model and action
954 information, and is passed the request object.
955
956 You can set action, args or table in this method and parse_path will
957 then leave those values in place or populate them if not present
958
959 =cut
960
961 sub preprocess_path { };
962
963 =item make_path( %args or \%args or @args )
964
965 This is the counterpart to C<parse_path>. It generates a path to use
966 in links, form actions etc. To implement your own path scheme, just override
967 this method and C<parse_path>.
968
969     %args = ( table      => $table,
970               action     => $action,        
971               additional => $additional,    # optional - generally an object ID
972               );
973               
974     \%args = as above, but a ref
975     
976     @args = ( $table, $action, $additional );   # $additional is optional
977
978 C<id> can be used as an alternative key to C<additional>.
979
980 C<$additional> can be a string, an arrayref, or a hashref. An arrayref is
981 expanded into extra path elements, whereas a hashref is translated into a query
982 string. 
983
984 =cut
985
986 sub make_path
987 {
988     my $r = shift;
989     
990     my %args;
991     
992     if (@_ == 1 and ref $_[0] and ref $_[0] eq 'HASH')
993     {
994         %args = %{$_[0]};
995     }
996     elsif ( @_ > 1 and @_ < 4 )
997     {
998         $args{table}      = shift;
999         $args{action}     = shift;
1000         $args{additional} = shift;
1001     }
1002     else
1003     {
1004         %args = @_;
1005     }
1006     
1007     do { die "no $_" unless $args{$_} } for qw( table action );    
1008
1009     my $additional = $args{additional} || $args{id};
1010     
1011     my @add = ();
1012     
1013     if ($additional)
1014     {
1015         # if $additional is a href, make_uri() will transform it into a query
1016         @add = (ref $additional eq 'ARRAY') ? @$additional : ($additional);
1017     }    
1018     
1019     my $uri = $r->make_uri($args{table}, $args{action}, @add);
1020     
1021     return $uri->as_string;
1022 }
1023
1024
1025
1026 =item make_uri( @segments )
1027
1028 Make a L<URI> object given table, action etc. Automatically adds
1029 the C<uri_base>. 
1030
1031 If the final element in C<@segments> is a hash ref, C<make_uri> will render it
1032 as a query string.
1033
1034 =cut
1035
1036 sub make_uri
1037 {
1038     my ($r, @segments) = @_;
1039
1040     my $query = (ref $segments[-1] eq 'HASH') ? pop(@segments) : undef;
1041     
1042     my $base = $r->config->uri_base; 
1043     $base =~ s|/$||;
1044     
1045     my $uri = URI->new($base);
1046     $uri->path_segments($uri->path_segments, grep {length} @segments);
1047     
1048     my $abs_uri = $uri->abs('/');
1049     $abs_uri->query_form($query) if $query;
1050     return $abs_uri;
1051 }
1052
1053 =item parse_args
1054
1055 Turns post data and query string paramaters into a hash of C<params>.
1056
1057 You should only need to define this method if you are writing a new Maypole
1058 backend.
1059
1060 =cut 
1061
1062 sub parse_args
1063 {
1064     die "parse_args() is a virtual method. Do not use Maypole directly; ".
1065             "use Apache::MVC or similar";
1066 }
1067
1068 =item get_template_root
1069
1070 Implementation-specific path to template root.
1071
1072 You should only need to define this method if you are writing a new Maypole
1073 backend. Otherwise, see L<Maypole::Config/"template_root">
1074
1075 =cut
1076
1077 sub get_template_root {'.'}
1078
1079 =back
1080
1081 =head2 Request properties
1082
1083 =over 4
1084
1085 =item model_class
1086
1087 Returns the perl package name that will serve as the model for the
1088 request. It corresponds to the request C<table> attribute.
1089
1090
1091 =item objects
1092
1093 Get/set a list of model objects. The objects will be accessible in the view
1094 templates.
1095
1096 If the first item in C<$self-E<gt>args> can be C<retrieve()>d by the model
1097 class, it will be removed from C<args> and the retrieved object will be added to
1098 the C<objects> list. See L<Maypole::Model> for more information.
1099
1100 =item template_args
1101
1102     $self->template_args->{foo} = 'bar';
1103
1104 Get/set a hash of template variables.
1105
1106 =item stash
1107
1108 A place to put custom application data. Not used by Maypole itself. 
1109
1110 =item template
1111
1112 Get/set the template to be used by the view. By default, it returns
1113 C<$self-E<gt>action>
1114
1115
1116 =item error
1117
1118 Get/set a request error
1119
1120 =item output
1121
1122 Get/set the response output. This is usually populated by the view class. You
1123 can skip view processing by setting the C<output>.
1124
1125 =item table
1126
1127 The table part of the Maypole request path
1128
1129 =item action
1130
1131 The action part of the Maypole request path
1132
1133 =item args
1134
1135 A list of remaining parts of the request path after table and action
1136 have been
1137 removed
1138
1139 =item headers_in
1140
1141 A L<Maypole::Headers> object containing HTTP headers for the request
1142
1143 =item headers_out
1144
1145 A L<HTTP::Headers> object that contains HTTP headers for the output
1146
1147 =item document_encoding
1148
1149 Get/set the output encoding. Default: utf-8.
1150
1151 =item content_type
1152
1153 Get/set the output content type. Default: text/html
1154
1155 =item get_protocol
1156
1157 Returns the protocol the request was made with, i.e. https
1158
1159 =cut
1160
1161 sub get_protocol {
1162   die "get_protocol is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
1163 }
1164
1165 =back
1166
1167 =head2 Request parameters
1168
1169 The source of the parameters may vary depending on the Maypole backend, but they
1170 are usually populated from request query string and POST data.
1171
1172 Maypole supplies several approaches for accessing the request parameters. Note
1173 that the current implementation (via a hashref) of C<query> and C<params> is
1174 likely to change in a future version of Maypole. So avoid direct access to these
1175 hashrefs:
1176
1177     $r->{params}->{foo}      # bad
1178     $r->params->{foo}        # better
1179
1180     $r->{query}->{foo}       # bad
1181     $r->query->{foo}         # better
1182
1183     $r->param('foo')         # best
1184
1185 =over 4
1186
1187 =item param
1188
1189 An accessor (get or set) for request parameters. It behaves similarly to
1190 CGI::param() for accessing CGI parameters, i.e.
1191
1192     $r->param                   # returns list of keys
1193     $r->param($key)             # returns value for $key
1194     $r->param($key => $value)   # returns old value, sets to new value
1195
1196 =cut
1197
1198 sub param 
1199
1200     my ($self, $key) = (shift, shift);
1201     
1202     return keys %{$self->params} unless defined $key;
1203     
1204     return unless exists $self->params->{$key};
1205     
1206     my $val = $self->params->{$key};
1207     
1208     if (@_)
1209     {
1210         my $new_val = shift;
1211         $self->params->{$key} = $new_val;
1212     }
1213     
1214     return ref $val ? @$val : ($val) if wantarray;
1215         
1216     return ref $val ? $val->[0] : $val;
1217 }
1218
1219
1220 =item params
1221
1222 Returns a hashref of request parameters. 
1223
1224 B<Note:> Where muliple values of a parameter were supplied, the C<params> value
1225 will be an array reference.
1226
1227 =item query
1228
1229 Alias for C<params>.
1230
1231 =back
1232
1233 =head3 Utility methods
1234
1235 =over 4
1236
1237 =item redirect_request
1238
1239 Sets output headers to redirect based on the arguments provided
1240
1241 Accepts either a single argument of the full url to redirect to, or a hash of
1242 named parameters :
1243
1244 $r->redirect_request('http://www.example.com/path');
1245
1246 or
1247
1248 $r->redirect_request(protocol=>'https', domain=>'www.example.com', path=>'/path/file?arguments', status=>'302', url=>'..');
1249
1250 The named parameters are protocol, domain, path, status and url
1251
1252 Only 1 named parameter is required but other than url, they can be combined as
1253 required and current values (from the request) will be used in place of any
1254 missing arguments. The url argument must be a full url including protocol and
1255 can only be combined with status.
1256
1257 =cut
1258
1259 sub redirect_request {
1260   die "redirect_request is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
1261 }
1262
1263 =item redirect_internal_request 
1264
1265 =cut
1266
1267 sub redirect_internal_request {
1268
1269 }
1270
1271
1272 =item make_random_id
1273
1274 returns a unique id for this request can be used to prevent or detect repeat
1275 submissions.
1276
1277 =cut
1278
1279 # Session and Repeat Submission Handling
1280 sub make_random_id {
1281     use Maypole::Session;
1282     return Maypole::Session::generate_unique_id();
1283 }
1284
1285 =back
1286
1287 =head1 SEQUENCE DIAGRAMS
1288
1289 See L<Maypole::Manual::Workflow> for a detailed discussion of the sequence of 
1290 calls during processing of a request. This is a brief summary:
1291
1292     INITIALIZATION
1293                                Model e.g.
1294          BeerDB           Maypole::Model::CDBI
1295            |                        |
1296    setup   |                        |
1297  o-------->||                       |
1298            || setup_model           |     setup_database() creates
1299            ||------+                |      a subclass of the Model
1300            |||<----+                |        for each table
1301            |||                      |                |
1302            |||   setup_database     |                |
1303            |||--------------------->|| 'create'      *
1304            |||                      ||----------> $subclass
1305            |||                      |                  |
1306            ||| load_model_subclass  |                  |
1307  foreach   |||------+  ($subclass)  |                  |
1308  $subclass ||||<----+               |    require       |
1309            ||||--------------------------------------->|
1310            |||                      |                  |
1311            |||   adopt($subclass)   |                  |
1312            |||--------------------->||                 |
1313            |                        |                  |
1314            |                        |                  |
1315            |-----+ init             |                  |
1316            ||<---+                  |                  |
1317            ||                       |     new          |     view_object: e.g.
1318            ||---------------------------------------------> Maypole::View::TT
1319            |                        |                  |          |
1320            |                        |                  |          |
1321            |                        |                  |          |
1322            |                        |                  |          |
1323            |                        |                  |          |
1324            
1325
1326
1327     HANDLING A REQUEST
1328
1329
1330           BeerDB                                Model  $subclass  view_object
1331             |                                      |       |         |
1332     handler |                                      |       |         |
1333   o-------->| new                                  |       |         |
1334             |-----> r:BeerDB                       |       |         |
1335             |         |                            |       |         |
1336             |         |                            |       |         |
1337             |         ||                           |       |         |
1338             |         ||-----+ parse_location      |       |         |
1339             |         |||<---+                     |       |         |
1340             |         ||                           |       |         |
1341             |         ||-----+ start_request_hook  |       |         |
1342             |         |||<---+                     |       |         |
1343             |         ||                           |       |         |
1344             |         ||-----+ get_session         |       |         |
1345             |         |||<---+                     |       |         |
1346             |         ||                           |       |         |
1347             |         ||-----+ get_user            |       |         |
1348             |         |||<---+                     |       |         |
1349             |         ||                           |       |         |
1350             |         ||-----+ handler_guts        |       |         |
1351             |         |||<---+                     |       |         |
1352             |         |||     class_of($table)     |       |         |
1353             |         |||------------------------->||      |         |
1354             |         |||       $subclass          ||      |         |
1355             |         |||<-------------------------||      |         |
1356             |         |||                          |       |         |
1357             |         |||-----+ is_model_applicable|       |         |
1358             |         ||||<---+                    |       |         |
1359             |         |||                          |       |         |
1360             |         |||-----+ call_authenticate  |       |         |
1361             |         ||||<---+                    |       |         |
1362             |         |||                          |       |         |
1363             |         |||-----+ additional_data    |       |         |
1364             |         ||||<---+                    |       |         |
1365             |         |||             process      |       |         |
1366             |         |||--------------------------------->||  fetch_objects
1367             |         |||                          |       ||-----+  |
1368             |         |||                          |       |||<---+  |
1369             |         |||                          |       ||        |
1370             |         |||                          |       ||   $action
1371             |         |||                          |       ||-----+  |
1372             |         |||                          |       |||<---+  |            
1373             |         |||         process          |       |         |
1374             |         |||------------------------------------------->|| template
1375             |         |||                          |       |         ||-----+
1376             |         |||                          |       |         |||<---+
1377             |         |||                          |       |         |
1378             |         ||     send_output           |       |         |
1379             |         ||-----+                     |       |         |
1380             |         |||<---+                     |       |         |
1381    $status  |         ||                           |       |         |
1382    <------------------||                           |       |         |
1383             |         |                            |       |         |
1384             |         X                            |       |         |           
1385             |                                      |       |         |
1386             |                                      |       |         |
1387             |                                      |       |         |
1388            
1389            
1390
1391 =head1 SEE ALSO
1392
1393 There's more documentation, examples, and information on our mailing lists
1394 at the Maypole web site:
1395
1396 L<http://maypole.perl.org/>
1397
1398 L<Maypole::Application>, L<Apache::MVC>, L<CGI::Maypole>.
1399
1400 =head1 AUTHOR
1401
1402 Maypole is currently maintained by Aaron Trevena, David Baird, Dave Howorth and
1403 Peter Speltz.
1404
1405 =head1 AUTHOR EMERITUS
1406
1407 Simon Cozens, C<simon#cpan.org>
1408
1409 Simon Flack maintained Maypole from 2.05 to 2.09
1410
1411 Sebastian Riedel, C<sri#oook.de> maintained Maypole from 1.99_01 to 2.04
1412
1413 =head1 THANKS TO
1414
1415 Sebastian Riedel, Danijel Milicevic, Dave Slack, Jesse Sheidlower, Jody Belka,
1416 Marcus Ramberg, Mickael Joanne, Randal Schwartz, Simon Flack, Steve Simms,
1417 Veljko Vidovic and all the others who've helped.
1418
1419 =head1 LICENSE
1420
1421 You may distribute this code under the same terms as Perl itself.
1422
1423 =cut
1424
1425 1;
1426
1427 __END__
1428
1429  =item register_cleanup($coderef)
1430
1431 Analogous to L<Apache>'s C<register_cleanup>. If an Apache request object is
1432 available, this call simply redispatches there. If not, the cleanup is
1433 registered in the Maypole request, and executed when the request is
1434 C<DESTROY>ed.
1435
1436 This method is only useful in persistent environments, where you need to ensure
1437 that some code runs when the request finishes, no matter how it finishes (e.g.
1438 after an unexpected error). 
1439
1440  =cut
1441
1442 {
1443     my @_cleanups;
1444
1445     sub register_cleanup
1446     {
1447         my ($self, $cleanup) = @_;
1448         
1449         die "register_cleanup() is an instance method, not a class method" 
1450             unless ref $self;
1451         die "Cleanup must be a coderef" unless ref($cleanup) eq 'CODE';
1452         
1453         if ($self->can('ar') && $self->ar)
1454         {
1455             $self->ar->register_cleanup($cleanup);
1456         }
1457         else
1458         {
1459             push @_cleanups, $cleanup;
1460         }
1461     }
1462
1463     sub DESTROY
1464     {
1465         my ($self) = @_;
1466         
1467         while (my $cleanup = shift @_cleanups)
1468         {
1469             eval { $cleanup->() };
1470             if ($@)
1471             {
1472                 warn "Error during request cleanup: $@";
1473             }
1474         }        
1475     }    
1476 }
1477