1 =head1 Maypole Request Hacking Cookbook
5 =head3 Changing how params are parsed
9 =head2 Authentication hacks
11 =head2 Creating and editing hacks
13 =head3 Getting data from external sources
15 You want to supplement the data received from a form with additional
16 data from another source.
18 B<Solution>: Munge the contents of C< $r-E<gt>params > before jumping
19 to the original C<do_edit> routine. For instance, in this method,
20 we use a C<Net::Amazon> object to fill in some fields of a database row based
23 sub create_from_isbn :Exported {
25 my $response = $ua->search(asin => $r->{params}{isbn});
26 my ($prop) = $response->properties;
27 # Rewrite the CGI parameters with the ones from Amazon
28 @{$r->{params}{qw(title publisher author year)} =
31 (join "/", $prop->authors()),
33 # And jump to the usual edit/create routine
37 The request will carry on as though it were a normal C<do_edit> POST, but
38 with the additional fields we have provided.
40 =head2 Content display hacks
44 Here's a hack I've used a number of times. You want to store structured
45 data in a database and to abstract out its display.
47 B<Solution>: You have your data as XML, because handling big chunks of
48 XML is a solved problem. Build your database schema as usual around the
49 important elements that you want to be able to search and browse on. For
50 instance, I have an XML format for songs which has a header section of
51 the key, title and so on, plus another section for the lyrics and
57 <artist>Derek and the Dominos</artist>
63 <line> <sup>A</sup>Lay<sup>Dm</sup>la <sup>Bb</sup> </line>
64 <line> <sup>C</sup>Got me on my <sup>Dm</sup>knees </line>
67 I store the title, artist and key in the database, as well as an "xml"
68 field which contains the whole song as XML.
70 To load the songs into the database, I can C<use> the driver class for
71 my application, since that's a handy way of setting up the database classes
72 we're going to need to use. Then the handy C<XML::TreeBuilder> will handle
73 the XML parsing for us:
77 my $t = XML::TreeBuilder->new;
78 $t->parse_file("songs.xml");
80 for my $song ($t->find("song")) {
81 my ($key) = $song->find("key"); $key &&= $key->as_text;
82 my ($title) = $song->find("title"); $title = $title->as_text;
83 my ($artist) = $song->find("artist"); $artist = $artist->as_text;
84 my ($first_line) = $song->find("line");
85 $first_line = join "", grep { !ref } $first_line->content_list;
86 $first_line =~ s/[,\.\?!]\s*$//;
87 Songbook::Song->find_or_create({
89 first_line => $first_line,
90 song_key => Songbook::SongKey->find_or_create({name => $key}),
91 artist => Songbook::Artist->find_or_create({name => $artist}),
96 Now we need to set up the custom display for each song; thankfully, with
97 the C<Template::Plugin::XSLT> module, this is as simple as putting the
98 following into F<templates/song/view>:
101 USE transform = XSLT("song.xsl");
102 song.xml | $transform
105 We essentially pipe the XML for the selected song through to an XSL
106 transformation, and this will fill out all the HTML we need. Job done.
108 =head3 Displaying pictures
110 You want to serve a picture, or something else which doesn't have a
111 content type of C<text/html>, out of your database.
113 B<Solution>: Fill the content and content-type yourself.
115 Here's a subroutine which displays the C<photo> for either a specified
116 user or the currently logged in user. We set the C<output> slot of the
117 Maypole request object: if this is done then the view class is not called
118 upon to process a template, since we already have some output to display.
119 We also set the C<content_type> using one from the database.
121 sub view_picture :Exported {
123 my $user = $r->{objects}->[0] || $r->{user};
124 if ($r->{content_type} = $user->photo_type) {
125 $r->{output} = $user->photo;