]> git.decadent.org.uk Git - maypole.git/blobdiff - doc/StandardTemplates.pod
Moved doc/*.pod to lib/Maypole/Manual/ and added new Maypole.pm
[maypole.git] / doc / StandardTemplates.pod
diff --git a/doc/StandardTemplates.pod b/doc/StandardTemplates.pod
deleted file mode 100644 (file)
index e5eb9f0..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-
-=head1 Maypole's Standard Templates and Actions
-
-As we saw in our CRUD example, Maypole does all it can to make your life
-easier; this inclues providing a set of default actions and
-factory-supplied templates. These are written in such a generic way,
-making extensive use of class metadata, that they are more or less
-applicable to any table or application. However, in order to progress
-from automatically generated CRUD applications to real customized
-applications, we need to begin by understanding how these default
-actions do their stuff, and how the default templates are put together.
-Once we have an understanding of what Maypole does for us automatically,
-we can begin to customize and create our own templates and actions.
-
-=head2 The standard actions
-
-A simple, uncustomized Maypole model class, such as one of the classes
-in the beer database application, provides the following default actions
-- that is, provides access to the following URLs:
-
-=over 3
-
-=item C</[table]/view/[id]>
-
-This takes the ID of an object in a table, retrieves the object, and
-presents it to the F<view> template.
-
-=item C</[table]/edit/[id]>
-
-This is the same as C<view>, but uses the F<edit> template to provide a
-web form to edit the object; it submits to C<do_edit>.
-
-=item C</[table]/do_edit/[id]>
-
-=item C</[table]/do_edit/>
-
-This provides both editing and row creation facilities. 
-
-=item C</[table]/delete/id>
-
-This deletes a row, returning to the C<list> page.
-
-=item C</[table]/list/>
-
-This provides a paged list of the table suitable for browsing.
-
-=item C</[table]/search/>
-
-This handles a search query and presents the search results back to the
-F<list> template.
-
-=back
-
-We'll now look at how these actions are implemented, before moving on to
-take a detailed look at the templates they drive.
-
-=head3 C<view> and C<edit>
-
-These actions are very simple; their job is to take a row ID, turn it
-into an object, and hand it to the template to be displayed. However, as
-taking the first argument and turning it into an object is such a common
-action, it is handled directly by the model class's C<process> method.
-Similarly, the default template name provided by the C<process> method
-is the name of the acction, and so will be C<view> or C<edit>
-accordingly. 
-
-So the code required to make these two actions work turns out to be:
-
-    sub view :Exported { }
-    sub edit :Exported { }
-
-That's right - no code at all. This shows the power of the templating
-side of the system. If you think about it for a moment, it is natural
-that these actions should not have any code - after all, we have
-separated out the concerns of "acting" and displaying. Both of these
-"actions" are purely concerned with displaying a record, and don't need
-to do any "acting". Remember that the "edit" method doesn't actually do
-any editing - this is provided by C<do_edit>; it is just another view of
-the data, albeit once which allows the data to be modified later. These
-two methods don't need to modify the row in any way, they don't need to
-do anything clever. They just are.
-
-So why do we need the subroutines at all? If the subroutines did not exist,
-we would be sent to the C<view> and C<edit> templates as would be
-expected, but these templates would not be provided with the right
-arguments; we need to go through the C<process> method in order to turn
-the URL argument into a row and thence into an object to be fed to the
-template. By exporting these methods, even though they contain no code
-themselves, we force Maypole to call C<process> and provide the class
-and object to the templates.
-
-The moral of this story is that if you need to have an action which is
-purely concerned with display, not acting, but needs to receive an ID
-and turn it into an object, then create an empty method. For instance,
-if we want to make an alternate view of a row which only showed the
-important columns, we might create a method
-
-    sub short_view :Exported {}
-
-This will cause the row to be turned into an object and fed to the
-C<short_view> template, and that template would be responsible for
-selecting the particular columns to be displayed.
-
-=head3 C<do_edit>
-
-This action, on the other hand, actually has to do something. If it's
-provided with an ID, this is turned into an object and we're in edit
-mode, acting upon that object. If not, we're in create mode. 
-
-    sub do_edit :Exported {
-        my ($self, $r) = @_;
-        my $h = CGI::Untaint->new(%{$r->{params}});
-        my ($obj) = @{$r->objects || []};
-        if ($obj) {
-            # We have something to edit
-            $obj->update_from_cgi($h);
-        } else {
-            $obj = $self->create_from_cgi($h);
-        }
-
-The C<CDBI> model uses L<Class::DBI::FromCGI> to turn C<POST> parameters
-into database table data. This in turn uses C<CGI::Untaint> to ensure
-that the data coming in is suitable for the table. If you're using the
-default C<CDBI> model, then, you're going to need to set up your tables
-in a way that makes C<FromCGI> happy.
-
-=over 
-
-=item Digression on C<Class::DBI::FromCGI>
-
-C<CGI::Untaint> is a mechanism for testing that incoming form data
-conforms to various properties. For instance, given a C<CGI::Untaint>
-object that encapsulates some C<POST> parameters, we can extract an
-integer like so:
-
-    $h->extract(-as_integer => "score");
-
-This checks that the C<score> parameter is an integer, and returns it if
-it is; if not, C<< $h->error >> will be set to an appropriate error
-message. Other tests by which you can extract your data are C<as_hex>
-and C<as_printable>, which tests for a valid hex number and an ordinary
-printable string respectively; there are other handlers available on
-CPAN, and you can make your own, as documented in L<CGI::Untaint>.
-
-To tell the C<FromCGI> handler what handler to use for each of your
-columns, you need to use the C<untaint_columns> methods in the classes
-representing your tables. For instance:
-
-    BeerDB::Beer->untaint_columns(
-        integer => ["score", ... ],
-    );
-
-This must be done after the call to C<setup> in your handler, because
-otherwise the model classes won't have been set up to inherit from
-C<Class::DBI::FromCGI>.
-
-Remember that if you want to use drop-downs to set the value of related
-fields, such as the brewery for a beer, you need to untaint these as
-something acceptable for the primary key of that table:
-
-    BeerDB::Beer->untaint_columns(
-        integer => ["score", "brewery", "style" ],
-        ...
-    );
-
-This is usually integer, if you're using numeric IDs for your primary
-key. If not, you probably want C<printable>, but you probably know what
-you're doing anyway.
-
-=back
-
-The data is untainted, and any errors are collected into a hash which is
-passed to the template. We also pass back in the parameters, so that the
-template can re-fill the form fields with the original values. The user
-is then sent back to the C<edit> template.
-
-        if (my %errors = $obj->cgi_update_errors) {
-            # Set it up as it was:
-            $r->{template_args}{cgi_params} = $r->{params};
-            $r->{template_args}{errors} = \%errors;
-            $r->{template} = "edit";
-        }
-
-Otherwise, the user is taken back to viewing the new object:
-
-    } else {
-        $r->{template} = "view";
-    }
-    $r->objects([ $obj ]);
-
-Notice that this does use hard-coded names for the templates to go to next.
-Feel free to override this in your subclasses:
-
-    sub do_edit :Exported {
-        my ($class, $r) = @_;
-        $class->SUPER::do_edit($r);
-        $r->template("my_edit");
-    }
-
-=head3 delete
-
-The delete method takes a number of arguments and deletes those rows from the
-database; it then loads up all rows and heads to the F<list> template.
-You almost certainly want to override this to provide some kind of
-authentication.
-
-=head3 list
-
-Listing, like viewing, is a matter of selecting objects for
-presentation. This time, instead of a single object specified in the
-URL, we want, by default, all the records in the table:
-
-    sub list :Exported {
-        my ($class, $r) = @_;
-        $r->objects([ $self->retrieve_all ])
-    }
-
-However, things are slightly complicated by paging and ordering by
-column; the default implementation also provides a C<Class::DBI::Pager>
-object to the templates and uses that to retrieve the appropriate bit of
-the data, as specified by the C<page> URL query parameter. See the F<pager> 
-template below.
-
-=head3 search
-
-Searching also uses paging, and creates a query from the C<POST>
-parameters. It uses the F<list> template to display the objects once
-they've been selected from the database.
-
-=head2 The templates and macros
-
-Once these actions have done their work, they hand a set of objects to
-the templates; if you haven't specified your own custom template
-globally or for a given class, you'll be using the factory specified
-template. Let's take a look now at each of these and how they're put
-together.
-
-The beauty of the factory specified templates is that they make use of
-the classes' metadata as supplied by the view class. Although you're
-strongly encouraged to write your own templates, in which you don't need
-to necessarily be as generic, the factory templates will always do the
-right thing for any class without further modification, and as such are
-useful examples of how to build Maypole templates.
-
-=head3 Commonalities
-
-There are certain common elements to a template, and these are extracted
-out. For instance, all the templates call the F<header> template to
-output a HTML header, and nearly all include the F<macros> template to
-load up some common template functions. We'll look at these common
-macros as we come across them.
-
-=head3 F<view> 
-
-=template view
-
-=head3 F<edit>
-
-The F<edit> template is pretty much the same as F<view>, but it uses the
-C<to_field> method on each column of an object to return a C<HTML::Element>
-object representing a form element to edit that property. These elements
-are then rendered to HTML with C<as_HTML>. It expects to see a list of
-editing errors, if any, in the C<errors> template variable:
-
-     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;
-
-=head3 F<list>
-
-Browsing records and search results are both handled by the F<list> template.
-The C<search> template argument is used to distinguish between the two cases:
-
-    [% IF search %]
-    <h2> Search results </h2>
-    [% ELSE %]
-    <h2> Listing of all [% classmetadata.plural %]</h2>
-    [% END %]
-
-=head1 Customizing Generic CRUD Applications