File Coverage

blib/lib/Maypole.pm
Criterion Covered Total %
statement 3 3 100.0
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 4 4 100.0


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