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