]> git.decadent.org.uk Git - maypole.git/blob - doc/Request.pod
Introduction to Flox, beginnings of request chapter.
[maypole.git] / doc / Request.pod
1 =head1 Maypole Request Hacking Cookbook
2
3 =head2 Frontend hacks
4
5 =head3 Changing how params are parsed
6
7 =head3 REST
8
9 =head2 Authentication hacks
10
11 =head2 Creating and editing hacks
12
13 =head3 Getting data from external sources
14
15 You want to supplement the data received from a form with additional
16 data from another source.
17
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
21 on an ISBN:
22
23     sub create_from_isbn :Exported {
24        my ($self, $r) = @_;
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)} =            
29            ($prop->title,
30            $prop->publisher,
31            (join "/", $prop->authors()),
32            $prop->year());
33        # And jump to the usual edit/create routine
34        $self->do_edit($r);
35     }
36
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.
39
40 =head2 Content display hacks
41
42 =head3 XSLT
43
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.
46
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
52 chords:
53
54     <song>
55         <header>
56             <title>Layla</title>
57             <artist>Derek and the Dominos</artist>
58             <key>Dm</key>
59         </header>
60         <lyrics>
61           <verse>...</verse>
62           <chorus>
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> 
65             ...
66  
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.
69
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:
74
75     use Songbook;
76     use XML::TreeBuilder;
77     my $t = XML::TreeBuilder->new;
78     $t->parse_file("songs.xml");
79
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({
88             title => $title,
89             first_line => $first_line,
90             song_key => Songbook::SongKey->find_or_create({name => $key}),
91             artist => Songbook::Artist->find_or_create({name => $artist}),
92             xml => $song->as_XML
93         });
94     }
95
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>:
99
100     [%
101         USE transform = XSLT("song.xsl");
102         song.xml | $transform
103     %]
104
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.
107
108 =head3 Displaying pictures
109
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.
112
113 B<Solution>: Fill the content and content-type yourself.
114
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.
120
121     sub view_picture :Exported {
122         my ($self, $r) = @_;
123         my $user = $r->{objects}->[0] || $r->{user};
124         if ($r->{content_type} = $user->photo_type) {
125            $r->{output} = $user->photo;
126         }
127     }