=head1 Maypole Request Hacking Cookbook Hacks; design patterns; recipes: call it what you like, this chapter is a developing collection of techniques which can be slotted in to Maypole applications to solve common problems or make the development process easier. As Maypole developers, we don't necessarily know the "best practice" for developing Maypole applications ourselves, in the same way that Larry Wall didn't know all about the best Perl programming style as soon as he wrote Perl. These techniques are what we're using at the moment, but they may be refined, modularized, or rendered irrelevant over time. But they've certainly saved us a bunch of hours work. =head2 Frontend hacks These hacks deal with changing the way Maypole relates to the outside world; alternate front-ends to the Apache and CGI interfaces, or subclassing chunks of the front-end modules to alter Maypole's behaviour in particular ways. =head3 Separate model class modules You want to put all the C routines in a separate module, so you say: package BeerDB::Beer; BeerDB::Beer->has_a(brewery => "BeerDB::Brewery"); sub foo :Exported {} And in F, you put: use BeerDB::Beer; It doesn't work. B: It doesn't work because of the timing of the module loading. C will try to set up the C relationships at compile time, when the database tables haven't even been set up, since they're set up by BeerDB->setup("...") which does its stuff at runtime. There are two ways around this; you can either move the C call to compile time, like so: BEGIN { BeerDB->setup("...") } or move the module loading to run-time (my preferred solution): BeerDB->setup("..."); BeerDB::Beer->require; =head3 Debugging with the command line You're seeing bizarre problems with Maypole output, and you want to test it in some place outside of the whole Apache/mod_perl/HTTP/Internet/browser circus. B: Use the C module to go directly from a URL to standard output, bypassing Apache and the network altogether. C is not a standalone front-end, but to allow you to debug your applications without having to change the front-end they use, it temporarily "borgs" an application. If you run it from the command line, you're expected to use it like so: perl -MMaypole::CLI=Application -e1 'http://your.server/path/table/action' For example: perl -MMaypole::CLI=BeerDB -e1 'http://localhost/beerdb/beer/view/1?o2=desc' You can also use the C module programatically to create test suites for your application. See the Maypole tests themselves or the documentation to C for examples of this. =head3 Changing how URLs are parsed You don't like the way Maypole URLs look, and want something that either fits in with the rest of your site or hides the internal workings of the system. C: So far we've been using the C form of a URL as though it was "the Maypole way"; well, there is no Maypole way. Maypole is just a framework and absolutely everything about it is overridable. If we want to provide our own URL handling, the method to override in the driver class is C. This is responsible for taking C<$r-E{path}> and filling the C, C and C slots of the request object. Normally it does this just by splitting the path on Cs, but you can do it any way you want, including getting the information from C form parameters or session variables. For instance, suppose we want our URLs to be of the form C, we could provide a C method like so: sub parse_path { my $r = shift; $r->{path} ||= "ProductList.html"; ($r->{table}, $r->{action}) = ($r->{path} =~ /^(.*?)([A-Z]\w+)\.html/); $r->{table} = lc $r->{table}; $r->{action} = lc $r->{action}; my %query = $r->{ar}->args; $self->{args} = [ $query{id} ]; } This takes the path, which already has the query parameters stripped off and parsed, and finds the table and action portions of the filename, lower-cases them, and then grabs the C from the query. Later methods will confirm whether or not these tables and actions exist. See L for another example of custom URL processing. =head3 Maypole for mobile devices You want Maypole to use different templates to display on particular browsers. B: There are several ways to do this, but here's the neatest we've found. Maypole chooses where to get its templates either by looking at the C config parameter or, if this is not given, calling the C method to ask the front-end to try to work it out. We can give the front-end a little bit of help, by putting this method in our driver class: sub get_template_root { my $r = shift; my $browser = $r->{ar}->headers_in->get('User-Agent'); if ($browser =~ /mobile|palm|nokia/i) { "/home/myapp/templates/mobile"; } else { "/home/myapp/templates/desktop"; } } (Maybe there's a better way to detect a mobile browser, but you get the idea.) =head2 Content display hacks These hacks deal primarily with the presentation of data to the user, modifying the C template or changing the way that the results of particular actions are displayed. =head3 Null Action You need an "action" which doesn't really do anything, but just formats up a template. B: There are two ways to do this, depending on what precisely you need. If you just need to display a template, C style, with no Maypole objects in it, then you don't need to write any code; just create your template, and it will be available in the usual way. If, on the other hand, you want to display some data, and what you're essentially doing is a variant of the C action, then you need to ensure that you have an exported action, as described in L: sub my_view :Exported { } =head3 Template Switcheroo An action doesn't have any data of its own to display, but needs to display B. B: This is an B common hack. You've just issued an action like C, which updates the database. You don't want to display a page that says "Record updated" or similar. Lesser application servers would issue a redirect to have the browser request C> instead, but we can actually modify the Maypole request on the fly and, after doing the update, pretend that we were going to C> all along. We do this by setting the objects in the C slot and changing the C