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