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