]> git.decadent.org.uk Git - maypole.git/blobdiff - doc/Request.pod
Lots more documentation.
[maypole.git] / doc / Request.pod
index 1505d361d9a014b2f0c058e4e9c3f64b7676fb0e..fc51d1ba854ea87900250ce5a6f90d83bf96e602 100644 (file)
@@ -40,9 +40,70 @@ You can also use the C<Maypole::CLI> module programatically to create
 test suites for your application. See the Maypole tests themselves or
 the documentation to C<Maypole::CLI> for examples of this.
 
-=head3 Changing how params are parsed
+=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<Solution>: So far we've been using the C</table/action/id/args> 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<parse_path>. This is responsible for taking
+C<$r-E<gt>{path}> and filling the C<table>, C<action> and C<args> slots
+of the request object. Normally it does this just by splitting the path
+on C</>s, but you can do it any way you want, including getting the
+information from C<POST> form parameters or session variables. 
+
+For instance, suppose we want our URLs to be of the form
+C<ProductDisplay.html?id=123>, we could provide a C<parse_path> 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} ];
+    }
 
-=head3 REST
+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<id> from the query. Later methods
+will confirm whether or not these tables and actions exist.
+
+See L<BuySpy.pod> 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<Solution>: 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<template_root> config parameter or, if this is not
+given, calling the C<get_template_root> 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
 
@@ -99,10 +160,6 @@ a user's page.
 This hack is so common that it's expected that there'll be a neater
 way of doing this in the future.
 
-=head3 Maypole for mobile devices
-
-XXX
-
 =head3 XSLT
 
 Here's a hack I've used a number of times. You want to store structured
@@ -194,6 +251,47 @@ itself; if your file is stored in the filesystem, but you have a file
 name or some other pointer in the database, you can still arrange for
 the data to be fetched and inserted into C<$r-E<gt>{output}>.
 
+=head3 REST
+
+You want to provide a programmatic interface to your Maypole site.
+
+B<Solution>: The best way to do this is with C<REST>, which uses a
+descriptive URL to encode the request. For instance, in L<Flox.pod> we
+describe a social networking system. One neat thing you can do with
+social networks is to use them for reputation tracking, and we can use
+that information for spam detection. So if a message arrives from
+C<person@someco.com>, we want to know if they're in our network of
+friends or not and mark the message appropriately. We'll do this by
+having a web agent (say, L<WWW::Mechanize> or L<LWP::UserAgent>) request
+a URL of the form
+C<http://flox.simon-cozens.org/user/relationship_by_email/person%40someco.com>.
+Naturally, they'll need to present the appropriate cookie just like a
+normal browser, but that's a solved problem. We're just interested in
+the REST request.
+
+The request will return a single integer status code: 0 if they're not
+in the system at all, 1 if they're in the system, and 2 if they're our
+friend.
+
+All we need to do to implement this is provide the C<relationship_by_email>
+action, and use it to fill in the output in the same way as we did when
+displaying a picture. Since C<person%40someco.com> is not the ID of a
+row in the user table, it will appear in the C<args> array:
+
+    use URI::Escape;
+    sub relationship_by_email :Exported {
+        my ($self, $r) = @_;
+        my $email = uri_unescape($r->{args}[0]);
+        $r->{content_type} = "text/plain";
+        my $user;
+        unless (($user) = Flox::User->search(email => $email)) {
+            $r->{content} = "0\n"; return;
+        }
+
+        if ($r->{user}->is_friend($user)) { $r->{content} = "2\n"; return; };
+        $r->{content} = "1\n"; return;
+    }
+
 =head3 Component-based Pages
 
 You're designing something like a portal site which has a number of