-=head1 FlOx: A Social Networking Site
+=head1 Flox: A Free Social Networking Site
+
+Friendster, Tribe, and now Google's Orkut - it seems like in early 2004,
+everyone wanted to be a social networking site. At the time, I was too
+busy to be a social networking site, as I was working on my own project
+at the time, a web application server called Maypole. However, I
+realised that if I could implement a social networking system using
+Maypole, then Maypole could probably do anything.
+
+I'd already decided there was room for a free, open-source networking
+site, and then Peter Sergeant came up with the hook - localizing it to
+universities and societies, and tying in meet-ups with restaurant
+bookings. I called it Flox, partially because it flocks people together
+and partially because it's localised for my home town of Oxford and its
+university.
+
+Flox is still in, uh, flux, but it does the essentials. In this chapter,
+we're going to see how it was put together, and how the techniques shown
+in the L<Request.pod> chapter can help to create a sophisticated web
+application. Of course, I didn't have this manual available at the time,
+so it took a bit longer than it should have done...
=head1 Maypole Request Hacking Cookbook
-=head2 Changing how params are parsed
+=head2 Frontend hacks
-=head2 Authentication
+=head3 Changing how params are parsed
-=head2 REST
+=head3 REST
-=head2 Filling Content Yourself
+=head2 Authentication hacks
+
+=head2 Creating and editing hacks
+
+=head3 Getting data from external sources
+
+You want to supplement the data received from a form with additional
+data from another source.
+
+B<Solution>: Munge the contents of C< $r-E<gt>params > before jumping
+to the original C<do_edit> routine. For instance, in this method,
+we use a C<Net::Amazon> object to fill in some fields of a database row based
+on an ISBN:
+
+ sub create_from_isbn :Exported {
+ my ($self, $r) = @_;
+ my $response = $ua->search(asin => $r->{params}{isbn});
+ my ($prop) = $response->properties;
+ # Rewrite the CGI parameters with the ones from Amazon
+ @{$r->{params}{qw(title publisher author year)} =
+ ($prop->title,
+ $prop->publisher,
+ (join "/", $prop->authors()),
+ $prop->year());
+ # And jump to the usual edit/create routine
+ $self->do_edit($r);
+ }
+
+The request will carry on as though it were a normal C<do_edit> POST, but
+with the additional fields we have provided.
+
+=head2 Content display hacks
+
+=head3 XSLT
+
+Here's a hack I've used a number of times. You want to store structured
+data in a database and to abstract out its display.
+
+B<Solution>: You have your data as XML, because handling big chunks of
+XML is a solved problem. Build your database schema as usual around the
+important elements that you want to be able to search and browse on. For
+instance, I have an XML format for songs which has a header section of
+the key, title and so on, plus another section for the lyrics and
+chords:
+
+ <song>
+ <header>
+ <title>Layla</title>
+ <artist>Derek and the Dominos</artist>
+ <key>Dm</key>
+ </header>
+ <lyrics>
+ <verse>...</verse>
+ <chorus>
+ <line> <sup>A</sup>Lay<sup>Dm</sup>la <sup>Bb</sup> </line>
+ <line> <sup>C</sup>Got me on my <sup>Dm</sup>knees </line>
+ ...
+
+I store the title, artist and key in the database, as well as an "xml"
+field which contains the whole song as XML.
+
+To load the songs into the database, I can C<use> the driver class for
+my application, since that's a handy way of setting up the database classes
+we're going to need to use. Then the handy C<XML::TreeBuilder> will handle
+the XML parsing for us:
+
+ use Songbook;
+ use XML::TreeBuilder;
+ my $t = XML::TreeBuilder->new;
+ $t->parse_file("songs.xml");
+
+ for my $song ($t->find("song")) {
+ my ($key) = $song->find("key"); $key &&= $key->as_text;
+ my ($title) = $song->find("title"); $title = $title->as_text;
+ my ($artist) = $song->find("artist"); $artist = $artist->as_text;
+ my ($first_line) = $song->find("line");
+ $first_line = join "", grep { !ref } $first_line->content_list;
+ $first_line =~ s/[,\.\?!]\s*$//;
+ Songbook::Song->find_or_create({
+ title => $title,
+ first_line => $first_line,
+ song_key => Songbook::SongKey->find_or_create({name => $key}),
+ artist => Songbook::Artist->find_or_create({name => $artist}),
+ xml => $song->as_XML
+ });
+ }
+
+Now we need to set up the custom display for each song; thankfully, with
+the C<Template::Plugin::XSLT> module, this is as simple as putting the
+following into F<templates/song/view>:
+
+ [%
+ USE transform = XSLT("song.xsl");
+ song.xml | $transform
+ %]
+
+We essentially pipe the XML for the selected song through to an XSL
+transformation, and this will fill out all the HTML we need. Job done.
+
+=head3 Displaying pictures
+
+You want to serve a picture, or something else which doesn't have a
+content type of C<text/html>, out of your database.
+
+B<Solution>: Fill the content and content-type yourself.
+
+Here's a subroutine which displays the C<photo> for either a specified
+user or the currently logged in user. We set the C<output> slot of the
+Maypole request object: if this is done then the view class is not called
+upon to process a template, since we already have some output to display.
+We also set the C<content_type> using one from the database.
+
+ sub view_picture :Exported {
+ my ($self, $r) = @_;
+ my $user = $r->{objects}->[0] || $r->{user};
+ if ($r->{content_type} = $user->photo_type) {
+ $r->{output} = $user->photo;
+ }
+ }