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