]> git.decadent.org.uk Git - maypole.git/blobdiff - doc/Request.pod
Another day, another 1500 words.
[maypole.git] / doc / Request.pod
index fc51d1ba854ea87900250ce5a6f90d83bf96e602..bc2b303555fedc51257a4e446fefc499def7aba8 100644 (file)
@@ -17,6 +17,38 @@ 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<BeerDB::Beer> routines in a separate module,
+so you say:
+
+    package BeerDB::Beer;
+    BeerDB::Beer->has_a(brewery => "BeerDB::Brewery");
+    sub foo :Exported {}
+
+And in F<BeerDB.pm>, you put:
+
+    use BeerDB::Beer;
+
+It doesn't work.
+
+B<Solution>: It doesn't work because of the timing of the module
+loading. C<use Beer::Beer> will try to set up the C<has_a> 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<setup> 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
@@ -577,6 +609,82 @@ on an ISBN:
 The request will carry on as though it were a normal C<do_edit> POST, but
 with the additional fields we have provided.
 
+=head3 Catching errors in a form
+
+A user has submitted erroneous input to an edit/create form. You want to
+send him back to the form with errors displayed against the erroneous
+fields, but have the other fields maintain the values that the user
+submitted.
+
+B<Solution>: This is basically what the default C<edit> template and
+C<do_edit> method conspire to do, but it's worth highlighting again how
+they work. 
+
+If there are any errors, these are placed in a hash, with each error
+keyed to the erroneous field. The hash is put into the template as
+C<errors>, and we process the same F<edit> template again:
+
+        $r->{template_args}{errors} = \%errors;
+        $r->{template} = "edit";
+
+This throws us back to the form, and so the form's template should take
+note of the errors, like so:
+
+     FOR col = classmetadata.columns;
+        NEXT IF col == "id";
+        "<P>";
+        "<B>"; classmetadata.colnames.$col; "</B>";
+        ": ";
+            item.to_field(col).as_HTML;
+        "</P>";
+        IF errors.$col;
+            "<FONT COLOR=\"#ff0000\">"; errors.$col; "</FONT>";
+        END;
+    END;
+
+If we're designing our own templates, instead of using generic ones, we
+can make this process a lot simpler. For instance:
+
+    <TR><TD>
+    First name: <INPUT TYPE="text" NAME="forename">
+    </TD>
+    <TD>
+    Last name: <INPUT TYPE="text" NAME="surname">
+    </TD></TR>
+
+    [% IF errors.forename OR errors.surname %]
+        <TR>
+        <TD><SPAN class="error">[% errors.forename %]</SPAN> </TD>
+        <TD><SPAN class="error">[% errors.surname %]</SPAN> </TD>
+        </TR>
+    [% END %]
+
+The next thing we want to do is to put the originally-submitted values
+back into the form. We can do this relatively easily because Maypole
+passes the Maypole request object to the form, and the POST parameters
+are going to be stored in a hash as C<request.params>. Hence:
+
+    <TR><TD>
+    First name: <INPUT TYPE="text" NAME="forename"
+    VALUE="[%request.params.forename%]">
+    </TD>
+    <TD>
+    Last name: <INPUT TYPE="text" NAME="surname"
+    VALUE="[%request.params.surname%]"> 
+    </TD></TR>
+
+Finally, we might want to only re-fill a field if it is not erroneous, so
+that we don't get the same bad input resubmitted. This is easy enough:
+
+    <TR><TD>
+    First name: <INPUT TYPE="text" NAME="forename"
+    VALUE="[%request.params.forename UNLESS errors.forename%]">
+    </TD>
+    <TD>
+    Last name: <INPUT TYPE="text" NAME="surname"
+    VALUE="[%request.params.surname UNLESS errors.surname%]"> 
+    </TD></TR>
+
 =head3 Uploading files and other data
 
 You want the user to be able to upload files to store in the database.