]> git.decadent.org.uk Git - maypole.git/blob - lib/Maypole.pm
Modified setup_model() to load any available custom table classes.
[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 URI();
10
11 our $VERSION = '2.11';
12
13 # proposed privacy conventions:
14 # - no leading underscore     - public to custom application code and plugins
15 # - single leading underscore - private to the main Maypole stack - *not*
16 #     including plugins
17 # - double leading underscore - private to the current package
18
19 =head1 NAME
20
21 Maypole - MVC web application framework
22
23 =head1 SYNOPSIS
24
25 See L<Maypole::Application>.
26
27 =head1 DESCRIPTION
28
29 This documents the Maypole request object. See the L<Maypole::Manual>, for a
30 detailed guide to using Maypole.
31
32 Maypole is a Perl web application framework similar to Java's struts. It is 
33 essentially completely abstracted, and so doesn't know anything about
34 how to talk to the outside world.
35
36 To use it, you need to create a driver package which represents your entire
37 application. This is the C<BeerDB> package used as an example in the manual.
38
39 This needs to first use L<Maypole::Application> which will make your package
40 inherit from the appropriate platform driver such as C<Apache::MVC> or
41 C<CGI::Maypole>. Then, the driver calls C<setup>.  This sets up the model classes and
42 configures your application. The default model class for Maypole uses
43 L<Class::DBI> to map a database to classes, but this can be changed by altering
44 configuration (B<before> calling setup.)
45
46
47 =head1 DOCUMENTATION AND SUPPORT
48
49 Note that some details in some of these resources may be out of date.
50
51 =over 4 
52
53 =item The Maypole Manual
54
55 The primary documentation is the Maypole manual. This lives in the 
56 C<Maypole::Manual> pod documents included with the distribution. 
57
58 =item Embedded POD
59
60 Individual packages within the distribution contain (more or less) detailed
61 reference documentation for their API.
62
63 =item Mailing lists
64
65 There are two mailing lists - maypole-devel and maypole-users - see
66 http://maypole.perl.org/?MailingList
67
68 =item The Maypole Wiki
69
70 The Maypole wiki provides a useful store of extra documentation -
71 http://maypole.perl.org
72
73 In particular, there's a FAQ (http://maypole.perl.org/?FAQ) and a cookbook
74 (http://maypole.perl.org/?Cookbook). Again, certain information on these pages
75 may be out of date.
76
77 =item Web applications with Maypole
78
79 A tutorial written by Simon Cozens for YAPC::EU 2005 -
80 http://www.droogs.org/perl/maypole/maypole-tutorial.pdf [228KB].
81
82 =item A Database-Driven Web Application in 18 Lines of Code
83
84 By Paul Barry, published in Linux Journal, March 2005.
85
86 http://www.linuxjournal.com/article/7937
87
88 "From zero to Web-based database application in eight easy steps".
89
90 Maypole won a 2005 Linux Journal Editor's Choice Award
91 (http://www.linuxjournal.com/article/8293) after featuring in this article. 
92
93 =item Build Web apps with Maypole
94
95 By Simon Cozens, on IBM's DeveloperWorks website, May 2004.
96
97 http://www-128.ibm.com/developerworks/linux/library/l-maypole/
98
99 =item Rapid Web Application Deployment with Maypole
100
101 By Simon Cozens, on O'Reilly's Perl website, April 2004.
102
103 http://www.perl.com/pub/a/2004/04/15/maypole.html
104
105 =item Authentication
106
107 Some notes written by Simon Cozens. A little bit out of date, but still 
108 very useful: http://www.droogs.org/perl/maypole/authentication.html
109
110 =item CheatSheet
111
112 There's a refcard for the Maypole (and Class::DBI) APIs on the wiki -
113 http://maypole.perl.org/?CheatSheet. Probably a little out of date now - it's a
114 wiki, so feel free to fix any errors!
115
116 =item Plugins and add-ons
117
118 There are a large and growing number of plugins and other add-on modules
119 available on CPAN - http://search.cpan.org/search?query=maypole&mode=module
120
121 =item del.icio.us
122
123 You can find a range of useful Maypole links, particularly to several thoughtful
124 blog entries, starting here: http://del.icio.us/search/?all=maypole
125
126 =item CPAN ratings
127
128 There are a couple of short reviews here:
129 http://cpanratings.perl.org/dist/Maypole
130
131 =back
132
133 =head1 DEMOS
134
135 A couple of demos are available, sometimes with source code and configs. 
136
137 =over 4 
138
139 =item http://maypole.perl.org/beerdb/
140
141 The standard BeerDB example, using the TT factory templates supplied in the
142 distribution.
143
144 =item beerdb.riverside-cms.co.uk
145
146 The standard BeerDB example, running on Mason, using the factory templates
147 supplied in the L<MasonX::Maypole> distribution.
148
149 =item beerfb.riverside-cms.co.uk
150
151 A demo of L<Maypole::FormBuilder>. This site is running on the set of Mason 
152 templates included in the L<Maypole::FormBuilder> distribution. See the 
153 synopsis of L<Maypole::Plugin::FormBuilder> for an example driver
154
155 =back
156
157 =cut
158
159 __PACKAGE__->mk_classdata($_) for qw( config init_done view_object );
160
161 __PACKAGE__->mk_accessors(
162     qw( params query objects model_class template_args output path
163         args action template error document_encoding content_type table
164         headers_in headers_out stash session)
165 );
166
167 __PACKAGE__->config( Maypole::Config->new() );
168
169 __PACKAGE__->init_done(0);
170
171 =head1 CLASS METHODS
172
173 =over 4
174
175 =item config
176
177 Returns the L<Maypole::Config> object
178
179 =item setup
180
181     My::App->setup($data_source, $user, $password, \%attr);
182
183 Initialise the Maypole application and plugins and model classes - see
184 L<Maypole::Manual::Plugins>.
185
186 If your model is based on L<Maypole::Model::CDBI>, the C<\%attr> hashref can 
187 contain options that are passed directly to L<Class::DBI::Loader>, to control 
188 how the model hierarchy is constructed. 
189
190 Your application should call this B<after> setting up configuration data via
191 L<"config">.
192
193 =cut
194
195 sub setup
196 {
197     my $class = shift;
198     
199     $class->setup_model(@_);    
200 }
201
202 =item setup_model
203
204 Called by C<setup>. This method builds the Maypole model hierarchy. 
205
206 A likely target for over-riding, if you need to build a customised model.
207
208 This method also ensures any code in custom model classes is loaded, so you
209 don't need to load them in the driver.
210
211 =cut
212
213 sub setup_model 
214 {
215     my $class = shift;
216     
217     $class = ref $class if ref $class;
218     
219     my $config = $class->config;
220     
221     $config->model || $config->model('Maypole::Model::CDBI');
222     
223     $config->model->require or die sprintf 
224         "Couldn't load the model class %s: %s", $config->model, $@;
225     
226     # among other things, this populates $config->classes
227     $config->model->setup_database($config, $class, @_);
228     
229     foreach my $subclass ( @{ $config->classes } ) 
230     {
231         no strict 'refs';
232         unshift @{ $subclass . "::ISA" }, $config->model;
233         $config->model->adopt($subclass)
234           if $config->model->can("adopt");
235
236         # Load custom model code, if it exists - nb this must happen after the 
237         # unshift, to allow code attributes to work
238         eval "use $subclass"; 
239         die "Error loading $subclass: $@"  
240             if $@ and $@ !~ /Can\'t locate \S+ in \@INC/;
241     }
242 }
243
244 =item init
245
246 Loads the view class and instantiates the view object.
247
248 You should not call this directly, but you may wish to override this to add
249 application-specific initialisation - see L<Maypole::Manual::Plugins>.
250
251 =cut
252
253 sub init 
254 {
255     my $class  = shift;
256     my $config = $class->config;
257     $config->view || $config->view("Maypole::View::TT");
258     $config->view->require;
259     die "Couldn't load the view class " . $config->view . ": $@" if $@;
260     $config->display_tables
261       || $config->display_tables( $class->config->tables );
262     $class->view_object( $class->config->view->new );
263     $class->init_done(1);
264 }
265
266 =item new
267
268 Constructs a very minimal new Maypole request object.
269
270 =cut
271
272 sub new
273 {
274     my ($class) = @_;
275     
276     my $self = bless {
277         template_args => {},
278         config        => $class->config,
279     }, $class;
280     
281     return $self;
282 }
283
284 =item view_object
285
286 Get/set the Maypole::View object
287
288 =item debug
289
290     sub My::App::debug {1}
291
292 Returns the debugging flag. Override this in your application class to
293 enable/disable debugging.
294
295 You can also set the C<debug> flag via L<Maypole::Application>.
296
297 =cut
298
299 sub debug { 0 }      
300
301 =item get_template_root
302
303 Implementation-specific path to template root.
304
305 You should only need to define this method if you are writing a new Maypole
306 backend. Otherwise, see L<Maypole::Config/"template_root">
307
308 =cut
309
310 sub get_template_root {'.'}
311
312 =back
313
314 =head1 INSTANCE METHODS
315
316 =head2 Workflow
317
318 =over 4
319
320 =item handler
321
322 This method sets up the class if it's not done yet, sets some defaults and
323 leaves the dirty work to C<handler_guts>.
324
325 =cut
326
327 # handler() has a method attribute so that mod_perl will invoke
328 # BeerDB->handler() as a method rather than a plain function
329 # BeerDB::handler() and so this inherited implementation will be
330 # found. See e.g. "Practical mod_perl" by Bekman & Cholet for
331 # more information <http://modperlbook.org/html/ch25_01.html>
332 sub handler : method 
333 {
334     # See Maypole::Workflow before trying to understand this.
335     my ($class, $req) = @_;
336     
337     $class->init unless $class->init_done;
338
339     my $self = $class->new;
340     
341     # initialise the request
342     $self->headers_out(Maypole::Headers->new);
343     $self->get_request($req);
344     $self->parse_location;
345     
346     # hook useful for declining static requests e.g. images
347     my $status = $self->start_request_hook;
348     return $status unless $status == Maypole::Constants::OK();
349     
350     $self->session($self->get_session);
351     
352     $status = $self->handler_guts;
353     
354     # moving this here causes unit test failures - need to check why
355     # before committing the move
356     #$status = $self->__call_process_view unless $self->output;
357     
358     return $status unless $status == OK;
359     
360     # TODO: require send_output to return a status code
361     $self->send_output;
362     
363     return $status;
364 }
365
366 =item handler_guts
367
368 This is the main request handling method and calls various methods to handle the
369 request/response and defines the workflow within Maypole.
370
371 B<Currently undocumented and liable to be refactored without warning>.
372
373 =cut
374
375 # The root of all evil
376 sub handler_guts 
377 {
378     my ($self) = @_;
379     
380     $self->__load_model;
381
382     my $applicable = $self->is_model_applicable;
383     
384     $self->__setup_plain_template unless $applicable;
385
386     my $status;
387
388     eval { $status = $self->call_authenticate };
389     
390     if ( my $error = $@ ) 
391     {
392         $status = $self->call_exception($error);
393         
394         if ( $status != OK ) 
395         {
396             warn "caught authenticate error: $error";
397             return $self->debug ? 
398                     $self->view_object->error($self, $error) : ERROR;
399         }
400     }
401     
402     if ( $self->debug and $status != OK and $status != DECLINED ) 
403     {
404         $self->view_object->error( $self,
405             "Got unexpected status $status from calling authentication" );
406     }
407     
408     return $status unless $status == OK;
409
410     # We run additional_data for every request
411     $self->additional_data;
412     
413     if ($applicable) 
414     {
415         eval { $self->model_class->process($self) };
416         
417         if ( my $error = $@ ) 
418         {
419             $status = $self->call_exception($error);
420             
421             if ( $status != OK ) 
422             {
423                 warn "caught model error: $error";
424                 return $self->debug ? 
425                     $self->view_object->error($self, $error) : ERROR;
426             }
427         }
428     }
429     
430     # less frequent path - perhaps output has been set to an error message
431     return OK if $self->output;
432     
433     # normal path - no output has been generated yet
434     return $self->__call_process_view;
435 }
436
437 sub __load_model
438 {
439     my ($self) = @_;
440     $self->model_class( $self->config->model->class_of($self, $self->table) );
441 }
442
443 # is_applicable() returned false, so set up a plain template. Model processing 
444 # will be skipped, but need to remove the model anyway so the template can't 
445 # access it. 
446 sub __setup_plain_template
447 {
448     my ($self) = @_;
449     
450     # It's just a plain template
451     $self->model_class(undef);
452     
453     my $path = $self->path;
454     $path =~ s{/$}{};    # De-absolutify
455     $self->path($path);
456     
457     $self->template($self->path);
458 }
459
460 # The model has been processed or skipped (if is_applicable returned false), 
461 # any exceptions have been handled, and there's no content in $self->output
462 sub __call_process_view
463 {
464     my ($self) = @_;
465     
466     my $status;
467     
468     eval { $status = $self->view_object->process($self) };
469     
470     if ( my $error = $@ ) 
471     {
472         $status = $self->call_exception($error);
473         
474         if ( $status != OK ) 
475         {
476             warn "caught view error: $error" if $self->debug;
477             return $self->debug ? 
478                 $self->view_object->error($self, $error) : ERROR;
479         }
480     }
481     
482     return $status;
483 }
484
485 =item get_request
486
487 You should only need to define this method if you are writing a new
488 Maypole backend. It should return something that looks like an Apache
489 or CGI request object, it defaults to blank.
490
491 =cut
492
493 sub get_request { }
494
495 =item parse_location
496
497 Turns the backend request (e.g. Apache::MVC, Maypole, CGI) into a Maypole
498 request. It does this by setting the C<path>, and invoking C<parse_path> and
499 C<parse_args>.
500
501 You should only need to define this method if you are writing a new Maypole
502 backend.
503
504 =cut
505
506 sub parse_location 
507 {
508     die "parse_location is a virtual method. Do not use Maypole directly; " . 
509                 "use Apache::MVC or similar";
510 }
511
512 =item start_request_hook
513
514 This is called immediately after setting up the basic request. The default
515 method simply returns C<Maypole::Constants::OK>.
516
517 Any other return value causes Maypole to abort further processing of the
518 request. This is useful for filtering out requests for static files, e.g.
519 images, which should not be processed by Maypole or by the templating engine:
520
521     sub start_request_hook
522     {
523         my ($r) = @_;
524         
525         return Maypole::Constants::DECLINED if $r->path =~ /\.jpg$/;
526         return Maypole::Constants::OK;
527     }
528
529 =cut
530
531 sub start_request_hook { Maypole::Constants::OK }
532
533 =item is_applicable
534
535 B<This method is deprecated> as of version 2.11. If you have overridden it,
536 please override C<is_model_applicable> instead, and change the return type
537 from a Maypole:Constant to a true/false value.
538
539 Returns a Maypole::Constant to indicate whether the request is valid.
540
541 =item is_model_applicable
542
543 Returns true or false to indicate whether the request is valid.
544
545 The default implementation checks that C<< $r->table >> is publicly
546 accessible and that the model class is configured to handle the
547 C<< $r->action >>.
548
549 =cut
550
551 sub is_model_applicable 
552 {
553     my ($self) = @_;
554     
555     # cater for applications that are using obsolete version
556     if ($self->can('is_applicable')) 
557     {
558         warn "DEPRECATION WARNING: rewrite is_applicable to the interface ".
559                 "of Maypole::is_model_applicable\n";
560         return $self->is_applicable == OK;
561     }
562
563     # Establish which tables should be processed by the model
564     my $config = $self->config;
565     
566     $config->ok_tables || $config->ok_tables( $config->display_tables );
567     
568     $config->ok_tables( { map { $_ => 1 } @{ $config->ok_tables } } )
569         if ref $config->ok_tables eq "ARRAY";
570         
571     my $ok_tables = $config->ok_tables;
572       
573     # Does this request concern a table to be processed by the model?
574     my $table = $self->table;
575     
576     my $ok = 0;
577     
578     if (exists $ok_tables->{$table}) 
579     {
580         $ok = 1;
581     } 
582
583     if (not $ok) 
584     {
585         warn "We don't have that table ($table).\n"
586             . "Available tables are: "
587             . join( ",", keys %$ok_tables )
588                 if $self->debug and not $ok_tables->{$table};
589                 
590         return 0;
591     }
592     
593     # Is the action public?
594     my $action = $self->action;
595     return 1 if $self->model_class->is_public($action);
596     
597     warn "The action '$action' is not applicable to the table $table"
598         if $self->debug;
599     
600     return 0;
601 }
602
603 =item get_session
604
605 The default method is empty. 
606
607 =cut
608
609 sub get_session { }
610
611 =item call_authenticate
612
613 This method first checks if the relevant model class
614 can authenticate the user, or falls back to the default
615 authenticate method of your Maypole application.
616
617 =cut
618
619 sub call_authenticate 
620 {
621     my ($self) = @_;
622
623     # Check if we have a model class with an authenticate() to delegate to
624     return $self->model_class->authenticate($self) 
625         if $self->model_class and $self->model_class->can('authenticate');
626     
627     # Interface consistency is a Good Thing - 
628     # the invocant and the argument may one day be different things 
629     # (i.e. controller and request), like they are when authenticate() 
630     # is called on a model class (i.e. model and request)
631     return $self->authenticate($self);   
632 }
633
634 =item authenticate
635
636 Returns a Maypole::Constant to indicate whether the user is authenticated for
637 the Maypole request.
638
639 The default implementation returns C<OK>
640
641 =cut
642
643 sub authenticate { return OK }
644
645
646 =item call_exception
647
648 This model is called to catch exceptions, first after authenticate, then after
649 processing the model class, and finally to check for exceptions from the view
650 class.
651
652 This method first checks if the relevant model class
653 can handle exceptions the user, or falls back to the default
654 exception method of your Maypole application.
655
656 =cut
657
658 sub call_exception 
659 {
660     my ($self, $error) = @_;
661
662     # Check if we have a model class with an exception() to delegate to
663     if ( $self->model_class && $self->model_class->can('exception') )
664     {
665         my $status = $self->model_class->exception( $self, $error );
666         return $status if $status == OK;
667     }
668     
669     return $self->exception($error);
670 }
671
672 =item exception
673
674 This method is called if any exceptions are raised during the authentication or
675 model/view processing. It should accept the exception as a parameter and return
676 a Maypole::Constant to indicate whether the request should continue to be
677 processed.
678
679 =cut
680
681 sub exception { return ERROR }
682
683 =item additional_data
684
685 Called before the model processes the request, this method gives you a chance to
686 do some processing for each request, for example, manipulating C<template_args>.
687
688 =cut
689
690 sub additional_data { }
691
692 =item send_output
693
694 Sends the output and additional headers to the user.
695
696 =cut
697
698 sub send_output {
699     die "send_output is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
700 }
701
702
703
704
705 =back
706
707 =head2 Path processing and manipulation
708
709 =over 4
710
711 =item path
712
713 Returns the request path
714
715 =item parse_path
716
717 Parses the request path and sets the C<args>, C<action> and C<table>
718 properties. Calls C<preprocess_path> before parsing path and setting properties.
719
720 =cut
721
722 sub parse_path 
723 {
724     my ($self) = @_;
725     
726     # Previous versions unconditionally set table, action and args to whatever 
727     # was in @pi (or else to defaults, if @pi is empty).
728     # Adding preprocess_path(), and then setting table, action and args 
729     # conditionally, broke lots of tests, hence this:
730     $self->$_(undef) for qw/action table args/;
731     
732     $self->preprocess_path;
733
734     $self->path || $self->path('frontpage');
735     
736     my @pi = grep {length} split '/', $self->path;
737     
738     $self->table  || $self->table(shift @pi);
739     $self->action || $self->action( shift @pi or 'index' );
740     $self->args   || $self->args(\@pi);
741 }
742
743 =item preprocess_path
744
745 Sometimes when you don't want to rewrite or over-ride parse_path but
746 want to rewrite urls or extract data from them before it is parsed.
747
748 This method is called after parse_location has populated the request
749 information and before parse_path has populated the model and action
750 information, and is passed the request object.
751
752 You can set action, args or table in this method and parse_path will
753 then leave those values in place or populate them if not present
754
755 =cut
756
757 sub preprocess_path { };
758
759 =item make_path( %args or \%args or @args )
760
761 This is the counterpart to C<parse_path>. It generates a path to use
762 in links, form actions etc. To implement your own path scheme, just override
763 this method and C<parse_path>.
764
765     %args = ( table      => $table,
766               action     => $action,        
767               additional => $additional,    # optional - generally an object ID
768               );
769               
770     \%args = as above, but a ref
771     
772     @args = ( $table, $action, $additional );   # $additional is optional
773
774 C<id> can be used as an alternative key to C<additional>.
775
776 C<$additional> can be a string, an arrayref, or a hashref. An arrayref is
777 expanded into extra path elements, whereas a hashref is translated into a query
778 string. 
779
780 =cut
781
782 sub make_path
783 {
784     my $r = shift;
785     
786     my %args;
787     
788     if (@_ == 1 and ref $_[0] and ref $_[0] eq 'HASH')
789     {
790         %args = %{$_[0]};
791     }
792     elsif ( @_ > 1 and @_ < 4 )
793     {
794         $args{table}      = shift;
795         $args{action}     = shift;
796         $args{additional} = shift;
797     }
798     else
799     {
800         %args = @_;
801     }
802     
803     do { die "no $_" unless $args{$_} } for qw( table action );    
804
805     my $additional = $args{additional} || $args{id};
806     
807     my @add = ();
808     
809     if ($additional)
810     {
811         # if $additional is a href, make_uri() will transform it into a query
812         @add = (ref $additional eq 'ARRAY') ? @$additional : ($additional);
813     }    
814     
815     my $uri = $r->make_uri($args{table}, $args{action}, @add);
816     
817     return $uri->as_string;
818 }
819
820
821
822 =item make_uri( @segments )
823
824 Make a L<URI> object given table, action etc. Automatically adds
825 the C<uri_base>. 
826
827 If the final element in C<@segments> is a hash ref, C<make_uri> will render it
828 as a query string.
829
830 =cut
831
832 sub make_uri
833 {
834     my ($r, @segments) = @_;
835
836     my $query = (ref $segments[-1] eq 'HASH') ? pop(@segments) : undef;
837     
838     my $base = $r->config->uri_base; 
839     $base =~ s|/$||;
840     
841     my $uri = URI->new($base);
842     $uri->path_segments($uri->path_segments, grep {length} @segments);
843     
844     my $abs_uri = $uri->abs('/');
845     $abs_uri->query_form($query) if $query;
846     return $abs_uri;
847 }
848
849 =item parse_args
850
851 Turns post data and query string paramaters into a hash of C<params>.
852
853 You should only need to define this method if you are writing a new Maypole
854 backend.
855
856 =back
857
858 =head2 Request properties
859
860 =over 4
861
862 =item model_class
863
864 Returns the perl package name that will serve as the model for the
865 request. It corresponds to the request C<table> attribute.
866
867
868 =item objects
869
870 Get/set a list of model objects. The objects will be accessible in the view
871 templates.
872
873 If the first item in C<$self-E<gt>args> can be C<retrieve()>d by the model
874 class, it will be removed from C<args> and the retrieved object will be added to
875 the C<objects> list. See L<Maypole::Model> for more information.
876
877 =item template_args
878
879     $self->template_args->{foo} = 'bar';
880
881 Get/set a hash of template variables.
882
883 =item stash
884
885 A place to put custom application data. Not used by Maypole itself. 
886
887 =item template
888
889 Get/set the template to be used by the view. By default, it returns
890 C<$self-E<gt>action>
891
892
893 =item error
894
895 Get/set a request error
896
897 =item output
898
899 Get/set the response output. This is usually populated by the view class. You
900 can skip view processing by setting the C<output>.
901
902 =item table
903
904 The table part of the Maypole request path
905
906 =item action
907
908 The action part of the Maypole request path
909
910 =item args
911
912 A list of remaining parts of the request path after table and action
913 have been
914 removed
915
916 =item headers_in
917
918 A L<Maypole::Headers> object containing HTTP headers for the request
919
920 =item headers_out
921
922 A L<HTTP::Headers> object that contains HTTP headers for the output
923
924 =item document_encoding
925
926 Get/set the output encoding. Default: utf-8.
927
928 =item content_type
929
930 Get/set the output content type. Default: text/html
931
932 =item get_protocol
933
934 Returns the protocol the request was made with, i.e. https
935
936 =cut
937
938 sub get_protocol {
939   die "get_protocol is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
940 }
941
942 =back
943
944 =head2 Request parameters
945
946 The source of the parameters may vary depending on the Maypole backend, but they
947 are usually populated from request query string and POST data.
948
949 Maypole supplies several approaches for accessing the request parameters. Note
950 that the current implementation (via a hashref) of C<query> and C<params> is
951 likely to change in a future version of Maypole. So avoid direct access to these
952 hashrefs:
953
954     $r->{params}->{foo}      # bad
955     $r->params->{foo}        # better
956
957     $r->{query}->{foo}       # bad
958     $r->query->{foo}         # better
959
960     $r->param('foo')         # best
961
962 =over 4
963
964 =item param
965
966 An accessor (get or set) for request parameters. It behaves similarly to
967 CGI::param() for accessing CGI parameters, i.e.
968
969     $r->param                   # returns list of keys
970     $r->param($key)             # returns value for $key
971     $r->param($key => $value)   # returns old value, sets to new value
972
973 =cut
974
975 sub param 
976
977     my ($self, $key) = (shift, shift);
978     
979     return keys %{$self->params} unless defined $key;
980     
981     return unless exists $self->params->{$key};
982     
983     my $val = $self->params->{$key};
984     
985     if (@_)
986     {
987         my $new_val = shift;
988         $self->params->{$key} = $new_val;
989     }
990     
991     return ref $val ? @$val : ($val) if wantarray;
992         
993     return ref $val ? $val->[0] : $val;
994 }
995
996
997 =item params
998
999 Returns a hashref of request parameters. 
1000
1001 B<Note:> Where muliple values of a parameter were supplied, the C<params> value
1002 will be an array reference.
1003
1004 =item query
1005
1006 Alias for C<params>.
1007
1008 =back
1009
1010 =head3 Utility methods
1011
1012 =over 4
1013
1014 =item redirect_request
1015
1016 Sets output headers to redirect based on the arguments provided
1017
1018 Accepts either a single argument of the full url to redirect to, or a hash of
1019 named parameters :
1020
1021 $r->redirect_request('http://www.example.com/path');
1022
1023 or
1024
1025 $r->redirect_request(protocol=>'https', domain=>'www.example.com', path=>'/path/file?arguments', status=>'302', url=>'..');
1026
1027 The named parameters are protocol, domain, path, status and url
1028
1029 Only 1 named parameter is required but other than url, they can be combined as
1030 required and current values (from the request) will be used in place of any
1031 missing arguments. The url argument must be a full url including protocol and
1032 can only be combined with status.
1033
1034 =cut
1035
1036 sub redirect_request {
1037   die "redirect_request is a virtual method. Do not use Maypole directly; use Apache::MVC or similar";
1038 }
1039
1040 =item redirect_internal_request 
1041
1042 =cut
1043
1044 sub redirect_internal_request {
1045
1046 }
1047
1048
1049 =item make_random_id
1050
1051 returns a unique id for this request can be used to prevent or detect repeat
1052 submissions.
1053
1054 =cut
1055
1056 # Session and Repeat Submission Handling
1057 sub make_random_id {
1058     use Maypole::Session;
1059     return Maypole::Session::generate_unique_id();
1060 }
1061
1062 =back
1063
1064 =head1 SEE ALSO
1065
1066 There's more documentation, examples, and a information on our mailing lists
1067 at the Maypole web site:
1068
1069 L<http://maypole.perl.org/>
1070
1071 L<Maypole::Application>, L<Apache::MVC>, L<CGI::Maypole>.
1072
1073 =head1 AUTHOR
1074
1075 Maypole is currently maintained by Aaron Trevena
1076
1077 =head1 AUTHOR EMERITUS
1078
1079 Simon Cozens, C<simon#cpan.org>
1080
1081 Sebastian Riedel, C<sri#oook.de> maintained Maypole from 1.99_01 to 2.04
1082
1083 =head1 THANKS TO
1084
1085 Sebastian Riedel, Danijel Milicevic, Dave Slack, Jesse Sheidlower, Jody Belka,
1086 Marcus Ramberg, Mickael Joanne, Randal Schwartz, Simon Flack, Steve Simms,
1087 Veljko Vidovic and all the others who've helped.
1088
1089 =head1 LICENSE
1090
1091 You may distribute this code under the same terms as Perl itself.
1092
1093 =cut
1094
1095 1;