]> git.decadent.org.uk Git - maypole.git/commitdiff
Moved doc/*.pod to lib/Maypole/Manual/ and added new Maypole.pm
authorSebastian Riedel <sri@labs.kraih.com>
Sun, 26 Sep 2004 20:58:52 +0000 (20:58 +0000)
committerSebastian Riedel <sri@labs.kraih.com>
Sun, 26 Sep 2004 20:58:52 +0000 (20:58 +0000)
documentation

git-svn-id: http://svn.maypole.perl.org/Maypole/trunk@206 48953598-375a-da11-a14b-00016c27c3ee

21 files changed:
Changes
doc/About.pod [deleted file]
doc/Beer.pod [deleted file]
doc/BuySpy.pod [deleted file]
doc/Flox.pod [deleted file]
doc/Model.pod [deleted file]
doc/Overview.pod [deleted file]
doc/Request.pod [deleted file]
doc/StandardTemplates.pod [deleted file]
doc/View.pod [deleted file]
doc/makedoc.pl [deleted file]
lib/Maypole.pm
lib/Maypole/Manual/About.pod [new file with mode: 0644]
lib/Maypole/Manual/Beer.pod [new file with mode: 0644]
lib/Maypole/Manual/BuySpy.pod [new file with mode: 0644]
lib/Maypole/Manual/Flox.pod [new file with mode: 0644]
lib/Maypole/Manual/Model.pod [new file with mode: 0644]
lib/Maypole/Manual/Overview.pod [new file with mode: 0644]
lib/Maypole/Manual/Request.pod [new file with mode: 0644]
lib/Maypole/Manual/StandardTemplates.pod [new file with mode: 0644]
lib/Maypole/Manual/View.pod [new file with mode: 0644]

diff --git a/Changes b/Changes
index 4575ddcd483c51865e0b0f7af8e72f7002b578a2..f017a09112b61341951f0a061706932664e2b061 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,7 +1,7 @@
 Revision history for Perl extension Maypole 
 
 2.0   XXX XXX XX XX:XX:XX XXX XXXX
-    - Added parse_args() (Simon Flack)
+    - added parse_args() (Simon Flack)
     - call additional_data() and authenticate() for plain templates
     - merged Apache2::MVC (mod_perl2 support) into Apache::MVC
     - added Maypole::Application universal front-end
@@ -9,14 +9,16 @@ Revision history for Perl extension Maypole
     - $r->{query} is now deprecated, use $r->{params} for GET and POST
     - fixed multiple value handling (Simon Flack)
     - added exception handling (Simon Flack)
-    - Fixed documentation bugs
-    - Changed default documentencoding to utf8. Change with 
+    - fixed documentation bugs
+    - changed default documentencoding to utf8. Change with 
       $r->config->{document_encoding}
-    - Removed Maypole::View::Mason as it's distributed separately on CPAN.
-    - Factory templates are now XHTML 1.1 compliant.
+    - removed Maypole::View::Mason as it's distributed separately on CPAN.
+    - factory templates are now XHTML 1.1 compliant.
     - made the config hash into -> Maypole::Config
     - accessors for everything
-    - Win32 support
+    - win32 support
+    - new documentation for Maypole.pm (Simon Flack)
+    - moved doc/*.pod to lib/Maypole/Manual
 
 1.7   Sat Jul 17 20:15:26 BST 2004
     - Emergency release - we lost the "use Maypole::Constants" from
diff --git a/doc/About.pod b/doc/About.pod
deleted file mode 100644 (file)
index 3600a94..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-
-=head1 Introduction to the Maypole Request Model
-
-This chapter serves as a gentle introduction to Maypole and setting up
-Maypole applications. We look at Maypole is, how to get it up and
-running, and how to start thinking about building Maypole applications.
-
-=head2 What is Maypole?
-
-Presumably you have some idea of what Maypole is all about, or otherwise
-you wouldn't be reading this manual. But Maypole is good at many
-different things, and you may have accidentally focussed on one aspect
-of Maypole while missing the big picture.
-
-For instance, you may know that Maypole is extremely good at putting web
-front-ends onto databases. This is true, but it's only a part of what
-Maypole does. You may have heard that Maypole is a web application
-framework, which is true, but it doesn't mean very much. There are a
-huge number of things that Maypole can do, because it's very much a
-blank slate. You can make it do what you will. In this manual, we'll be
-making it act as a front-end to a database, as a social network site, as
-an intranet portal, and many other things besides. It is a framework.
-
-I like to think that Maypole is a way of going from a URL to a method
-call to some output. If you have a URL like C</product/order/12>,
-Maypole is a way of having it load up product number 12, call an
-C<order> method, and produce a page about what it's just done. The
-reason Maypole is such a big deal is because it does all this for you.
-You no longer have to care about your web server. You hardly have to
-care about your database. You don't have to care about templating
-modules, parsing CGI parameters, or anything else. You only need to care
-about business logic, and the business logic in this instance is how you
-C<order> a product, and what you need to display about it once you've
-done so. This is what programming should be: only caring about the work
-that distinguishes one program from another.
-
-It does this using a technique called MVC for web applications.
-
-=head2 What is MVC for web applications?
-
-Maypole was originally called C<Apache::MVC>, reflecting its basis in
-the Model-View-Controller design pattern. (I had to change it firstly
-because Maypole isn't tied to Apache, and secondly because
-C<Apache::MVC> is a really dull name.) It's the same design pattern that
-forms the foundation of similar projects in other languages, such as
-Java's Struts framework.
-
-This design pattern is found primarily in graphical applications; the
-idea is that you have a Model class which represents and manipulates
-your data, a View class which is responsible for displaying that data to
-the user, and a Controller class which controls the other classes in
-response to events triggered by the user. This analogy doesn't
-correspond precisely to a web-based application, but we can take an
-important principle from it. As Andy Wardley explains:
-
-    What the MVC-for-the-web crowd are really trying to achieve is a clear
-    separation of concerns.  Put your database code in one place, your 
-    application code in another, your presentation code in a third place.  
-    That way, you can chop and change different elements at will,
-    hopefully without affecting the other parts (depending on how well your
-    concerns are separated, of course).  This is common sense and good practice.
-    MVC achieves this separation of concerns as a by-product of clearly 
-    separating inputs (controls) and outputs (views). 
-
-This is what Maypole does. It has a number of database drivers, a number
-of front-end drivers and a number of templating presentation drivers.
-In common cases, Maypole provides precisely what you need for all of
-these areas, and you get to concentrate on writing just the business
-logic of your application. This is one of the reasons why Maypole lets
-you develop so rapidly: because most of the time, you don't need to do
-any development at all.
-
-=head2 Installing Maypole
-
-The first thing you're going to need to do to get Maypole running is to
-install it. Maypole needs an absolute shedload of Perl modules from CPAN
-to do its job. I am unrepentant about this. Maypole does a lot of work,
-so that you don't have to. This is called code re-use, and if we're
-serious about code re-use, then Maypole should be re-using as much code
-as possible in terms of Perl modules. In another sense, this gives the
-impression that Maypole doesn't actually do all that much itself,
-because all it's doing is gluing together already-existing code. Well,
-welcome to code re-use.
-
-The downside of code re-use is, of course, that you then have to install
-a shedload of Perl modules from CPAN. If you're using OpenBSD or
-FreeBSD, the wonderful ports system will be your friend. There's a
-Maypole port in C<p5-Maypole>. Just type C<make install>.
-
-Debian users, hang in there. There's a package coming.
-
-For other Unices, the L<CPANPLUS> or C<CPAN> modules will help with
-this. If you don't have C<CPANPLUS> installed, my recommendation is to
-use C<perl -MCPAN -e install CPANPLUS> to install it and then throw
-C<CPAN.pm> away. In any case, one of these two should get all that
-Maypole needs:
-
-    % perl -MCPANPLUS -e 'install Maypole'
-    % perl -MCPAN -e 'install Maypole'
-
-I don't know if Maypole works on Windows. I'm not sure I care.
-
-You're also going to need a database server and a web server. For
-databases, I recommend SQLite (if you install the C<DBD::SQLite> module,
-you get the SQLite library for free) for prototyping and mysql for
-production; heavier duty users should use Postgresql or Oracle - Maypole
-should be happy with them all. Maypole is happiest when running under
-Apache C<mod_perl>, with the C<Apache::Request> module installed, but as
-I said, it is a blank slate, and everything is customizable. There is a
-C<CGI::Maypole> frontend available to run as a standalone CGI script.
-
-=head2 The Beer Database example
-
-Throughout this manual, we're going to be referring back to a particular
-application so that we can give concrete examples for the concepts we're
-talking about. We could say "C<related_accessors> returns a list of
-accessors which can be called to return a list of objects in a has-a
-relationship to the original", or we could say "if we call
-C<related_accessors> on while viewing C<brewery>, it returns C<beers>,
-because we can call C<beers> on a C<brewery> object to get a list of
-that berwery's beers." 
-
-Because Maypole is all about beer. If you look carefully, you can
-probably see men playing cricket on the village green. The first
-ever Maypole application was written to help me keep track of the many
-different ales available in my area - their styles, their tastes, their
-breweries, prices and so on. Then the more I thought about it, the more
-I thought it was a particularly good data model for demonstrating
-different kinds of database relationships.
-
-We have a C<brewery> table, which has several C<beer>s. We'll call this
-a has-many relationship. The beers each have a C<style>; styles are
-stored in a separate table, so C<beer> has-a C<style>. Beers are in
-several pubs and a pub has several beers, so beers and pubs are in a
-many-to-many relationship. We use a link table called C<handpump> to
-relate pubs to beers.
-
-All in all, this gives us a schema like the following:
-
-    create table brewery (
-        id int not null auto_increment primary key,
-        name varchar(30),
-        url varchar(50),
-        notes text
-    );
-
-    create table beer (
-        id int not null auto_increment primary key,
-        brewery integer,
-        style integer, 
-        name varchar(30),
-        url varchar(120),
-        score integer(2),
-        price varchar(12),
-        abv varchar(10),
-        notes text
-    );
-
-    create table handpump (
-        id int not null auto_increment primary key,
-        beer integer,
-        pub integer
-    );
-
-    create table pub (
-        id int not null auto_increment primary key,
-        name varchar(60),
-        url varchar(120),
-        notes text
-    );
-
-    create table style (
-        id int not null auto_increment primary key,
-        name varchar(60),
-        notes text
-    );
-
-If you have C<DBD::SQLite> available, then a database like this will
-be created when Maypole was installed. Let's now see how to set it up
-with a web interface.
-
-=head2 Setting up Maypole
-
-The first thing we need for a Maypole interface to a database is to
-have a database. If you don't have one, now would be a good time to
-create one, using the schema above.
-
-The next thing we need is a module which is going to do all the work.
-Thankfully, it doesn't need to do B<all> the work itself. It's going to be a 
-subclass of C<Maypole> or a Maypole front-end like C<Apache::MVC>. 
-
-Here's the driver class for our beer database application. We're not
-going to go into much detail about it here; we'll do that in L<Beer.pod>.
-For now, simply admire its brevity, as you realise this is all the code
-you need to write for a simple database front-end:
-
-    package BeerDB;
-    use base 'Apache::MVC';
-    BeerDB->setup("dbi:SQLite:t/beerdb.db");
-    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
-    BeerDB->config->{rows_per_page} = 10;
-    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
-    BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
-    BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
-    BeerDB::Beer->untaint_columns(
-        printable => [qw/abv name price notes/],
-        integer => [qw/style brewery score/],
-        date => [ qw/date/],
-    );
-
-    use Class::DBI::Loader::Relationship;
-    BeerDB->config->{loader}->relationship($_) for (
-        "a brewery produces beers",
-        "a style defines beers",
-        "a pub has beers on handpumps");
-    1;
-
-This defines the C<BeerDB> application, which, as it inherits from 
-C<Apache::MVC>, will be a mod_perl handler. This means we need to
-tell the Apache configuration about it:
-
-    <Location /beerdb>
-        SetHandler perl-script
-        PerlHandler BeerDB
-    </Location>
-
-And now we need some templates. As we'll see in the chapter on views,
-L<View.pod>, there are several types of template. We're going to copy
-the whole lot from the F<templates/> directory of the Maypole source
-package into the F</beerdb> directory under our web root.
-
-And that's it. We should now be able to go to C<http://localhost/beerdb/>
-and see a menu of things to browse; C<http://localhost/beerdb/beer/list>
-will give a list of beers. There might not be any yet. There's a box
-that lets you add them.
-
-If you have any problems getting to this point, you might want to look
-at L<http://wiki.simon-cozens.org/index.cgi?InstallationIssues>.
-
-Play about with the site. Add some beers. Maybe go out and buy some beers
-to review if you need some inspiration. Don't be ill on my carpet.
-
-=head2 Phases of a Maypole request
-
-Now you should have a feel for what Maypole can do. The important thing
-to know at this point is that this is by no means B<all> that Maypole
-can do. What you've seen in the beer database example is all that Maypole
-can do if you don't customize it at all.
-
-Remember that, for instance, we don't ever tell Maypole what tables our
-database has, or what columns each table has. We don't tell Maypole what
-those tables should be called or how to display them. We don't tell Maypole
-what to do - that we want to list, search, edit and delete beers and breweries.
-Maypole just works that out for itself. We can customize it and have Maypole
-do all sorts of interesting things with our database, and most of the rest
-of this manual will be about how to do that.
-
-In order to do that, we need to look at what Maypole's actually doing.
-
-As mentioned, Maypole is responsible for turning a URL into an object, a
-method call, and some templated output. Here's a handy diagram to
-explain how it does that:
-
-=for html
-<IMG SRC="maypole_process2.png">
-
-Maypole's process revolves around the concept of the Maypole request
-object. This is a little like Apache's request object, but at a much
-higher level - in fact, in C<mod_perl>-based Maypole front-ends, the
-Apache request object is incorporated in the Maypole request object. All
-that Maypole does is gradually flesh out this object until it contains
-something in the C<output> member, and then it is dispatched back to the
-front-end for output.
-
-So to start with, we take the Apache request (or CGI object, or other
-way of isolating what's going on) and break it down. For instance, we
-turn the URL C</beer/view/1> into
-
-    {
-        table => "beer",
-        action => "view",
-        args => [ 1 ]
-    }
-
-Then Maypole will check that C<beer> is a real table, and find the class
-that models it. It also checks whether or not we're allowed to call the
-C<view> method over the network:
-
-    {
-        table => "beer",
-        action => "view",
-        args => [ 1 ],
-        model_class => "BeerDB::Beer"
-    }
-
-Then there's a user-defined authentication method, which by default just
-lets us do anything. Now we hand over to the model class, which loads up
-the object, and decides what template we want to use:
-
-    {
-        table => "beer",
-        action => "view",
-        args => [ ],
-        objects => [ BeerDB::Beer->retrieve(1) ],
-        model_class => "BeerDB::Beer",
-        template => "view"
-    }
-
-Then it calls C<BeerDB::Beer-E<gt>view>, passing in the request object
-as a parameter, and passes the whole lot to the view class for templating.
-In the next two chapters, we'll look at how Maypole's default model and
-view classes generally do what you want them to do.
diff --git a/doc/Beer.pod b/doc/Beer.pod
deleted file mode 100644 (file)
index 033d9ce..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-=head1 The Beer Database, Twice
-
-We briefly introduced the "beer database" example in the L<About.pod>
-material, where we presented its driver class as a fait accompli. Where
-did all that code come from, and what does it actually mean?
-
-=head2 The big beer problem
-
-I have a seriously bad habit. This is not the beer problem; this is a
-programming problem. The bad habit is that when I approach a problem I
-want to solve, I get sidetracked deeper and deeper trying to solve more
-and more generic problems, and then, satisfied with solving the generic
-problem, I never get around to solving the specific problem. I always
-write libraries for people writing libraries, and never write
-applications.
-
-The thing with really good beer is that it commands you to drink more of
-it, and then by the morning you can't remember whether it was any good
-or not. After buying several bottles of some random central African
-lager on a dim recollection that it was really good and having it turn
-out to be abysmal, this really became a problem. If only I could have a
-database that I updated every time I buy a new beer, I'd be able to tell
-whether or not I should buy that Lithuanian porter again or whether it
-would be quicker just to flush my money down the toilet and cut out the
-middle-man.
-
-The only problem with databases on Unix is that there isn't really a
-nice way to get data into them. There isn't really a Microsoft Access
-equivalent which can put a simple forms-based front-end onto an
-arbitrary database, and if there is, I either didn't like it or couldn't
-find it, and after a few brews, you really don't want to be trying to type
-in your tasting notes in raw SQL.
-
-So you see a generic problem arising out of a specific problem here. I
-didn't want to solve the specific problem of the beer database, because
-I'd already had another idea for a database that needed a front-end. So
-for two years, I sat on this great idea of having a database of tasting
-notes for beer. I even bought that damned African beer again. Enough was
-enough. I wrote Maypole.
-
-=head2 The easy way
-
-The first Maypole application was the beer database. We've already met
-it; it looks like this.
-
-    package BeerDB;
-    use base 'Apache::MVC';
-    BeerDB->set_database("dbi:SQLite:t/beerdb.db");
-    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
-    BeerDB->config->{rows_per_page} = 10;
-    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
-    BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
-    BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
-    BeerDB::Beer->untaint_columns(
-        printable => [qw/abv name price notes/],
-        integer => [qw/style brewery score/],
-        date => [ qw/date/],
-    );
-
-    use Class::DBI::Loader::Relationship;
-    BeerDB->config->{loader}->relationship($_) for (
-        "a brewery produces beers",
-        "a style defines beers",
-        "a pub has beers on handpumps");
-    1;
-
-Now, we can split this into four sections. Let's look at them one
-at a time. 
-
-=head3 Driver setup
-
-Here's the first section:
-
-    package BeerDB;
-    use base 'Apache::MVC';
-    BeerDB->setup("dbi:SQLite:t/beerdb.db");
-
-This is actually all you need for a functional database front-end. Everything
-else is configuration details. This says three things: we're an application
-called C<BeerDB>. This package is called the B<driver class>, because
-it's a relatively small class which defines how the whole application is
-going to run. 
-
-The second line says that our front-end is going to be C<Apache::MVC>,
-which is the Apache C<mod_perl> based version of Maypole; there's also
-a CGI version, C<CGI::Maypole>, and a command-line version for
-debugging, C<Maypole::CLI>, but C<Apache::MVC> is  usually the one you
-want.
-
-Thirdly we're going to need to set up our database with the given DBI
-connection string. Now the core of Maypole itself doesn't know about
-DBI; as we explained in L<Model.pod>, this argument is passed to our
-model class wholesale. As we haven't said anything about a model
-class, we get the default one, C<Maypole::Model::CDBI>, which takes a
-DBI connect string. So this one line declares that we're using a C<CDBI>
-model class and it sets up the database for us. In the same way, we
-don't say that we want a particular view class, so we get the default
-C<Maypole::View::TT>.
-
-At this point, everything is in place; we have our driver class, it uses
-a front-end, we have a model class and a view class, and we have a data
-source.
-
-=head3 Application configuration
-
-The next of our four sections is the configuration for the application itself.
-
-    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
-    BeerDB->config->{rows_per_page} = 10;
-    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
-
-Maypole provides a method called C<config> which returns a hash reference
-of the application's whole configuration. We can use this to set some
-parameters; the C<uri_base> is used as the canonical URL of the base
-of this application, and Maypole uses it to construct links.
-
-By defining C<rows_per_page>, we say that any listings we do with the
-C<list> and C<search> templates should be arranged in sets of pages, with
-a maximum of 10 items on each page. If we didn't declare that, C<list>
-would try to put all the objects on one page, which could well be bad.
-
-Finally, we declare which tables we want our Maypole front-end to
-reference. If you remember from the schema, there's a table called
-C<handpump> which acts as a linking table in a many-to-many relationship
-between the C<pub> and C<beer> tables. As it's only a linking table, we
-don't want people poking with it directly, so we exclude it from the
-list of C<display_tables>.
-
-=head3 Editability
-
-The next section is the following set of lines:
-
-    BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
-    BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
-    BeerDB::Beer->untaint_columns(
-        printable => [qw/abv name price notes/],
-        integer => [qw/style brewery score/],
-        date => [ qw/date/],
-    );
-
-As explained in L<StandardTemplates.pod>, this is an set of instructions to
-C<Class::DBI::FromCGI> regarding how the given columns should be edited.
-If we didn't have this section, we'd be able to view and delete records,
-but adding and editing them wouldn't work. It took me ages to work that
-one out.
-
-=head3 Relationships
-
-Finally, we want to explain to Maypole how the various tables relate to
-each other. This is done so that, for instance, when displaying a beer,
-the brewery does not appear as an integer like "2" but as the name of
-the brewery from the C<brewery> table with an ID of 2.
-
-The usual C<Class::DBI> way to do this involves the C<has_a> and
-C<has_many> methods, but I can never remember how to use them, so I came
-up with the C<Class::DBI::Loader::Relationship> module; this was another
-yak that needed shaving on the way to the beer database:
-
-    use Class::DBI::Loader::Relationship;
-    BeerDB->config->{loader}->relationship($_) for (
-        "a brewery produces beers",
-        "a style defines beers",
-        "a pub has beers on handpumps");
-    1;
-
-C<CDBIL::Relationship> acts on a C<Class::DBI::Loader> object and
-defines relationships between tables in a fairly free-form style.
-The equivalent in ordinary C<Class::DBI> would be:
-
-       BeerDB::Brewery->has_many(beers => "BeerDB::Beer");
-       BeerDB::Beer->has_a(brewery => "BeerDB::Brewery");
-       BeerDB::Style->has_many(beers => "BeerDB::Beer");
-       BeerDB::Beer->has_a(style => "BeerDB::Style");
-
-       BeerDB::Handpump->has_a(beer => "BeerDB::Beer");
-       BeerDB::Handpump->has_a(pub => "BeerDB::Pub");
-       BeerDB::Pub->has_many(beers => [ BeerDB::Handpump => 'beer' ]);
-       BeerDB::Beer->has_many(pubs => [ BeerDB::Handpump => 'pub' ]);
-
-Maypole's default templates will use this information to display, for
-instance, a list of a brewery's beers on the brewery view page.
-
-This is the complete beer database application; Maypole's default templates
-and the actions in the view class do the rest. But what if we want to do a
-little more. How would we begin to extend this application?
-
-=head2 The hard way
-
-Maypole was written because I don't like writing more Perl code than is
-necessary. I also don't like writing HTML. In fact, I don't really get
-on this whole computer thing, to be honest. But we'll start by ways that
-we can customize the beer application simply by adding methods or
-changing properties of the Perl driver code.
-
-The first thing we ought to look into is the names of the columns; most
-of them are fine, but that "Abv" column stands out. I'd rather that was
-"A.B.V.". Maypole uses the C<column_names> method to map between the
-names of the columns in the database to the names it displays in the
-default templates. This is provided by C<Maypole::Model::Base>, and
-normally, it does a pretty good job; it turns C<model_number> into
-"Model Number", for instance, but there was no way it could guess that
-C<abv> was an abbreviation. Since it returns a hash, the easiest way
-to correct it is to construct a hash consisting of the bits it got
-right, and then override the bits it got wrong:
-
-    package BeerDB::Beer;
-    sub column_names { 
-        (shift->SUPER::column_names(), abv => "A.B.V.")
-    }
-
-Similarly, the order of columns is a bit wonky. We can fix this by
-overriding the C<display_columns> method; this is also a good way to
-hide away any columns we don't want to have displayed, in the same way
-as declaring the C<display_tables> configuration parameter let us hide
-away tables we weren't using:
-
-    sub display_columns { 
-        ("name", "brewery", "style", "price", "score", "abv", "notes")
-    }
-
-Hey, have you noticed that we haven't done anything with the
-beers/handpumps/pubs thing yet? Good, I was hoping that you hadn't.
-Ayway, this is because Maypole can't tell easily that a C<BeerDB::Beer>
-object can call C<pubs> to get a list of pubs. Not yet, at least; we're
-working on it. In the interim, we can explicitly tell Maypole which
-accessors are related to the C<BeerDB::Beer> class like so:
-
-    sub related { "pubs" }
-
-Now when we view a beer, we'll have a list of the pubs that it's on at.
diff --git a/doc/BuySpy.pod b/doc/BuySpy.pod
deleted file mode 100644 (file)
index ef3d872..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-=head1 The Maypole iBuySpy Portal
-
-I think it's good fun to compare Maypole
-
-We begin with a length process of planning and investigating the
-sources. Of prime interest is the database schema and the initial data,
-which we convert to a Mysql database. Converting MS SQL to Mysql is not fun.
-I shall spare you the gore. Especially the bit where the default insert IDs
-didn't match up between the tables.
-
-The C<ibsportal> database has a number of tables which describe how the
-portal should look, and some tables which describe the data that should
-appear on it. The portal is defined in terms of a set of modules; each
-module takes some data from somewhere, and specifies a template to be
-used to format the data. This is quite different from how Maypole
-normally operates, so we have a choice as to whether we're going to
-completely copy this design, or use a more "natural" implementation in 
-terms of having the portal display defined as a template itself, with
-all the modules specified right there in Template Toolkit code rather
-than picked up from the database. This would be much faster, since you
-get one shot of rendering instead of having to process each module's
-template independently. The thing is, I feel like showing off
-precisely how flexible Maypole is, so we'll do it the hard way.
-
-The first thing we need to do is get the database into some sort of
-useful shape, and work out the relationships between the tables. This of
-course requires half a day of playing with GraphViz, Omnigraffle and
-mysql, but ended up with something like this:
-
-=for html
-<img src="ibs-schema.png">
-
-This leads naturally to the following driver code:
-
-    package Portal;
-    use base 'Apache::MVC';
-    Portal->setup("dbi:mysql:ibsportal");
-    use Class::DBI::Loader::Relationship;
-    Portal->config->{loader}->relationship($_) for (
-        "A module has a definition",  "A module has settings",
-        "A tab has modules",          "A portal has tabs",
-        "A role has a portal",        "A definition has a portal",
-        "A module has announcements", "A module has contacts",
-        "A module has discussions",   "A module has events",
-        "A module has htmltexts",     "A module has links",
-        "A module has documents",
-        "A user has roles via userrole"
-    );
-    1;
-
-As you can see, a portal is made up of a number of different tabs;
-the tabs contain modules, but they're separated into different panes,
-so a module knows whether it belongs on the left pane, the right pane
-or the center. A module also knows where it appears in the pane.
-
-We'll begin by mocking up the portal view in plain text, like so:
-
-    use Portal;
-    my $portal = Portal::Portal->retrieve(2);
-    for my $tab ($portal->tabs) {
-        print $tab,"\n";
-        for my $pane (qw(LeftPane ContentPane RightPane)) {
-            print "\t$pane:\n";
-            for (sort { $a->module_order <=> $b->module_order }
-                $tab->modules(pane => $pane)) {
-                print "\t\t$_:\t", $_->definition,"\n";
-            }
-        }
-        print "\n";
-    }
-
-This dumps out the tabs of our portal, along with the modules in each
-tab and their types; this lets us check that we've got the database
-set up properly. If we have, it should produce something like this:
-
-    Home
-            LeftPane:
-                    Quick link:     Quicklink
-            ContentPane:
-                    Welcome to the IBuySpy Portal:  Html Document
-                    News and Features:      announcement
-                    Upcoming event: event
-            RightPane:
-                    This Week's Special:    Html Document
-                    Top Movers:     XML/XSL
-
-    ...
-
-Now we want to get the front page up; for the moment, we'll just have it
-display the module names and their definitions like our text mock-up,
-and we'll flesh out the actual modules later.
-
-But before we do that, we'll write a front-end URL handler method, to
-allow us to ape the ASP file names. Why do we want to make a Maypole
-site look like it's running C<.aspx> files? Because we can! - and
-because I want to show we don't necessarily B<have> to follow the
-Maypole tradition of having our URLs look like
-C</I<table>/I<action>/I<id>/I<arguments>>. 
-
-    our %pages = (
-        "DesktopDefault.aspx" => { action => "view", table => "tab" },
-        "MobileDefault.aspx"  => { action => "view_mobile", table => "tab" },
-    );
-
-    sub parse_path {
-        my $self = shift;
-        $self->{path} ||= "DesktopDefault.aspx";
-        return $self->SUPER::parse_path if not exists $pages{$self->{path}};
-        my $page = $pages{$self->{path}} ;
-        $self->{action} = $page->{action};
-        $self->{table} = $page->{table};
-        my %query = $self->{ar}->args;
-        $self->{args} = [ $query{tabid} || $query{ItemID} || 1];
-    }
-
-    1;
-
-Here we're overriding the C<parse_path> method which takes the C<path>
-slot from the request and populates the C<table>, C<action> and
-C<arguments> slots. If the user has asked for a page we don't know
-about, we ask the usual Maypole path handling method to give it a try;
-this will become important later on. We turn the default page,
-C<DesktopDefault.aspx>, into the equivalent of C</tab/view/1> unless
-another C<tabid> or C<ItemID> is given in the query parameters; this allows us
-to use the ASP.NET-style C<DesktopDefault.aspx?tabid=3> to select a tab.
-
-Now we have to create our C<tab/view> template; the majority of
-this is copied from the F<DesktopDefault.aspx> source, but our panes
-look like this:
-
-    <td id="LeftPane" Width="170">
-        [% pane("LeftPane") %]
-    </td>
-    <td width="1">
-    </td>
-    <td id="ContentPane" Width="*">
-        [% pane("ContentPane") %]
-    </td>
-    <td id="RightPane" Width="230">
-        [% pane("RightPane") %]
-    </td>
-    <td width="10">
-        &nbsp;
-   </td>
-
-The C<pane> macro has to be the Template Toolkit analogue of the Perl code
-we used for our mock-up:
-
-    [% MACRO pane(panename) BLOCK;
-        FOR module = tab.modules("pane", panename);
-            "<P>"; module; " - "; module.definition; "</P>";
-        END;
-    END;
-
-Now, the way that the iBuySpy portal works is that each module has a
-definition, and each definition contains a path to a template:
-C<$module-E<gt>definition-E<gt>DesktopSrc> returns a path name for an C<ascx>
-component file. All we need to do is convert those files from ASP to the
-Template Toolkit, and have Maypole process each component for each module,
-right?
-
-=head2 Components and templates
-
-Dead right, but it was here that I got too clever. I guess it was the word
-"component" that set me off. I thought that since the page was made up of a
-large number of different modules, all requiring their own set of objects, I
-should use a seperate Maypole sub-request for each one, as shown in the
-"Component-based pages" recipe in L<Request.pod>.
-
-So this is what I did. I created a method in C<Portal::Module> that would
-set the template to the appropriate C<ascx> file:
-
-    sub view_desktop :Exported {
-        my ($self, $r) = @_;
-        $r->{template} = $r->objects->[0]->definition->DesktopSrc;
-    }
-
-and changed the C<pane> macro to fire off a sub-request for each module:
-
-    [% MACRO pane(panename) BLOCK;
-        FOR module = tab.modules("pane", panename);
-            SET path = "/module/view_desktop/" _ module.id;
-            request.component(path);
-        END;
-    END; %]
-
-This did the right thing, and a call to C</module/view_desktop/12> would
-look up the C<Html Document> module definition, find the C<DesktopSrc> to
-be F<DesktopModules/HtmlModule.ascx>, and process module 12 with that
-template. Once I had converted F<HtmlModule.ascx> to be a Template Toolkit
-file (and we'll look at the conversion of the templates in a second) it
-would display nicely on my portal.
-
-Except it was all very slow; we were firing off a large number of Maypole
-requests in series, so that each template could get at the objects it
-needed. Requests were taking 5 seconds.
-
-That's when it dawned on me that these templates don't actually need different
-objects at all. The only object of interest that C</module/view_desktop> is
-passing in is a C<module> object, and each template figures everything out by
-accessor calls on that. But we already have a C<module> object, in our C<FOR>
-loop - we're using it to make the component call, after all! Why not just
-C<PROCESS> each template inside the loop directly?
-
-    [% MACRO pane(panename) BLOCK;
-        FOR module = tab.modules("pane", panename);
-            SET src = module.definition.DesktopSrc;
-            TRY;
-                PROCESS $src;
-            CATCH DEFAULT;
-                "Bah, template $src broke on me!";
-            END;
-        END;
-    END; %]
-
-This worked somewhat better, and took request times from 5 seconds down
-to acceptable sub-second levels again. I could take the C<view_desktop>
-method out again; fewer lines of code to maintain is always good. Now
-all that remained to do for the view side of the portal was to convert
-our ASP templates over to something sensible.
-
-=head2 ASP to Template Toolkit
-
-They're all much of a muchness, these templating languages. Some of
-them, though, are just a wee bit more verbose than others. For instance,
-the banner template which appears in the header consists of 104 lines
-of ASP code; most of those are to create the navigation bar of tabs
-that we can view. Now I admit that we're slightly cheating at the moment
-since we don't have the concept of a logged-in user and so we don't
-distinguish between the tabs that anyone can see and those than only an
-admin can see, but we'll come back to it later. Still, 104 lines, eh?
-
-The actual tab list is presented here: (reformated slightly for sanity)
-
-    <tr>
-        <td>
-            <asp:datalist id="tabs" cssclass="OtherTabsBg" 
- repeatdirection="horizontal" ItemStyle-Height="25" 
- SelectedItemStyle-CssClass="TabBg" ItemStyle-BorderWidth="1" 
- EnableViewState="false" runat="server">
-                <ItemTemplate>
-                    &nbsp;<a href='<%= Request.ApplicationPath %>/
- DesktopDefault.aspx?tabindex=<%# Container.ItemIndex %>&tabid=
- <%# ((TabStripDetails) Container.DataItem).TabId %>' class="OtherTabs">
- <%# ((TabStripDetails) Container.DataItem).TabName %></a>&nbsp;
-                </ItemTemplate>
-                <SelectedItemTemplate>
-                    &nbsp;<span class="SelectedTab">
- <%# ((TabStripDetails) Container.DataItem).TabName %></span>&nbsp;
-                </SelectedItemTemplate>
-            </asp:datalist>
-        </td>
-    </tr>
-
-But it has to be built up in some 22 lines of C# code which creates and
-populates an array and then binds it to a template parameter. See those
-C<E<lt>%#> and C<E<lt>%=> tags? They're the equivalent of our Template
-Toolkit C<[% %]> tags. C<Request.ApplicationPath>? That's our C<base>
-template argument. 
-
-In our version we ask the portal what tabs it has, and display the
-list directly, displaying the currently selected tab differently:
-
-    <table id="Banner_tabs" class="OtherTabsBg" cellspacing="0" border="0">
-        <tr>
-    [% FOR a_tab = portal.tabs %]
-        [% IF a_tab.id == tab.id %]
-            <td class="TabBg" height="25">
-                &nbsp;<span class="SelectedTab">[%tab.name%]</span>&nbsp;
-        [% ELSE %]
-            <td height="25">
-                &nbsp;<a href='[%base%]DesktopDefault.aspx?tabid=[%a_tab.id%]' 
-                class="OtherTabs">[%a_tab.name%]</a>&nbsp;
-        [% END %]
-            </td>
-    [% END %]
-        </tr>
-    </table>
-
-This is the way the world should be. But wait, where have we pulled this
-C<portal> variable from? We need to tell the C<Portal> class to put the
-default portal into the template arguments:
-
-    sub additional_data {
-        shift->{template_args}{portal} = Portal::Portal->retrieve(2);
-    }
-
-Translating all the other ASP.NET components is a similar exercise in drudgery;
-on the whole, there was precisely nothing interesting about them at all - we
-merely converted a particularly verbose templating language (and if I never see
-C<asp:BoundColumn> again, it'll be no loss) into a rather more sophisticated
-one.
-
-The simplest component, F<HtmlModule.ascx>, asks a module for its associated
-C<htmltexts>, and then displays the C<DesktopHtml> for each of them in a table.
-This was 40 lines of ASP.NET, including more odious C# to make the SQL calls
-and retrieve the C<htmltexts>. But we can do all that retrieval by magic, so
-our F<HtmlModule.ascx> looks like this:
-
-    [% PROCESS module_title %]
-    <portal:title EditText="Edit" EditUrl="~/DesktopModules/EditHtml.aspx" />
-    <table id="t1" cellspacing="0" cellpadding="0">
-        <tr valign="top">
-            <td id="HtmlHolder">
-            [% FOR html = module.htmltexts; html.DesktopHtml; END %]
-            </td>
-        </tr>
-    </table>
-
-Now I admit that we've cheated here and kept that C<portal:title> tag
-until we know what to do with it - it's obvious that we should turn
-it into a link to edit the HTML of this module if we're allowed to.
-
-The next simplest one actually did provide a slight challenge;
-F<ImageModule.ascx> took the height, width and image source properties
-of an image from the module's C<settings> table, and displayed an C<IMG>
-tag with the appropriate values. This is only slightly difficult because
-we have to arrange the array of C<module.settings> into a hash of
-C<key_name> => C<setting> pairs. Frankly, I can't be bothered to do this
-in the template, so we'll add it into the C<template_args> again. This
-time C<addition_data> looks like:
-
-    sub additional_data {
-        my $r = shift;
-        shift->{template_args}{portal} = Portal::Portal->retrieve(2);
-        if ($r->{objects}->[0]->isa("Portal::Module")) {
-            $r->{template_args}{module_settings} =
-                { map { $_->key_name, $_->setting } 
-                  $r->{objects}->[0]->settings };
-        }
-    }
-
-And the F<ImageModule.ascx> drops from the 30-odd lines of ASP into:
-
-    [% PROCESS module_title; %]
-    <img id="Image1" border="0" src="[% module_settings.src %]" 
-      width="[% module_settings.width %]" 
-      height="[% module_settings.height %]" />
-    <br>
-
-Our portal is taking shape; after a few more templates have been translated,
-we now have a complete replica of the front page of the portal and all its
-tabs. It's fast, it's been developed rapidly, and it's less than 50 lines
-of Perl code so far. But it's not finished yet.
-
-=head2 Adding users
-
diff --git a/doc/Flox.pod b/doc/Flox.pod
deleted file mode 100644 (file)
index f42bc2e..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-=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 - 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 student population.
-
-Flox is still in, uh, flux, but it does the essentials. 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...
-
-=head2 Mapping the concepts
-
-Any Maypole application should start with two things: a database schema,
-and some idea of what the pages involved are going to look like.
-Usually, these pages will be tying to displaying or editing some element
-of the database, so these two concepts should come hand in hand.
-
-When I started looking at social networking sites, I began by
-identifying the concepts which were going to make up the tables of the
-application. At its most basic, a site like Orkut or Flox has two
-distinct concepts: a user, and a connection between two users.
-Additionally, there's the idea of an invitation to a new user, which can
-be extended, accepted, declined or ignored. These three will make up the
-key tables; there are an extra two tables in Flox, but they're
-essentially enumerations that are a bit easier to edit: each user has an
-affiliation to a particular college or department, and a status in the
-university. (Undergraduate, graduate, and so on.)
-
-For this first run-through, we're going to ignore the ideas of societies
-and communities, and end up with a schema like so:
-
-    CREATE TABLE user (
-        id int not null auto_increment primary key,
-        first_name varchar(50),
-        last_name varchar(50),
-        email varchar(255),
-        profile text,
-        password varchar(255),
-        affiliation int,
-        unistatus int,
-        status ENUM("real", "invitee"),
-        photo blob,
-        photo_type varchar(30)
-    );
-
-    CREATE TABLE connection (
-        id int not null auto_increment primary key,
-        from_user int,
-        to_user int,
-        status ENUM("offered", "confirmed")
-    );
-
-    CREATE TABLE invitation (
-        id char(32) not null primary key,
-        issuer int,
-        recipient int,
-        expires date
-    );
-
-Plus the definition of our two auxilliary tables:
-
-    CREATE TABLE affiliation (
-        id int not null auto_increment primary key,
-        name varchar(255)
-    );
-
-    CREATE TABLE unistatus (
-        id int not null auto_increment primary key,
-        name varchar(255)
-    );
-
-Notice that, for simplicity, invitations and friendship connections are
-quite similar: they are extended from one user to another. This means
-that people who haven't accepted an invite yet still have a place in the
-user table, with a different C<status>. Similarly, a connection between
-users can be offered, and when it is accepted, its status is changed to
-"confirmed" and a reciprocal relationship put in place.
-
-We also have some idea, based on what we want to happen, of what pages
-and actions we're going to define. Leaving the user aside for the
-moment, we want an action which extends an invitation from the current
-user to a new user. We want a page the new user can go to in order to
-accept that invitation. Similarly, we want an action which offers a
-friendship connection to an existing user, and a page the user can go to
-to accept or reject it. This gives us five pages so far:
-
-    invitation/issue
-    invitation/accept
-
-    user/befriend
-    connection/accept
-    connection/reject
-
-Notice that the C<befriend> action is performed on a user, not a
-connection. This is distinct from C<invitation/issue> because when
-befriending, we have a real user on the system that we want to do
-something to. This makes sense if you think of it in terms of object
-oriented programming - we could say
-
-    Flox::Connection->create(to => $user)
-
-but it's clearer to say
-
-    $user->befriend
-
-Similarly, we could say
-
-    Flox::User->create({ ... })->issue_invitation_to
-
-but it's clearer to say
-
-    Flox::Invitation->issue( to => Flox::User->create({ ... }) )
-
-because it more accurately reflects the principal subject and object of
-these actions.
-
-Returning to look at the user class, we want to be able to view a user's
-profile, edit one's own profile, set up the profile for the first
-time, upload pictures and display pictures. We also need to handle the
-concepts of logging in and logging out.
-
-As usual, though, we'll start with a handler class which sets up the
-database:
-
-    package Flox;
-    use base qw(Apache::MVC);
-    Flox->setup("dbi:mysql:flox");
-    Flox->config->{display_tables} = [qw[user invitation connection]];
-    1;
-
-Very simple, as these things are meant to be. Now let's build on it.
-
-=head2 Authentication
-
-The concept of a current user is absolutely critical in a site like
-Flox; it represents "me", the viewer of the page, as the site explores
-the connections in my world. We've described the authentication hacks
-briefly in the L<Request.pod> chapter, but now it's time to go into a
-little more detail about how user handling is done.
-
-XXX
-
-We also want to be able to refer to the current user from the templates,
-so we use the overridable C<additional_data> method to give us a C<my>
-template variable:
-
-    sub additional_data { 
-        my $r = shift; $r->{template_args}{my} = $r->{user}; 
-    }
-
-I've called it C<my> rather than C<me> because we it lets us check 
-C<[% my.name %]>, and so on.
-
-=head2 Viewing a user
-
-The first page that a user will see after logging in will be their own
-profile, so in order to speed development, we'll start by getting a
-C<user/view> page up.
-
-The only difference from a programming point of view between this action
-and the default C<view> action is that, if no user ID is given, then we
-want to view "me", the current user. Remembering that the default view
-action does nothing, our C<Flox::User::view> action only needs to do
-nothing plus ensure it has a user in the C<objects> slot, putting
-C<$r-E<gt>{user}> in there if not:
-
-    sub view :Exported {
-        my ($class, $r) = @_;
-        $r->{objects} = [ $r->{user} ] unless @{$r->{objects}||[]};
-    }
-
-Maypole, unfortunately, is very good at making programming boring. The
-downside of having to write very little code at all is that we now have
-to spend most of our time writing nice HTML for the templates.
-
-XXX
-
-The next stage is viewing the user's photo. Assuming we've got the photo
-stored in the database already (which is a reasonable assumption for the
-moment since we don't have a way to upload a photo quite yet) then we
-can use the a variation of the "Displaying pictures" hack from the 
-Requests chapter:
-
-    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;
-        } else {
-           # Read no-photo photo
-           $r->{content_type} = "image/png";
-           $r->{output} = slurp_file("images/no-photo.png");
-        }
-    }
-
-We begin by getting a user object, just like in the C<view> action: either
-the user whose ID was passed in on the URL, or the current user. Then
-we check if a C<photo_type> has been set in this user's record. If so,
-then we'll use that as the content type for this request, and the data
-in the C<photo> attribute as the data to send out. The trick here is
-that setting C<$r-E<gt>{output}> overrides the whole view class processing
-and allows us to write the content out directly.
-
-In our template, we can now say
-
-    <IMG SRC="/user/view_picture/[% user.id %]">
-
-and the appropriate user's mugshot will appear.
-
-However, if we're throwing big chunks of data around like C<photo>, it's
-now worth optimizing the C<User> class to ensure that only pertitent
-data is fetched by default, and C<photo> and friends are only fetched on
-demand. The "lazy population" section of C<Class::DBI>'s man page
-explains how to group the columns by usage so that we can optimize
-fetches:
-
-    Flox::User->columns(Primary   => qw/id/);
-    Flox::User->columns(Essential => qw/status/);
-    Flox::User->columns(Helpful   => qw/ first_name last_name email password/)
-    Flox::User->columns(Display   => qw/ profile affiliation unistatus /);
-    Flox::User->columns(Photo     => qw/ photo photo_type /);
-
-This means that the status and ID columns will always be retrieved when
-we deal with a user; next, any one of the name, email or password
-columns will cause that group of data to be retrieved; if we go on to
-display more information about a user, we also load up the profile,
-affiliation and university status; finally, if we're throwing around
-photos, then we load in the photo type and photo data.
-
-These groupings are somewhat arbitrary, and there needs to be a lot of
-profiling to determine the most efficient groupings of columns to load,
-but they demonstrate one principle about working in Maypole: this is the
-first time in dealing with Maypole that we've had to explicitly list the
-columns of a table, but Maypole has so far Just Worked. There's a
-difference, though, between Maypole just working and Maypole working
-well, and if you want to optimize your application, then you need to
-start putting in the code to do that. The beauty of Maypole is that you
-can do as much or as little of such optimization as you want or need.
-
-So now we can view users and their photos. It's time to allow the users
-to edit their profiles and upload a new photo.
-
-=head2 Editing users
-
-XXX Editing a profile
-
-I introduced Flox to a bunch of friends and told them to be as ruthless
-as possible in finding bugs and trying to break it. And break it they
-did; within an hour the screens were thoroughly messed up as users had
-nasty HTML tags in their profiles, names, email addresses and so on. 
-This spawned another hack in the request cookbook: "Limiting data for
-display". I changed the untaint columns to use C<html> untainting, and
-all was better:
-
-    Flox::User->untaint_columns(
-        html      => [qw/first_name last_name profile/],
-        printable => [qw/password/],
-        integer   => [qw/affiliation unistatus /],
-        email     => [qw/email/]
-    );
-
-The next stage was the ability to upload a photo. We unleash the "Uploading
-files" recipe, with an additional check to make sure the photo is of a
-sensible size:
-
-    use constant MAX_IMAGE_SIZE => 512 * 1024;
-    sub do_upload :Exported {
-        my ($class, $r) = @_;
-        my $user = $r->{user};
-        my $upload = $r->{ar}->upload("picture");
-        if ($upload) {
-            my $ct = $upload->info("Content-type");
-            return $r->error("Unknown image file type $ct")
-                if $ct !~ m{image/(jpeg|gif|png)};
-            return $r->error("File too big! Maximum size is ".MAX_IMAGE_SIZE)
-                if $upload->size > MAX_IMAGE_SIZE;
-
-            my $fh = $upload->fh;
-            my $image = do { local $/; <$fh> };
-
-            use Image::Size;
-            my ($x, $y) = imgsize(\$image);
-            return $r->error("Image too big! ($x, $y) Maximum size is 350x350")
-                if $y > 350 or $x > 350;
-            $r->{user}->photo_type($ct);
-            $r->{user}->photo($image);
-        }
-
-        $r->objects([ $user ]);
-        $r->{template} = "view";
-    }
-
-Now we've gone as far as we want to go about user editing at the moment.
-Let's have a look at the real meat of a social networking site: getting
-other people involved, and registering connections between users. 
-
-=head2 Invitations
-
-We need to do two things to invitations working: first provide a way to
-issue an invitation, and then provide a way to accept it. Since what
-we're doing in issuing an invitation is essentially creating a new
-one, we'll use our usual practice of having a page to display the form
-to offer an invitation, and then use a C<do_edit> method to actually do
-the work. So our C<issue> method is just an empty action:
-
-    sub issue :Exported {}
-
-and the template proceeds as normal:
-
-    [% PROCESS header %]
-    <h2> Invite a friend </h2>
-
-    <FORM ACTION="[%base%]/invitation/do_edit/" METHOD="post">
-    <TABLE>
-
-Now we use the "Catching errors in a form" recipe from L<Request.pod> and
-write our form template:
-
-    <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>
-    [% 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 %]
-    <TR>
-    ...
-
-Now we need to work on the C<do_edit> action. This has to validate the
-form parameters, create the invited user, create the row in the C<invitation>
-table, and send an email to the new user asking them to join.
-
-We'd normally use C<create_from_cgi> to do the first two stages, but this time
-we handle the untainting manually, because there are a surprising number of
-things we need to check before we actually do the create. So here's the
-untainting of the parameters:
-
-    my ($self, $r) = @_;
-    my $h = CGI::Untaint->new(%{$r->{params}});
-    my (%errors, %ex);
-    for (qw( email forename surname )) {
-        $ex{$_} = $h->extract(
-                "-as_".($_ eq "email" ? "email" : "printable") => $_
-        ) or $errors{$_} = $h->error;
-    }
-
-Next, we do the usual dance of throwing the user back at the form in case
-of errors:
-
-    if (keys %errors) {
-        $r->{template_args}{message} = "There was something wrong with that...";
-        $r->{template_args}{errors} = \%errors;
-        $r->{template} = "issue";
-        return;
-    }
-
-We've introduced a new template variable here, C<message>, which we'll use
-to display any important messages to the user.
-
-The first check we need to do is whether or not we already have a user
-with that email address. If we have, and they're a real user, then we
-abort the invite progress and instead redirect them to viewing that user's 
-profile.
-
-    my ($user) = Flox::User->search({ email => $ex{email} });
-    if ($user) {
-        if ($user->status eq "real") {
-            $r->{template_args}{message} =
-                "That user already seems to exist on Flox. ".
-                "Is this the one you meant?";
-
-            $self->redirect_to_user($r,$user);
-        } 
-
-Where C<redirect_to_user> looks like this:
-
-    sub redirect_to_user {
-        my ($self, $r, $user) = @_;
-        $r->{objects} = [ $user ];
-        $r->{template} = "view";
-        $r->{model_class} = "Flox::User"; # Naughty.
-    }
-
-This is, as the comment quite rightly points out, naughty. We're currently
-doing a C</invitation/do_edit/> and we want to turn this into a
-C</user/view/xxx>, changing the table, template and arguments all at once.
-To do this, we have to change the Maypole request object's idea of the model
-class, since this determines where to look for the template: if we didn't,
-we'd end up with C<invitation/view> instead of C<user/view>.
-
-Ideally, we'd do this with a Apache redirect, but we want to get that
-C<message> in there as well, so this will have to do. This isn't good practice;
-we put it into a subroutine so that we can fix it up if we find a better way
-to do it.
-
-Anyway, this is what we should do if a user already exists on the system
-and has accepted an invite already. What if we're trying to invite a user but
-someone else has invited them first and they haven't replied yet?
-
-         } else {
-            # Put it back to the form
-            $r->{template_args}{message} =
-            "That user has already been invited; ".
-            "please wait for them to accept";
-            $r->{template} = "issue";
-        }
-        return;
-    }
-
-Race conditions suck.
-
-Okay. Now we know that the user doesn't exist, and so can create the new 
-one:
-
-    my $new_user = Flox::User->create({
-        email => $ex{email},
-        first_name => $ex{forename},
-        last_name  => $ex{surname},
-        status => "invitee"
-    });
-
-We want to give the invitee a URL that they can go to in order to
-accept the invite. Now we don't just want the IDs of our invites to
-be sequential, since someone could get one invite, and then guess the
-rest of the invite codes. We provide a relatively secure MD5 hash as
-the invite ID:
-
-    my $random = md5_hex(time.(0+{}).$$.rand);
-
-For additional security, we're going to have the URL in the form
-C</invitation/accept/I<id>/I<from_id>/I<to_id>>, encoding the user ids
-of the two users. Now we can send email to the invitee to ask them to
-visit that URL:
-
-    my $newid = $new_user->id;
-    my $myid  = $r->{user}->id;
-    _send_mail(to => $ex{email}, url => "$random/$myid/$newid", 
-               user => $r->{user});
-
-I'm not going to show the C<_send_mail> routine, since it's boring.
-We haven't actually created the C<Invitation> object yet, so let's
-do that now.
-
-    Flox::Invitation->create({
-        id => $random,
-        issuer => $r->{user},
-        recipient => $new_user,
-        expires => Time::Piece->new(time + LIFETIME)->datetime
-    });
-
-You can also imagine a daily cron job that cleans up the C<Invitation>
-table looking for invitations that ever got replied to within their
-lifetime:
-
-   ($_->expires > localtime && $_->delete)
-       for Flox::Invitation->retrieve_all;
-
-Notice that we don't check whether the ID is already used. We could, but,
-you know, if MD5 sums start colliding, we have much bigger problems on
-our hands.
-
-Anyway, now we've got the invitation created, we can go back to whence we
-came: viewing the original user:
-
-    $self->redirect_to_user($r, $r->{user});
-
-Now our invitee has an email, and goes B<click> on the URL. What happens?
-
-XXX
-
-=head2 Friendship Connections
-
-=head2 
diff --git a/doc/Model.pod b/doc/Model.pod
deleted file mode 100644 (file)
index bc54ffd..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-=head1 Maypole Model Classes
-
-=head2 Class::DBI
-
-=head2 Maypole::Model::CDBI
-
-Maypole model classes are pretty evil. The very first thing a Maypole
-model class will do in a Maypole application is to cause a load of
-table-based classes to come into being, and then assimilate them.
-
-What I mean by this is that when you set up a Maypole application, in
-your driver class, you'll say something like this:
-
-    BeerDB->setup("dbi:mysql:beerdb");
-
-C<setup> is a Maypole method, and it hands its parameter to the model
-class. In our case, the model class is a DBI connect string, because
-that's what C<Maypole::Model::CDBI>, the C<Class::DBI>-based model
-expects. C<Maypole::Model::CDBI> has a method called C<setup_database>
-that creates all the C<Class::DBI> table classes after connecting to the
-database with that connect string. It does this by using
-C<Class::DBI::Loader>, a utility module which asks a database
-about its schema and sets up classes such as C<BeerDB::Beer> to inherit
-from C<Class::DBI>. This is just doing automatically what we did
-manually in our examples above.
-
-Now it gets interesting. The names of these classes are stashed away in
-the application's configuration, and then Maypole forcibly has these
-classes inherit from the model class. Our C<BeerDB::Beer> now inherits
-both from C<Class::DBI> and C<Maypole::Model::CDBI>.
-
-This is useful for two reasons. The first reason is that
-C<Maypole::Model::CDBI> is stuffed full of C<Class::DBI> goodies that
-make writing Maypole applications a lot easier:
-
-    package Maypole::Model::CDBI;
-    use base qw(Maypole::Model::Base Class::DBI);
-    use Class::DBI::AsForm;
-    use Class::DBI::FromCGI;
-    use Class::DBI::Loader;
-    use Class::DBI::AbstractSearch;
-    use Class::DBI::Plugin::RetrieveAll;
-    use Class::DBI::Pager;
-
-We'll meet most of these goodies in L<StandardTemplates.pod>, where we
-explain how C<Maypole::Model::CDBI> works.
-
-The second reason why we want our table classes to inherit from
-C<Maypole::Model::CDBI> is because C<CDBI> provides a useful set of 
-default actions. So what's an action, and why are they useful?
-
-=head2 Extending a model class with actions
-
-Maypole operates primarily by turning URLs into method calls on a model
-class. All that the model stage of Maypole's operation does, when it
-comes down to it, is maintain a mapping of tables to classes, and
-despatch a HTTP request to a method call on the relevant table class. This
-means that if you request a URL such as
-
-    http://localhost/beerdb/brewery/delete/20
-
-Maypole's first stage of operation is to turn that into
-C<BeerDB::Brewery-E<gt>delete(20)>. Now, it's slightly more complex than
-that. Firstly because it doesn't actually pass the parameter C<20>, but
-it passes an object representing row 20 in the database, but we can
-gloss over that for the second. No, the real issue is that Maypole does
-not allow you to call any method in the table class; that would be
-somewhat insecure. 
-
-Instead, Maypole makes a distinction between the kind of methods that
-only the class itself and other Perl code can call, and the kind of
-methods that anyone can call from a URL. This latter set of methods are
-called B<exported> methods, and exporting is done with by means of Perl
-attributes. You define a method to be exported like so:
-
-    sub drink :Exported {
-
-This will allow the user to access C</beerdb/beer/drink> over the web.
-An exported method accompanied with a template to render its output is
-sometimes called an B<action>. 
-
-Maypole model classes like C<Maypole::Model::CDBI> come with a
-relatively handy set of actions which are all you need to set up a CRUD
-database front-end: viewing a row in a database, editing it, adding a
-new one, deleting, and so on. The most important thing about Maypole,
-though, is that it doesn't stop there. You can add your own.
-
-For instance, in our beer database application, we could create a
-C<BeerDB::Beer> package, and put some additional actions in there.
-
-    package BeerDB::Beer;
-    sub top_five :Exported {
-        my ($class, $r) = @_;
-        $r->{objects} = [ ($r->retrieve_all_sorted_by("score"))[-5..-1] ];
-    }
-
-Our action is called as a class method with the Maypole request object.
-It uses the C<Class::DBI::Plugin::RetrieveAll> module's
-C<retrieve_all_sorted_by> mixin to get the top five scoring beers, and
-puts these in the C<objects> slot of the request of object. Next, the
-view class will come along and process the C<top_five> template with
-these five beers.
-
-We'll look more at how to put together actions in the
-L<StandardTemplates.pod> chapter and our case studies.
-
-=head2 What Maypole wants from a model
-
-=head2 Building your own model class
diff --git a/doc/Overview.pod b/doc/Overview.pod
deleted file mode 100644 (file)
index e5e6151..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-=head1 Overview of Maypole Documentation
-
-The Maypole documentation is arranged over several files; this is a good
-one to start with.
-
-Once you've read this, you should probably look at L<About.pod>, the
-guide to what Maypole is and how the Maypole request works. It also
-describes how to set up a simple CRUD web application in Maypole.
-
-The next two chapters are quite thorough, and you might want to skip
-over them if you already know how L<Class::DBI> and the L<Template>
-toolkit work. L<Model.pod> and L<View.pod> describe these technologies
-and their relationship to Maypole.
-
-Now we present the default actions and templates - the F<factory>
-templates - in L<StandardTemplates.pod>. When you have read these
-chapters, you are ready to start building more complex applications in
-Maypole than just a simple CRUD interface. L<Beer.pod> reintroduces the
-beer database application and shows how to move from the "magic" of the
-automatically supplied templates and actions to a customized application
-with user-specified actions.
-
-L<Request.pod> contains more information about the Maypole request
-object and provides some cookbook-style techniques: how to provide
-authentication, how to provide a REST interface, how to override various
-stages of the content generation process, and so on.
-
-The final chapters are examples of how to construct large web
-applications in Maypole: L<Flox.pod> describes a "social network" site
-similar to Friendster and Orkut; L<PetStore.pod> implements the Java/C#
-benchmark Pet Store application; and L<BuySpy.pod> implements the
-ASP.NET sample portal application.
diff --git a/doc/Request.pod b/doc/Request.pod
deleted file mode 100644 (file)
index bc2b303..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-=head1 Maypole Request Hacking Cookbook
-
-Hacks; design patterns; recipes: call it what you like, this chapter is a
-developing collection of techniques which can be slotted in to Maypole
-applications to solve common problems or make the development process easier.
-
-As Maypole developers, we don't necessarily know the "best practice" for
-developing Maypole applications ourselves, in the same way that Larry Wall
-didn't know all about the best Perl programming style as soon as he wrote
-Perl. These techniques are what we're using at the moment, but they may
-be refined, modularized, or rendered irrelevant over time. But they've
-certainly saved us a bunch of hours work.
-
-=head2 Frontend hacks
-
-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
-some place outside of the whole Apache/mod_perl/HTTP/Internet/browser circus.
-
-B<Solution>: Use the C<Maypole::CLI> module to go directly from a URL to
-standard output, bypassing Apache and the network altogether.
-
-C<Maypole::CLI> is not a standalone front-end, but to allow you to debug your
-applications without having to change the front-end they use, it temporarily
-"borgs" an application. If you run it from the command line, you're expected
-to use it like so:
-
-    perl -MMaypole::CLI=Application -e1 'http://your.server/path/table/action'
-
-For example:
-
-    perl -MMaypole::CLI=BeerDB -e1 'http://localhost/beerdb/beer/view/1?o2=desc'
-
-You can also use the C<Maypole::CLI> module programatically to create
-test suites for your application. See the Maypole tests themselves or
-the documentation to C<Maypole::CLI> for examples of this.
-
-=head3 Changing how URLs are parsed
-
-You don't like the way Maypole URLs look, and want something that either
-fits in with the rest of your site or hides the internal workings of the
-system.
-
-C<Solution>: So far we've been using the C</table/action/id/args> form
-of a URL as though it was "the Maypole way"; well, there is no Maypole
-way. Maypole is just a framework and absolutely everything about it is 
-overridable. 
-
-If we want to provide our own URL handling, the method to override in
-the driver class is C<parse_path>. This is responsible for taking
-C<$r-E<gt>{path}> and filling the C<table>, C<action> and C<args> slots
-of the request object. Normally it does this just by splitting the path
-on C</>s, but you can do it any way you want, including getting the
-information from C<POST> form parameters or session variables. 
-
-For instance, suppose we want our URLs to be of the form
-C<ProductDisplay.html?id=123>, we could provide a C<parse_path> method
-like so:
-
-    sub parse_path {
-        my $r = shift;
-        $r->{path} ||= "ProductList.html";
-        ($r->{table}, $r->{action}) = 
-            ($r->{path} =~ /^(.*?)([A-Z]\w+)\.html/);
-        $r->{table}  = lc $r->{table};
-        $r->{action} = lc $r->{action};
-        my %query = $r->{ar}->args;
-        $self->{args} = [ $query{id} ];
-    }
-
-This takes the path, which already has the query parameters stripped off
-and parsed, and finds the table and action portions of the filename,
-lower-cases them, and then grabs the C<id> from the query. Later methods
-will confirm whether or not these tables and actions exist.
-
-See L<BuySpy.pod> for another example of custom URL processing.
-
-=head3 Maypole for mobile devices
-
-You want Maypole to use different templates to display on particular
-browsers.
-
-B<Solution>: There are several ways to do this, but here's the neatest
-we've found. Maypole chooses where to get its templates either by
-looking at the C<template_root> config parameter or, if this is not
-given, calling the C<get_template_root> method to ask the front-end to
-try to work it out. We can give the front-end a little bit of help, by
-putting this method in our driver class:
-
-    sub get_template_root {
-        my $r = shift;
-        my $browser = $r->{ar}->headers_in->get('User-Agent');
-        if ($browser =~ /mobile|palm|nokia/i) {
-            "/home/myapp/templates/mobile";
-        } else {
-            "/home/myapp/templates/desktop";
-        }
-    }
-
-(Maybe there's a better way to detect a mobile browser, but you get the
-idea.)
-
-=head2 Content display hacks
-
-These hacks deal primarily with the presentation of data to the user,
-modifying the C<view> template or changing the way that the results of
-particular actions are displayed.
-
-=head3 Null Action
-
-You need an "action" which doesn't really do anything, but just formats
-up a template.
-
-B<Solution>: There are two ways to do this, depending on what precisely
-you need. If you just need to display a template, C<Apache::Template>
-style, with no Maypole objects in it, then you don't need to write any
-code; just create your template, and it will be available in the usual
-way.
-
-If, on the other hand, you want to display some data, and what you're
-essentially doing is a variant of the C<view> action, then you need to
-ensure that you have an exported action, as described in
-L<StandardTemplates.pod>:
-
-    sub my_view :Exported { }
-
-=head3 Template Switcheroo
-
-An action doesn't have any data of its own to display, but needs to display
-B<something>.
-
-B<Solution>: This is an B<extremely> common hack. You've just issued an
-action like C<beer/do_edit>, which updates the database. You don't want
-to display a page that says "Record updated" or similar. Lesser
-application servers would issue a redirect to have the browser request
-C</beer/view/I<id>> instead, but we can actually modify the Maypole
-request on the fly and, after doing the update, pretend that we were
-going to C</beer/view/I<id>> all along. We do this by setting the
-objects in the C<objects> slot and changing the C<template> to the
-one we wanted to go to.
-
-In this example from L<Flox.pod>, we've just performed an C<accept>
-method on a C<Flox::Invitation> object and we want to go back to viewing
-a user's page.
-
-    sub accept :Exported {
-        my ($self, $r) = @_;
-        my $invitation = $r->objects->[0];
-        # [... do stuff to $invitation ...]
-        $r->{objects} = [$r->{user}];
-        $r->{model_class} = "Flox::User";
-        $r->{template} = "view";
-    }
-
-This hack is so common that it's expected that there'll be a neater
-way of doing this in the future.
-
-=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, a Word document, 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->{content_type} = $user->photo_type;
-        $r->{output} = $user->photo;
-    }
-
-Of course, the file doesn't necessarily need to be in the database
-itself; if your file is stored in the filesystem, but you have a file
-name or some other pointer in the database, you can still arrange for
-the data to be fetched and inserted into C<$r-E<gt>{output}>.
-
-=head3 REST
-
-You want to provide a programmatic interface to your Maypole site.
-
-B<Solution>: The best way to do this is with C<REST>, which uses a
-descriptive URL to encode the request. For instance, in L<Flox.pod> we
-describe a social networking system. One neat thing you can do with
-social networks is to use them for reputation tracking, and we can use
-that information for spam detection. So if a message arrives from
-C<person@someco.com>, we want to know if they're in our network of
-friends or not and mark the message appropriately. We'll do this by
-having a web agent (say, L<WWW::Mechanize> or L<LWP::UserAgent>) request
-a URL of the form
-C<http://flox.simon-cozens.org/user/relationship_by_email/person%40someco.com>.
-Naturally, they'll need to present the appropriate cookie just like a
-normal browser, but that's a solved problem. We're just interested in
-the REST request.
-
-The request will return a single integer status code: 0 if they're not
-in the system at all, 1 if they're in the system, and 2 if they're our
-friend.
-
-All we need to do to implement this is provide the C<relationship_by_email>
-action, and use it to fill in the output in the same way as we did when
-displaying a picture. Since C<person%40someco.com> is not the ID of a
-row in the user table, it will appear in the C<args> array:
-
-    use URI::Escape;
-    sub relationship_by_email :Exported {
-        my ($self, $r) = @_;
-        my $email = uri_unescape($r->{args}[0]);
-        $r->{content_type} = "text/plain";
-        my $user;
-        unless (($user) = Flox::User->search(email => $email)) {
-            $r->{content} = "0\n"; return;
-        }
-
-        if ($r->{user}->is_friend($user)) { $r->{content} = "2\n"; return; };
-        $r->{content} = "1\n"; return;
-    }
-
-=head3 Component-based Pages
-
-You're designing something like a portal site which has a number of
-components, all displaying different bits of information about different
-objects. You want to include the output of one Maypole request call while
-building up another. 
-
-B<Solution>: Use C<Maypole::Component>. By inheriting from this, you can
-call the C<component> method on the Maypole request object to make a 
-"sub-request". For instance, if you have a template
-
-    <DIV class="latestnews">
-    [% request.component("/news/latest_comp") %]
-    </DIV>
-
-    <DIV class="links">
-    [% request.component("/links/list_comp") %]
-    </DIV>
-
-then the results of calling the C</news/latest_comp> action and template
-will be inserted in the C<latestnews> DIV, and the results of calling
-C</links/list_comp> will be placed in the C<links> DIV. Naturally, you're
-responsible for exporting actions and creating templates which return 
-fragments of HTML suitable for inserting into the appropriate locations.
-
-Alternatively, if you've already got all the objects you need, you can
-probably just C<[% PROCESS %]> the templates directly.
-
-=head3 Bailing out with an error
-
-Maypole's error handling sucks. Something really bad has happened to the
-current request, and you want to stop processing now and tell the user about
-it.
-
-B<Solution>: Maypole's error handling sucks because you haven't written it
-yet. Maypole doesn't know what you want to do with an error, so it doesn't
-guess. One common thing to do is to display a template with an error message
-in it somewhere.
-
-Put this in your driver class:
-
-    sub error { 
-        my ($r, $message) = @_;
-        $r->{template} = "error";
-        $r->{template_args}{error} = $message;
-        return OK;
-    }
-
-And then have a F<custom/error> template like so:
-
-    [% PROCESS header %]
-    <H2> There was some kind of error... </H2>
-    <P>
-    I'm sorry, something went so badly wrong, we couldn't recover. This
-    may help:
-    </P>
-    <DIV CLASS="messages"> [% error %] </DIV>
-
-Now in your actions you can say things like this:
-
-    if (1 == 0) { return $r->error("Sky fell!") }
-
-This essentially uses the template switcheroo hack to always display the
-error template, while populating the template with an C<error> parameter.
-Since you C<return $r-E<gt>error>, this will terminate the processing
-of the current action.
-
-The really, really neat thing about this hack is that since C<error>
-returns C<OK>, you can even use it in your C<authenticate> routine:
-
-    sub authenticate {
-        my ($self, $r) = @_;
-        $r->get_user;
-        return $r->error("You do not exist. Go away.")
-            if $r->{user} and $r->{user}->status ne "real";
-        ...
-    }
-
-This will bail out processing the authentication, the model class, and
-everything, and just skip to displaying the error message. 
-
-Non-showstopper errors or other notifications are best handled by tacking a
-C<messages> template variable onto the request:
-
-    if ((localtime)[6] == 1) {
-        push @{$r->{template_args}{messages}}, "Warning: Today is Monday";
-    }
-
-Now F<custom/messages> can contain:
-
-    [% IF messages %]
-    <DIV class="messages">
-    <UL>
-        [% FOR message = messages %]
-           <LI> [% message %] </LI>
-        [% END %]
-    </UL>
-    </DIV>
-    [% END %]
-
-And you can display messages to your user by adding C<PROCESS messages> at an
-appropriate point in your template; you may also want to use a template
-switcheroo to ensure that you're displaying a page that has the messages box in
-it.
-
-=head2 Authentication hacks
-
-The next series of hacks deals with providing the concept of a "user" for
-a site, and what you do with one when you've got one.
-
-=head3 Logging In
-
-You need the concept of a "current user".
-
-B<Solution>: Use something like
-C<Maypole::Authentication::UserSessionCookie> to authenticate a user
-against a user class and store a current user object in the request
-object.
-
-C<UserSessionCookie> provides the C<get_user> method which tries to get
-a user object, either based on the cookie for an already authenticated
-session, or by comparing C<username> and C<password> form parameters
-against a C<user> table in the database. Its behaviour is highly
-customizable, so see the documentation, or the authentication paper at
-C<http://maypole.simon-cozens.org/docs/authentication.html> for examples.
-
-=head3 Pass-through login
-
-You want to intercept a request from a non-logged-in user and have
-them log in before sending them on their way to wherever they were
-originally going.
-
-B<Solution>:
-
-    sub authenticate {
-        my ($self, $r) = @_;
-        $r->get_user;
-        return OK if $r->{user};
-        # Force them to the login page.
-        $r->{template} = "login";
-        return OK;
-    }
-
-This will display the C<login> template, which should look something
-like this:
-
-    [% INCLUDE header %]
-
-      <h2> You need to log in </h2>
-
-    <DIV class="login">
-    [% IF login_error %]
-       <FONT COLOR="#FF0000"> [% login_error %] </FONT>
-    [% END %]
-      <FORM ACTION="/[% request.path%]" METHOD="post">
-    Username: 
-        <INPUT TYPE="text" NAME="[% config.auth.user_field || "user" %]"> <BR>
-    Password: <INPUT TYPE="password" NAME="password"> <BR>
-    <INPUT TYPE="submit">
-    </FORM>
-    </DIV>
-
-Notice that this request gets C<POST>ed back to wherever it came from, using
-C<request.path>. This is because if the user submits correct credentials,
-C<get_user> will now return a valid user object, and the request will pass
-through unhindered to the original URL.
-
-=head3 Logging Out
-
-Now your users are logged in, you want a way of having them log out
-again and taking the authentication cookie away from them, sending
-them back to the front page as an unprivileged user.
-
-B<Solution>: This action, on the user class, is probably overkill, but
-it does the job:
-
-    sub logout :Exported {
-        my ($class, $r) = @_;
-        # Remove the user from the request object
-        my $user = delete $r->{user};
-        # Destroy the session
-        tied(%{$r->{session}})->delete;
-        # Send a new cookie which expires the previous one
-        my $cookie = Apache::Cookie->new($r->{ar},
-            -name => $r->config->{auth}{cookie_name},
-            -value => undef,
-            -path => "/"
-            -expires => "-10m"
-        );
-        $cookie->bake();
-        # Template switcheroo
-        $r->template("frontpage");
-    }
-
-=head3 Multi-level Authentication
-
-You have both a global site access policy (for instance, requiring a
-user to be logged in except for certain pages) and a policy for
-particular tables. (Only allowing an admin to delete records in some
-tables, say, or not wanting people to get at the default set of methods
-provided by the model class.) 
-
-You don't know whether to override the global C<authenticate> method or
-provide one for each class.
-
-B<Solution>: Do both. Have a global C<authenticate> method which calls 
-a C<sub_authenticate> method based on the class:
-
-    sub authenticate {
-        ...
-        if ($r->{user}) {
-            return $r->model_class->sub_authenticate($r)
-                if $r->model_class->can("sub_authenticate");
-            return OK;
-        }
-        ...
-    }
-
-And now your C<sub_authenticate> methods can specify the policy for
-each table:
-
-    sub sub_authenticate { # Ensure we can only create, reject or accept
-        my ($self, $r) = @_;
-        return OK if $r->{action} =~ /^(issue|accept|reject|do_edit)$/;
-        return;
-    }
-
-=head2 Creating and editing hacks
-
-These hacks particularly deal with issues related to the C<do_edit>
-built-in action.
-
-=head3 Limiting data for display
-
-You want the user to be able to type in some text that you're later
-going to display on the site, but you don't want them to stick images in
-it, launch cross-site scripting attacks or otherwise insert messy HTML.
-
-B<Solution>: Use the C<CGI::Untaint::html> module to sanitize the HTML
-on input. C<CGI::Untaint::html> uses C<HTML::Sanitizer> to ensure that
-tags are properly closed and can restrict the use of certain tags and
-attributes to a pre-defined list.
-
-Simply replace:
-
-    App::Table->untaint_columns(
-        text      => [qw/name description/]
-    );
-
-with:
-
-    App::Table->untaint_columns(
-        html      => [qw/name description/]
-    );
-
-And incoming HTML will be checked and cleaned before it is written to
-the database.
-
-=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.
-
-=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.
-
-B<Solution>: It's messy.
-
-First, we set up an upload form, in an ordinary dummy action. Here's
-the action:
-
-    sub upload_picture : Exported {}
-
-And here's the template:
-
-    <FORM action="/user/do_upload" enctype="multipart/form-data" method="POST">
-
-    <P> Please provide a picture in JPEG, PNG or GIF format:
-    </P>
-    <INPUT TYPE="file" NAME="picture">
-    <BR>
-    <INPUT TYPE="submit">
-    </FORM>
-
-(Although you'll probably want a bit more HTML around it than that.)
-
-Now we need to write the C<do_upload> action. At this point we have to get a
-little friendly with the front-end system. If we're using C<Apache::Request>,
-then the C<upload> method of the C<Apache::Request> object (which
-C<Apache::MVC> helpfully stores in C<$r-E<gt>{ar}>) will work for us:
-
-    sub do_upload :Exported {
-        my ($class, $r) = @_;
-        my $user = $r->{user};
-        my $upload = $r->{ar}->upload("picture");
-
-This returns a C<Apache::Upload> object, which we can query for its
-content type and a file handle from which we can read the data. It's
-also worth checking the image isn't going to be too massive before we
-try reading it and running out of memory, and that the content type is
-something we're prepared to deal with. 
-
-    if ($upload) {
-        my $ct = $upload->info("Content-type");
-        return $r->error("Unknown image file type $ct")
-            if $ct !~ m{image/(jpeg|gif|png)};
-        return $r->error("File too big! Maximum size is ".MAX_IMAGE_SIZE)
-            if $upload->size > MAX_IMAGE_SIZE;
-
-        my $fh = $upload->fh;
-        my $image = do { local $/; <$fh> };
-
-Now we can store the content type and data into our database, store it
-into a file, or whatever:
-
-        $r->{user}->photo_type($ct);
-        $r->{user}->photo($image);
-    }
-
-And finally, we use our familiar template switcheroo hack to get back to
-a useful page:
-
-        $r->objects([ $user ]);
-        $r->{template} = "view";
-    }
-
-Now, as we've mentioned, this only works because we're getting familiar with
-C<Apache::Request> and its C<Apache::Upload> objects. If we're planning to use
-C<CGI::Maypole> instead, or want to write our application in a generic way so
-that it'll work regardless of front-end, then we need to replace the C<upload>
-call with an equivalent which uses the C<CGI> module to get the upload data.
-This is convoluted and horrific and we're not going to show it here, but it's
-possible.
-
-Combine with the "Displaying pictures" hack above for a happy time.
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
diff --git a/doc/View.pod b/doc/View.pod
deleted file mode 100644 (file)
index c469100..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-=head1 Maypole View Classes
-
-In a large application, you will almost certainly want to customize the
-layout and design of the output pages. This task may even be the purview
-of a separate team of HTML designers rather than the programmers. Since
-a typical programmer will try to avoid touching HTML as much as possible
-and a typical designer will try to avoid touching Perl code, programmers
-have evolved a system of templating to separate the concerns of
-programming and designing. 
-
-One of the core concepts in Maypole is the I<view class>, and this is
-responsible for routing the data produced in the model class into the
-templates produced by the designers. Of course, there are a great many
-possible templating systems and styles, and so there can be a great many
-possible Maypole view classes. Each view class will take the data from
-the controller, locate a template to be processed, and hand the whole
-lot to its preferred templating module, which will then do the hard work
-of filling in the template and coming up with the output.
-
-You can choose whatever Maypole view class you want, but the default
-view class is C<Maypole::View::TT>, and it feeds its data and templates
-to a module called the Template Toolkit.
-
-=head2 The Template Toolkit
-
-The Template Toolkit, written by Andy Wardley, is a very powerful and
-generic templating system. It provides its own little formatting language
-which supports loops, conditionals, hash and array dereferences and
-method calls, macro processing and a plug-in system to connect it to
-external Perl modules. There are several good introductions to the
-Template Toolkit available: you should have one installed as
-L<Template::Tutorial::Datafile>; there's one at
-L<http://www.perl.com/pub/a/2003/07/15/nocode.html>, and of course
-there's the "Badger Book" - I<The Perl Template Toolkit>, by Andy et al.
-
-We'll present a brief introduction here by deconstructing some of the 
-templates used by Maypole applications. For more deconstruction, see
-L<StandardTemplates.pod>, which is an entire chapter dealing with the
-factory supplied templates.
-
-Here's the template which is called for the front page of the standard
-beer database application, C<custom/frontpage>.
-
-    [% INCLUDE header %]
-
-    <h2> The beer database </h2>
-
-    <TABLE BORDER="0" ALIGN="center" WIDTH="70%">
-    [% FOR table = config.display_tables %]
-    <TR>
-    <TD>
-    <A HREF="[%table%]/list">List by [%table %]</A>
-    </TD>
-    </TR>
-    [% END %]
-    </TABLE>
-
-The first thing to note about this is that everything outside of the
-Template Toolkit tags (C<[%> and C<%]>) is output verbatim. That is,
-you're guaranteed to see 
-
-    <h2> The beer database </h2>
-
-    <TABLE BORDER="0" ALIGN="center" WIDTH="70%">
-
-in the output somewhere. Inside the tags, magic happens. The first piece
-of magic is the C<[% INCLUDE header %]> directive. This goes away and
-finds a file called F<header> - don't worry about how it finds that yet,
-we'll come to that later on - and processes the file's contents as
-though they were right there in the template. Our F<header> file happens
-not to contain any C<[% %]> tags, but if it did, they would be processed
-in the same way as the ones in F<frontpage>. 
-
-The next piece of magic is this line:
-
-    [% FOR table = config.display_tables %]
-
-We're seeing a lot of things here at once. C<config> is where we should
-start looking. This is a template variable, which is what templates are
-all about - templating means getting data from somewhere outside and
-presenting it to the user in a useful way, and the C<config> hash is a
-prime example of data that we want to use. It's actually the hash of
-configuration parameters for this Maypole application, and one of the
-keys in that hash is C<display_tables>, the database tables that we're
-allowed to play with. In the application, we probably said something
-like
-
-    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
-
-This stores the four values - C<beer>, C<brewery>, C<pub> and C<style> -
-in an array, which is placed in the config hash under the key
-C<display_tables>. Now we're getting them back again.
-
-The Template Toolkit's dot operator is a sort of do-the-right-thing
-operator; we can say C<array.0> to get the first element of an array,
-C<hash.key> to look up the C<key> key in a hash, and C<object.method> to
-call C<method> on an object. So, for instance, if we said
-C<config.display_tables.2>, we'd look up the C<display_tables> key in
-the configuration hash and get our array back, then look up the 2nd
-element and get C<pub>.
-
-The C<FOR> loop will repeat the code four times, setting our new
-variable C<table> to the appropriate array element. This code:
-
-    [% FOR table = config.display_tables %]
-        Hello [% table %]!
-    [% END %]
-
-will produce something like
-
-    Hello beer!
-    Hello brewery!
-    Hello pub!
-    Hello style!
-
-In our case, though, we're printing out a table element linking to each
-database table in turn.
-
-Here's a slightly more complicated example, adapted from F<factory/pager>.
-This template is responsible for printing the little page menu at the
-bottom of a listing if there are more rows in the listing than we want
-on a single page.
-
-    [% PROCESS macros %]
-    <P ALIGN="center">Pages:
-    [%
-         FOREACH num = [pager.first_page .. pager.last_page];
-              IF num == pager.current_page;
-                "["; num; "] ";
-              ELSE;
-                SET args = "?page=" _ num;
-                SET label = "[" _ num _ "]";
-                link(classmetadata.moniker, "list", args, label);
-              END;
-         END;
-    %]
-    </P>
-
-Maypole will be providing a whole bunch of variables to this template,
-and we'll look at them all in a moment, but the only ones we need to care
-about are C<pager> and C<classmetadata>. 
-
-We start by loading in a bunch of macros. Macros are Template Toolkit's
-functions - you can provide them some parameters and they'll run a little
-sub-template based on them. The C<macros> file contains some handy macros
-that I've found useful for constructing Maypole templates; again, these
-will be covered in full detail in L<StandardTemplates.pod>.
-
-We're going to be displaying something like this:
-
-    Pages: [1] [2] [3] [4]
-
-with most of those numbers being a link to the appropriate page. This
-mean we're going to have to have a list of numbers, and the C<FOREACH> loop
-provides this: (C<FOREACH> and C<FOR> are identical, just like in Perl.)
-
-         FOREACH num = [pager.first_page .. pager.last_page];
-
-Here we're manually constructing an array of numbers, using the range
-operator (C<..>) to fill in all the numbers from the C<first_page> (1)
-to the C<last_page> (4). The same dot operator is used to ask the C<pager>
-what its C<first_page> and C<last_page> is. Remember when we said 
-C<config.display_tables>, we were looking up the C<display_tables> key
-in the C<config> hash? Well, this time we're not looking anything up in
-a hash. C<pager> is an object, and C<first_page> is a method. Thing is,
-you don't have to care. You can pretend it's a hash if you want. The
-syntax is the same, and Template Toolkit knows the right thing to do.
-
-Now we're going to be executing this loop four times, once each for C<num>
-being set to 1, 2, 3, and 4. At some point, we'll come across the page
-that we're actually on right now:
-
-      IF num == pager.current_page;
-
-and in that case, we don't want to produce a link to it. We just want
-to output it as text, surrounded by square brackets:
-
-                "["; num; "] ";
-
-We're using string literals to output the brackets. We don't have to
-do that. We could say it this way:
-
-    [% ...
-      IF num == pager.current_page;
-    %]
-        [ [% num %] ] 
-    [% ELSE %]
-       ...
-    [% END %]
-
-But you know, I quite like it my way.
-
-Now if the number we're printing isn't the number of the current page,
-we want to make a link. Here's how we do it:
-
-    SET args = "?page=" _ num;
-    SET label = "[" _ num _ "]";
-    link(classmetadata.table, "list", args, label);
-
-C<SET> declares a new variable of our own. If there was anything called
-C<args> before, there isn't now. It's going to be the result of our
-statement C<"?page=" _ num>. C<_> is the concatenation operator, and
-glues C<?page=> onto the front of our number. So if we want to link to
-page 4, then the C<args> variable will contain C<?page=4>. Similarly,
-the C<label> variable will be C<[4]>.
-
-Now we call a macro, C<link> with these two variables and the value of
-C<classmetadata.table>. This macro takes four arguments, C<table>, 
-C<action>, C<args> and C<label>, and constructs a link of the form
-
-    <A HREF="[% config.base_url %]/[% table %]/[% action %][% args %]">
-    [% label %]
-    </A>
-
-In our case, it'll be filled in like so:
-
-    <A HREF="[% config.base_url %]/[% classmetadata.table %]/list?page=4">
-    [ 4 ]
-    </A>
-
-Where C<classmetadata.table> will actually be the name of the current
-table, and C<config.base_url> will be replaced by the appropriate URL for
-this application.
-
-=head2 Locating Templates
-
-Another feature of C<Maypole::View::TT> which may not be present in
-alternate view class implementations - although they are strongly
-encouraged to provide it - is the way that templates are located.
-(Remember, I B<did> say I'd tell you about that later.) Template Toolkit
-allows whatever uses it to provide a path for template files to be
-located in. C<Maypole::View::TT> feeds it up to three possible
-directories to look things up in, and it will try to find a template in
-each of these in turn.
-
-When you configure a Maypole application, you can tell it the base
-directory of your templates like so:
-
-    BeerDB->config->{template_root} = "/var/www/beerdb/templates";
-
-If you don't do this, most Maypole front-ends will use the current
-directory, which is generally what you want anyway. Off this directory,
-Maypole will look for a set of subdirectories.
-
-For instance, I said we were in the middle of processing the front page
-and looking up a template file called F<header>. Maypole will first look
-for this file in the F<custom> subdirectory. (say,
-F</var/www/beerdb/templates/custom>) If it doesn't find one, then it
-looks in the F<factory> subdirectory. If it doesn't find one there, then
-it gives up and dies with an error. But that's your fault, since you've
-called for a template which doesn't exist. Don't do that. 
-
-This behaviour means that you can provide your own site-specific
-templates, but if you don't do so, then you get to use a generic one
-provided by Maypole. Maypole's "factory setting" templates are written
-in such a way as to try and do the right thing no matter what your
-application does. They are occasionally successful at this. 
-
-Now the front page was a pretty simple example, since Maypole only looks
-up two directories. In most cases, it checks an additional directory,
-and this directory depends entirely on what Maypole is doing.
-
-If you're writing an e-commerce application, for example, you may well
-have a table which represents the product catalogue and all the products
-you can buy. Let's call this the C<product> table. You'll also have a
-data source which is specific to the user which contains all the
-products that they're buying on this particular visit to the site. In
-time-honoured tradition, we'll call this the C<basket> table.
-
-Now it ought to be reasonably apparent that you don't want the basket
-to be displayed in exactly the same way as the product catalogue. The
-templates for C<product/list> and C<basket/list> need to be different.
-This is where the third directory comes in. The other directory, which
-Maypole checks very first of all, is specific to the table that you're
-viewing. So if you go to C<http://your.shop.com/basket/list>, Maypole
-will look in the F<basket> directory first for a file called F<list>,
-and second in the F<custom> directory for a site-wide list template,
-and then fall-back to the F<factory> directory for a generic list
-template. It should be obvious that you probably want to provide all
-of F<basket/list>, F<basket/view>, F<product/list>, F<product/view>
-and any other combination of classes and actions that you can think of.
-
-=head2 What Maypole provides to a template
-
-C<Maypole::View::TT> provides quite a variety of template variables to
-the template. As these are the building blocks of your pages, it's worth
-looking at precisely what variables are available.
-
-The most important variable is called C<objects>, and is a list of all
-the objects that this page is going to deal with. For instance,
-in the template F</beer/view>, C<objects> will contain the C<BeerDB::Beer>
-object for the 23rd item in the database, while F</brewery/list> will
-fill C<objects> will all the breweries; or at least, all the breweries
-on the current page.
-
-This variable is so important that to help design templates with it,
-C<Maypole::View::TT> provides a helpful alias to it depending on
-context. For instance, if you're writing your own F</brewery/list>
-template, the data in C<objects> is also available in a template
-variable called C<breweries>. If you're working on F</brewery/view>,
-though, it's available in C<brewery>, since there's only one brewery to
-be displayed.
-
-Additionally, you can get the base URL for the application from the
-C<base> template variable; this allows you to construct links, as we
-saw earlier:
-
-    <A HREF="[% base %]/brewery/edit/[% brewery.id %]">Edit this brewery</A>
-
-You can also get at the rest of the configuration for the site with the
-C<config> variable as we saw above, and the entire request object in 
-C<request>, should you really need to poke at it. (I've only found this
-useful when working with authentication modules which stash a current user
-object in C<request.user>.)
-
-To allow the construction of the "generic" templates which live in
-F<factory>, Maypole also passes in a hash called C<classmetadata>,
-which contains all sorts of useful information about the class under
-examination:
-
-=over 3
-
-=item C<table>
-
-This is the name of the table that is represented by the class.
-
-=item C<class>
-
-This is the Perl's idea of the class; you don't need this unless you're
-doing really tricky things.
-
-=item C<moniker>
-
-This is a more human-readable version of the table name, that can be
-used for display.
-
-=item C<plural>
-
-The same, but a correctly-formed plural. For instance, "breweries".
-
-=item C<columns>
-
-The list of columns for display; see the section "Customizing Generic
-CRUD Applications" in L<StandardTemplates.pod>.
-
-=item C<colnames>
-
-This is a hash mapping the database's name for a column to a more
-human-readable name. Again, see "Customizing Generic CRUD Applications>.
-
-=item C<cgi>
-
-This is a slightly trickier one. It is a hash mapping column names to
-a C<HTML::Element> suitable for entering data into a new instance of
-that class. That is, for the C<beer> table, C<classmetadata.cgi.style>
-should be a C<HTML::Element> object containing a drop-down list of
-beer styles. This is explained in L<StandardTemplates.pod>.
-
-=item C<description>
-
-This is the human-readable description provided by a class.
-
-=item C<related_accessors>
-
-This is a list of accessors which can be called on an object to get
-lists of other things that this object "has". For instance, on a
-brewery, it would return C<beers>, since calling C<brewery.beers> would
-give you a list of beers produced by the brewery. Note that this only
-caters for accessors defining one-to-many relationships, not the
-ordinary one-to-one relationships, such as C<style>.
-
-=back
-
-=head2 Other view classes
-
-Please note that these template variables, C<config>, C<classmetadata>,
-C<objects> and its user-friendly alias, as well as the rest of them are
-a function of one particular view class, the default
-C<Maypole::View::TT> class. Other view classes may need to present an
-entirely different set of template variables, since the default ones
-might not make sense. The templates may look wildly different in other
-view class implementations. But that's OK, because you couldn't
-necessarily use the same templates with a different templating system
-anyway.
-
-For instance, in really dumb templating languages which can't handle
-dereferencing hashes or arrays - no wait, that's most of them - passing
-in a hash reference like C<classmetadata> won't help you since you can't
-get at any of its elements. So you'll need to take a look at the
-documentation for the appropriate view class to see what template
-variables it provides.
-
-So if, for some perverse reason, the Template Toolkit just isn't good
-enough for you, then you can set your own view class while configuring
-your application:
-
-   package BeerDB;
-   use base 'Apache::MVC';
-   ...
-   BeerDB->setup("dbi:SQLite:t/beerdb.db");
-   BeerDB->config->{uri_base} = "http://localhost/beerdb/";
-   BeerDB->config->{rows_per_page} = 10;
-   BeerDB->config->{view} = "Maypole::View::Mason"; 
-
-Where do these alternate view classes come from? Gentle reader, they
-come from B<you>.
-
-=head2 Building your own view class
-
-I<You should probably skip this section for the first few readings of this manual. It's only intended for people extending Maypole.>
-
-Imagine you've found a brand new templating system that's B<much better>
-than the Template Toolkit. I know I'm stretching your imagination a bit
-here, but try. You'd like to use it with Maypole, which means writing your
-own view class. How is it done?
-
-We'll demonstrate by implementing a view class for C<HTML::Mason>,
-although no value judgement is implied. C<HTML::Mason> is a templating
-system which embeds pure Perl code inside its magic tags. The good side
-of this is that it can get into hash references and objects, and so
-providing C<classmetadata>, C<config> and the Maypole request object
-will work out just fine. The down side is that C<HTML::Mason> is used to
-running more or less standalone, and having all the template variables
-it wants already at its disposal through CGI parameters and the like, so
-we have to fiddle a bit to get these variables into our template.
-
-The key to building view classes is C<Maypole::View::Base>. This is the
-base class that you're going to inherit from and, to be honest, it does
-pretty much everything you need. It provides a method called C<vars>
-which returns a hash of all the template variables described above, so
-it would be good to feed those into C<HTML::Mason>. It also provides a
-C<paths> method which turns returns the full filesystem path of the
-three possible template paths as shown above. Again, it would be good to
-use this as our component paths if we can. It also has some methods we
-can override if we want to, but they're not massively important, so you
-can see L<Maypole::View::Base> for more about them. 
-
-The module will do the right thing for us if we agree to provide a
-method called C<template>. This is responsible for taking the Maypole
-request object (of which more later) and putting the appropriate output
-either into C<$r-E<gt>{output}> or C<$r-E<gt>{error}>, depending, of
-course, whether things are OK or whether we got an error.
-
-Thankfully, C<HTML::Mason> makes things really easy for us. We B<can>
-use multiple template roots, so we can use the C<paths> method; we
-B<can> pass in a hash full of interesting data structures, so we can use
-the C<vars> method too. In fact, we have to do very little to make
-C<Maypole::View::Mason> work. Which is somewhat annoying, because it
-makes a boring example. But it means I can leave the fun ones to you!
-
-The doing-the-templating, in Mason and in any templating system, depends on
-three things: the paths that we're going to use to find our templates, the
-template name that we've been asked to fill out, and the set of variables that
-are going to be fed to the template. We'll assemble these for reference:
-
-    sub template {
-        my ($self, $r) = @_;
-        my @paths = $self->paths($r);
-        my $template = $r->template;
-        my %vars = $self->args($r);
-
-We'll also declare somewhere to temporarily store the output:
-
-        my $output;
-
-Now comes the part where we have to actually do something
-templating-language specific, so we open up our copy of "Embedding Perl
-in HTML with Mason" and find the bit where it talks about running Mason
-standalone. We find that the first thing we need to do is create a
-C<HTML::Mason::Interp> object which knows about the component roots.
-There's a slight subtlety in that the component roots have to be
-specified as an array of arrays, with each array being a two-element
-list of label and path, like so:
-
-    comproot => [
-        [ class   => "/var/www/beerdb/templates/brewery" ],
-        [ custom  => "/var/www/beerdb/templates/custom" ],
-        [ factory => "/var/www/beerdb/templates/factory" ],
-    ]
-
-We also find that we can set the output method here to capture Mason's
-output into a scalar, and also that we can tell Mason to generate
-sensible error messages itself, which saves us from having to worry
-about catching errors. At the end of all this, we come up with a
-constructor for our C<HTML::Mason::Interp> object which looks like this:
-
-    my $label = "path0";
-    my $mason = HTML::Mason::Interp->new(
-        comproot => [ map { [ $label++ => $_ ] } @paths ],
-        output_method => \$output,
-        error_mode => "output" 
-    );
-
-The next thing we need to do is run the template with the appropriate
-template variables. This turns out to be really easy:
-
-    $mason->exec($template, %vars);
-
-Now we've got the data in C<$output>, we can put it into the request object,
-and return a true value to indicate that we processed everything OK. (If there
-was an error, then Mason will have produced some suitable output, so we can
-pretend that everything's OK anyway.)
-
-    $r->{output} = $output;
-    return 1;
-
-And that's all we need to do. Barely twenty lines of code for the finished
-product. Wasn't that easy? Don't you feel inspired to write Maypole view
-classes for your favourite templating language? Well, don't let me stop you!
-Patches are always welcome!
diff --git a/doc/makedoc.pl b/doc/makedoc.pl
deleted file mode 100644 (file)
index b6dec2f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-my @templates = <../templates/factory/*>;
-
-my %doc;
-
-for my $template (@templates) {
-    open TEMP, $template or die $!;
-    $template =~ s/.*factory\///g;
-    while (<TEMP>) {
-        next unless /^#?=for doc/... /^#?=cut/
-                    and not /(%#?\]|\[%#?)$/
-                    and not /=cut|=for doc/; # Much magic.
-        s/^\s*#//g;
-        $doc{$template} .= $_;
-    }
-}
-
-while (<>) {
-    if (!/^=template (\w+)/) { print; next; }
-    die "Can't find doc for template $1" unless $doc{$1};
-    print $doc{$1};
-}
index dd9ff770a1827ca393dd4361509222461135f1b7..6ab5bc029860121331a1285467ef68d961f4a2ec 100644 (file)
@@ -189,148 +189,218 @@ sub parse_path {
     $self->{args}   = \@pi;
 }
 
+sub get_template_root { "." }
+sub get_request       { }
+
+sub parse_location {
+    die "Do not use Maypole directly; use Apache::MVC or similar";
+}
+
+sub send_output {
+    die "Do not use Maypole directly; use Apache::MVC or similar";
+}
+
 =head1 NAME
 
 Maypole - MVC web application framework
 
 =head1 SYNOPSIS
 
-See L<Maypole>.
+See L<Maypole::Application>.
 
 =head1 DESCRIPTION
 
-A large number of web programming tasks follow the same sort of pattern:
-we have some data in a datasource, typically a relational database. We
-have a bunch of templates provided by web designers. We have a number of
-things we want to be able to do with the database - create, add, edit,
-delete records, view records, run searches, and so on. We have a web
-server which provides input from the user about what to do. Something in
-the middle takes the input, grabs the relevant rows from the database,
-performs the action, constructs a page, and spits it out.
-
-Maypole aims to be the most generic and extensible "something in the
-middle" - an MVC-based web application framework.
-
-An example would help explain this best. You need to add a product
-catalogue to a company's web site. Users need to list the products in
-various categories, view a page on each product with its photo and
-pricing information and so on, and there needs to be a back-end where
-sales staff can add new lines, change prices, and delete out of date
-records. So, you set up the database, provide some default templates
-for the designers to customize, and then write an Apache handler like
-this:
-
-    package ProductDatabase;
-    use base 'Maypole::Application';
-    __PACKAGE__->set_database("dbi:mysql:products");
-    ProductDatabase->config->uri_base = "http://your.site/catalogue/";
-    ProductDatabase::Product->has_a("category" => ProductDatabase::Category); 
-    # ...
-
-    sub authenticate {
-        my ($self, $request) = @_;
-        return OK if $request->{ar}->get_remote_host() eq "sales.yourcorp.com";
-        return OK if $request->{action} =~ /^(view|list)$/;
-        return DECLINED;
-    }
-    1;
+This documents the Maypole request object. For user documentation, see
+L<Maypole::Tutorial>.
 
-You then put the following in your Apache config:
+=head2 CLASS METHODS
 
-    <Location /catalogue>
-        SetHandler perl-script
-        PerlHandler ProductDatabase
-    </Location>
+=head3 config
 
-And copy the templates found in F<templates/factory> into the
-F<catalogue/factory> directory off the web root. When the designers get
-back to you with custom templates, they are to go in
-F<catalogue/custom>. If you need to do override templates on a
-database-table-by-table basis, put the new template in
-F<catalogue/I<table>>. 
+Returns the L<Maypole::Config> object
 
-This will automatically give you C<add>, C<edit>, C<list>, C<view> and
-C<delete> commands; for instance, a product list, go to 
+=head3 setup
 
-    http://your.site/catalogue/product/list
+    My::App->setup();
 
-For a full example, see the included "beer database" application.
+    Initialise the maypole application and model classes. Your
+    application should
+    call this after setting configuration via L<"config">
 
-=head1 HOW IT WORKS
+=head3 init
 
-There's some documentation for the workflow in L<Maypole::Workflow>,
-but the basic idea is that a URL part like C<product/list> gets
-translated into a call to C<ProductDatabase::Product-E<gt>list>. This
-propagates the request with a set of objects from the database, and then 
-calls the C<list> template; first, a C<product/list> template if it
-exists, then the C<custom/list> and finally C<factory/list>. 
+You should not call this directly, but you may wish to override this to
+add
+application-specific initialisation.
 
-If there's another action you want the system to do, you need to either
-subclass the model class, and configure your class slightly differently:
+=head3 view_object
 
-    package ProductDatabase::Model;
-    use base 'Maypole::Model::CDBI';
+Get/set the Maypole::View object
 
-    sub supersearch :Exported {
-        my ($self, $request) = @_;
-        # Do stuff, get a bunch of objects back
-        $r->objects(\@objects);
-        $r->template("template_name");
-    }
+=head3 debug
 
-Then your top-level application package should change the model class:
-(Before calling C<setup>)
+    sub My::App::debug {1}
 
-    ProductDatabase->config->model("ProductDatabase::Model");
+    Returns the debugging flag. Override this in your application class
+    to
+    enable/disable debugging.
 
-(The C<:Exported> attribute means that the method can be called via the
-URL C</I<table>/supersearch/...>.)
+=head2 INSTANCE METHODS
 
-Alternatively, you can put the method directly into the specific model
-class for the table:
+=head3 parse_location
 
-    sub ProductDatabase::Product::supersearch :Exported { ... }
+Turns the backend request (e.g. Apache::MVC, Maypole, CGI) into a
+Maypole
+request. It does this by setting the C<path>, and invoking C<parse_path>
+and
+C<parse_args>.
 
-By default, the view class uses Template Toolkit as the template
-processor, and the model class uses C<Class::DBI>; it may help you to be
-familiar with these modules before going much further with this,
-although I expect there to be other subclasses for other templating
-systems and database abstraction layers as time goes on. The article at
-C<http://www.perl.com/pub/a/2003/07/15/nocode.html> is a great
-introduction to the process we're trying to automate.
+You should only need to define this method if you are writing a new
+Maypole
+backend.
 
-=head1 USING MAYPOLE
+=head3 path
 
-You should probably not use Maypole directly. Maypole is an abstract
-class which does not specify how to communicate with the outside world.
-The most popular subclass of Maypole is L<Apache::MVC>, which interfaces
-the Maypole framework to Apache mod_perl; another important one is
-L<CGI::Maypole>. However, if you just don't care, use Maypole::Application,
-and it will choose the right one for you.
+Returns the request path
 
-If you are implementing Maypole subclasses, you need to provide at least
-the C<parse_location> and C<send_output> methods. You may also want to
-provide C<get_request> and C<get_template_root>. See the
-L<Maypole::Workflow> documentation for what these are expected to do.
+=head3 parse_path
 
-=cut
+Parses the request path and sets the C<args>, C<action> and C<table> 
+properties
 
-sub get_template_root { "." }
-sub get_request       { }
+=head3 table
 
-sub parse_location {
-    die "Do not use Maypole directly; use Apache::MVC or similar";
-}
+The table part of the Maypole request path
 
-sub send_output {
-    die "Do not use Maypole directly; use Apache::MVC or similar";
-}
+=head3 action
+
+The action part of the Maypole request path
+
+=head3 args
+
+A list of remaining parts of the request path after table and action
+have been
+removed
+
+=head3 parse_args
+
+Turns post data and query string paramaters into a hash of C<params>.
+
+You should only need to define this method if you are writing a new
+Maypole
+backend.
+
+=head3 params
+
+Returns a hash of request parameters. The source of the parameters may
+vary
+depending on the Maypole backend, but they are usually populated from
+request
+query string and POST data.
+
+B<Note:> Where muliple values of a parameter were supplied, the
+C<params> 
+value
+will be an array reference.
+
+=head3 get_template_root
+
+Implimentation-specific path to template root.
+
+You should only need to define this method if you are writing a new
+Maypole
+backend. Otherwise, see L<Maypole::Config/"template_root">
+
+=head3 is_applicable
+
+Returns a Maypole::Constant to indicate whether the request is valid.
+
+The default implimentation checks that C<$r-E<gt>table> is publicly
+accessible
+and that the model class is configured to handle the C<$r-E<gt>action>
+
+=head3 authenticate
+
+Returns a Maypole::Constant to indicate whether the user is
+authenticated for
+the Maypole request.
+
+The default implimentation returns C<OK>
+
+=head3 model_class
+
+Returns the perl package name that will serve as the model for the
+request. It corresponds to the request C<table> attribute.
+
+=head3 additional_data
+
+Called before the model processes the request, this method gives you a
+chance
+to do some processing for each request, for example, manipulating
+C<template_args>.
+
+=head3 objects
+
+Get/set a list of model objects. The objects will be accessible in the
+view
+templates.
+
+If the first item in C<$r-E<gt>args> can be C<retrieve()>d by the model
+class,
+it will be removed from C<args> and the retrieved object will be added
+to the
+C<objects> list. See L<Maypole::Model> for more information.
+
+=head3 template_args
+
+    $r->template_args->{foo} = 'bar';
+
+    Get/set a hash of template variables.
+
+=head3 template
+
+Get/set the template to be used by the view. By default, it returns
+C<$r-E<gt>action>
+
+=head3 exception
+
+This method is called if any exceptions are raised during the
+authentication 
+or
+model/view processing. It should accept the exception as a parameter and 
+return
+a Maypole::Constant to indicate whether the request should continue to
+be
+processed.
+
+=head3 error
+
+Get/set a request error
+
+=head3 output
+
+Get/set the response output. This is usually populated by the view
+class. You
+can skip view processing by setting the C<output>.
+
+=head3 document_encoding
+
+Get/set the output encoding. Default: utf-8.
+
+=head3 content_type
+
+Get/set the output content type. Default: text/html
+
+=head3 send_output
+
+Sends the output and additional headers to the user.
 
 =head1 SEE ALSO
 
-There's more documentation, examples, and a wiki at the Maypole web site:
+There's more documentation, examples, and a wiki at the Maypole web
+site:
 
-http://maypole.simon-cozens.org/
+http://maypole.perl.org/
 
 L<Maypole::Application>,L<Apache::MVC>, L<CGI::Maypole>.
 
@@ -345,7 +415,8 @@ Simon Cozens, C<simon@cpan.org>
 =head1 THANK YOU
 
 Danijel Milicevic, Jesse Scheidlower, Jody Belka, Marcus Ramberg,
-Mickael Joanne, Simon Flack, Veljko Vidovic and all the others who've helped.
+Mickael Joanne, Simon Flack, Veljko Vidovic and all the others who've
+helped.
 
 =head1 LICENSE
 
diff --git a/lib/Maypole/Manual/About.pod b/lib/Maypole/Manual/About.pod
new file mode 100644 (file)
index 0000000..3600a94
--- /dev/null
@@ -0,0 +1,312 @@
+
+=head1 Introduction to the Maypole Request Model
+
+This chapter serves as a gentle introduction to Maypole and setting up
+Maypole applications. We look at Maypole is, how to get it up and
+running, and how to start thinking about building Maypole applications.
+
+=head2 What is Maypole?
+
+Presumably you have some idea of what Maypole is all about, or otherwise
+you wouldn't be reading this manual. But Maypole is good at many
+different things, and you may have accidentally focussed on one aspect
+of Maypole while missing the big picture.
+
+For instance, you may know that Maypole is extremely good at putting web
+front-ends onto databases. This is true, but it's only a part of what
+Maypole does. You may have heard that Maypole is a web application
+framework, which is true, but it doesn't mean very much. There are a
+huge number of things that Maypole can do, because it's very much a
+blank slate. You can make it do what you will. In this manual, we'll be
+making it act as a front-end to a database, as a social network site, as
+an intranet portal, and many other things besides. It is a framework.
+
+I like to think that Maypole is a way of going from a URL to a method
+call to some output. If you have a URL like C</product/order/12>,
+Maypole is a way of having it load up product number 12, call an
+C<order> method, and produce a page about what it's just done. The
+reason Maypole is such a big deal is because it does all this for you.
+You no longer have to care about your web server. You hardly have to
+care about your database. You don't have to care about templating
+modules, parsing CGI parameters, or anything else. You only need to care
+about business logic, and the business logic in this instance is how you
+C<order> a product, and what you need to display about it once you've
+done so. This is what programming should be: only caring about the work
+that distinguishes one program from another.
+
+It does this using a technique called MVC for web applications.
+
+=head2 What is MVC for web applications?
+
+Maypole was originally called C<Apache::MVC>, reflecting its basis in
+the Model-View-Controller design pattern. (I had to change it firstly
+because Maypole isn't tied to Apache, and secondly because
+C<Apache::MVC> is a really dull name.) It's the same design pattern that
+forms the foundation of similar projects in other languages, such as
+Java's Struts framework.
+
+This design pattern is found primarily in graphical applications; the
+idea is that you have a Model class which represents and manipulates
+your data, a View class which is responsible for displaying that data to
+the user, and a Controller class which controls the other classes in
+response to events triggered by the user. This analogy doesn't
+correspond precisely to a web-based application, but we can take an
+important principle from it. As Andy Wardley explains:
+
+    What the MVC-for-the-web crowd are really trying to achieve is a clear
+    separation of concerns.  Put your database code in one place, your 
+    application code in another, your presentation code in a third place.  
+    That way, you can chop and change different elements at will,
+    hopefully without affecting the other parts (depending on how well your
+    concerns are separated, of course).  This is common sense and good practice.
+    MVC achieves this separation of concerns as a by-product of clearly 
+    separating inputs (controls) and outputs (views). 
+
+This is what Maypole does. It has a number of database drivers, a number
+of front-end drivers and a number of templating presentation drivers.
+In common cases, Maypole provides precisely what you need for all of
+these areas, and you get to concentrate on writing just the business
+logic of your application. This is one of the reasons why Maypole lets
+you develop so rapidly: because most of the time, you don't need to do
+any development at all.
+
+=head2 Installing Maypole
+
+The first thing you're going to need to do to get Maypole running is to
+install it. Maypole needs an absolute shedload of Perl modules from CPAN
+to do its job. I am unrepentant about this. Maypole does a lot of work,
+so that you don't have to. This is called code re-use, and if we're
+serious about code re-use, then Maypole should be re-using as much code
+as possible in terms of Perl modules. In another sense, this gives the
+impression that Maypole doesn't actually do all that much itself,
+because all it's doing is gluing together already-existing code. Well,
+welcome to code re-use.
+
+The downside of code re-use is, of course, that you then have to install
+a shedload of Perl modules from CPAN. If you're using OpenBSD or
+FreeBSD, the wonderful ports system will be your friend. There's a
+Maypole port in C<p5-Maypole>. Just type C<make install>.
+
+Debian users, hang in there. There's a package coming.
+
+For other Unices, the L<CPANPLUS> or C<CPAN> modules will help with
+this. If you don't have C<CPANPLUS> installed, my recommendation is to
+use C<perl -MCPAN -e install CPANPLUS> to install it and then throw
+C<CPAN.pm> away. In any case, one of these two should get all that
+Maypole needs:
+
+    % perl -MCPANPLUS -e 'install Maypole'
+    % perl -MCPAN -e 'install Maypole'
+
+I don't know if Maypole works on Windows. I'm not sure I care.
+
+You're also going to need a database server and a web server. For
+databases, I recommend SQLite (if you install the C<DBD::SQLite> module,
+you get the SQLite library for free) for prototyping and mysql for
+production; heavier duty users should use Postgresql or Oracle - Maypole
+should be happy with them all. Maypole is happiest when running under
+Apache C<mod_perl>, with the C<Apache::Request> module installed, but as
+I said, it is a blank slate, and everything is customizable. There is a
+C<CGI::Maypole> frontend available to run as a standalone CGI script.
+
+=head2 The Beer Database example
+
+Throughout this manual, we're going to be referring back to a particular
+application so that we can give concrete examples for the concepts we're
+talking about. We could say "C<related_accessors> returns a list of
+accessors which can be called to return a list of objects in a has-a
+relationship to the original", or we could say "if we call
+C<related_accessors> on while viewing C<brewery>, it returns C<beers>,
+because we can call C<beers> on a C<brewery> object to get a list of
+that berwery's beers." 
+
+Because Maypole is all about beer. If you look carefully, you can
+probably see men playing cricket on the village green. The first
+ever Maypole application was written to help me keep track of the many
+different ales available in my area - their styles, their tastes, their
+breweries, prices and so on. Then the more I thought about it, the more
+I thought it was a particularly good data model for demonstrating
+different kinds of database relationships.
+
+We have a C<brewery> table, which has several C<beer>s. We'll call this
+a has-many relationship. The beers each have a C<style>; styles are
+stored in a separate table, so C<beer> has-a C<style>. Beers are in
+several pubs and a pub has several beers, so beers and pubs are in a
+many-to-many relationship. We use a link table called C<handpump> to
+relate pubs to beers.
+
+All in all, this gives us a schema like the following:
+
+    create table brewery (
+        id int not null auto_increment primary key,
+        name varchar(30),
+        url varchar(50),
+        notes text
+    );
+
+    create table beer (
+        id int not null auto_increment primary key,
+        brewery integer,
+        style integer, 
+        name varchar(30),
+        url varchar(120),
+        score integer(2),
+        price varchar(12),
+        abv varchar(10),
+        notes text
+    );
+
+    create table handpump (
+        id int not null auto_increment primary key,
+        beer integer,
+        pub integer
+    );
+
+    create table pub (
+        id int not null auto_increment primary key,
+        name varchar(60),
+        url varchar(120),
+        notes text
+    );
+
+    create table style (
+        id int not null auto_increment primary key,
+        name varchar(60),
+        notes text
+    );
+
+If you have C<DBD::SQLite> available, then a database like this will
+be created when Maypole was installed. Let's now see how to set it up
+with a web interface.
+
+=head2 Setting up Maypole
+
+The first thing we need for a Maypole interface to a database is to
+have a database. If you don't have one, now would be a good time to
+create one, using the schema above.
+
+The next thing we need is a module which is going to do all the work.
+Thankfully, it doesn't need to do B<all> the work itself. It's going to be a 
+subclass of C<Maypole> or a Maypole front-end like C<Apache::MVC>. 
+
+Here's the driver class for our beer database application. We're not
+going to go into much detail about it here; we'll do that in L<Beer.pod>.
+For now, simply admire its brevity, as you realise this is all the code
+you need to write for a simple database front-end:
+
+    package BeerDB;
+    use base 'Apache::MVC';
+    BeerDB->setup("dbi:SQLite:t/beerdb.db");
+    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
+    BeerDB->config->{rows_per_page} = 10;
+    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
+    BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
+    BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
+    BeerDB::Beer->untaint_columns(
+        printable => [qw/abv name price notes/],
+        integer => [qw/style brewery score/],
+        date => [ qw/date/],
+    );
+
+    use Class::DBI::Loader::Relationship;
+    BeerDB->config->{loader}->relationship($_) for (
+        "a brewery produces beers",
+        "a style defines beers",
+        "a pub has beers on handpumps");
+    1;
+
+This defines the C<BeerDB> application, which, as it inherits from 
+C<Apache::MVC>, will be a mod_perl handler. This means we need to
+tell the Apache configuration about it:
+
+    <Location /beerdb>
+        SetHandler perl-script
+        PerlHandler BeerDB
+    </Location>
+
+And now we need some templates. As we'll see in the chapter on views,
+L<View.pod>, there are several types of template. We're going to copy
+the whole lot from the F<templates/> directory of the Maypole source
+package into the F</beerdb> directory under our web root.
+
+And that's it. We should now be able to go to C<http://localhost/beerdb/>
+and see a menu of things to browse; C<http://localhost/beerdb/beer/list>
+will give a list of beers. There might not be any yet. There's a box
+that lets you add them.
+
+If you have any problems getting to this point, you might want to look
+at L<http://wiki.simon-cozens.org/index.cgi?InstallationIssues>.
+
+Play about with the site. Add some beers. Maybe go out and buy some beers
+to review if you need some inspiration. Don't be ill on my carpet.
+
+=head2 Phases of a Maypole request
+
+Now you should have a feel for what Maypole can do. The important thing
+to know at this point is that this is by no means B<all> that Maypole
+can do. What you've seen in the beer database example is all that Maypole
+can do if you don't customize it at all.
+
+Remember that, for instance, we don't ever tell Maypole what tables our
+database has, or what columns each table has. We don't tell Maypole what
+those tables should be called or how to display them. We don't tell Maypole
+what to do - that we want to list, search, edit and delete beers and breweries.
+Maypole just works that out for itself. We can customize it and have Maypole
+do all sorts of interesting things with our database, and most of the rest
+of this manual will be about how to do that.
+
+In order to do that, we need to look at what Maypole's actually doing.
+
+As mentioned, Maypole is responsible for turning a URL into an object, a
+method call, and some templated output. Here's a handy diagram to
+explain how it does that:
+
+=for html
+<IMG SRC="maypole_process2.png">
+
+Maypole's process revolves around the concept of the Maypole request
+object. This is a little like Apache's request object, but at a much
+higher level - in fact, in C<mod_perl>-based Maypole front-ends, the
+Apache request object is incorporated in the Maypole request object. All
+that Maypole does is gradually flesh out this object until it contains
+something in the C<output> member, and then it is dispatched back to the
+front-end for output.
+
+So to start with, we take the Apache request (or CGI object, or other
+way of isolating what's going on) and break it down. For instance, we
+turn the URL C</beer/view/1> into
+
+    {
+        table => "beer",
+        action => "view",
+        args => [ 1 ]
+    }
+
+Then Maypole will check that C<beer> is a real table, and find the class
+that models it. It also checks whether or not we're allowed to call the
+C<view> method over the network:
+
+    {
+        table => "beer",
+        action => "view",
+        args => [ 1 ],
+        model_class => "BeerDB::Beer"
+    }
+
+Then there's a user-defined authentication method, which by default just
+lets us do anything. Now we hand over to the model class, which loads up
+the object, and decides what template we want to use:
+
+    {
+        table => "beer",
+        action => "view",
+        args => [ ],
+        objects => [ BeerDB::Beer->retrieve(1) ],
+        model_class => "BeerDB::Beer",
+        template => "view"
+    }
+
+Then it calls C<BeerDB::Beer-E<gt>view>, passing in the request object
+as a parameter, and passes the whole lot to the view class for templating.
+In the next two chapters, we'll look at how Maypole's default model and
+view classes generally do what you want them to do.
diff --git a/lib/Maypole/Manual/Beer.pod b/lib/Maypole/Manual/Beer.pod
new file mode 100644 (file)
index 0000000..033d9ce
--- /dev/null
@@ -0,0 +1,230 @@
+=head1 The Beer Database, Twice
+
+We briefly introduced the "beer database" example in the L<About.pod>
+material, where we presented its driver class as a fait accompli. Where
+did all that code come from, and what does it actually mean?
+
+=head2 The big beer problem
+
+I have a seriously bad habit. This is not the beer problem; this is a
+programming problem. The bad habit is that when I approach a problem I
+want to solve, I get sidetracked deeper and deeper trying to solve more
+and more generic problems, and then, satisfied with solving the generic
+problem, I never get around to solving the specific problem. I always
+write libraries for people writing libraries, and never write
+applications.
+
+The thing with really good beer is that it commands you to drink more of
+it, and then by the morning you can't remember whether it was any good
+or not. After buying several bottles of some random central African
+lager on a dim recollection that it was really good and having it turn
+out to be abysmal, this really became a problem. If only I could have a
+database that I updated every time I buy a new beer, I'd be able to tell
+whether or not I should buy that Lithuanian porter again or whether it
+would be quicker just to flush my money down the toilet and cut out the
+middle-man.
+
+The only problem with databases on Unix is that there isn't really a
+nice way to get data into them. There isn't really a Microsoft Access
+equivalent which can put a simple forms-based front-end onto an
+arbitrary database, and if there is, I either didn't like it or couldn't
+find it, and after a few brews, you really don't want to be trying to type
+in your tasting notes in raw SQL.
+
+So you see a generic problem arising out of a specific problem here. I
+didn't want to solve the specific problem of the beer database, because
+I'd already had another idea for a database that needed a front-end. So
+for two years, I sat on this great idea of having a database of tasting
+notes for beer. I even bought that damned African beer again. Enough was
+enough. I wrote Maypole.
+
+=head2 The easy way
+
+The first Maypole application was the beer database. We've already met
+it; it looks like this.
+
+    package BeerDB;
+    use base 'Apache::MVC';
+    BeerDB->set_database("dbi:SQLite:t/beerdb.db");
+    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
+    BeerDB->config->{rows_per_page} = 10;
+    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
+    BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
+    BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
+    BeerDB::Beer->untaint_columns(
+        printable => [qw/abv name price notes/],
+        integer => [qw/style brewery score/],
+        date => [ qw/date/],
+    );
+
+    use Class::DBI::Loader::Relationship;
+    BeerDB->config->{loader}->relationship($_) for (
+        "a brewery produces beers",
+        "a style defines beers",
+        "a pub has beers on handpumps");
+    1;
+
+Now, we can split this into four sections. Let's look at them one
+at a time. 
+
+=head3 Driver setup
+
+Here's the first section:
+
+    package BeerDB;
+    use base 'Apache::MVC';
+    BeerDB->setup("dbi:SQLite:t/beerdb.db");
+
+This is actually all you need for a functional database front-end. Everything
+else is configuration details. This says three things: we're an application
+called C<BeerDB>. This package is called the B<driver class>, because
+it's a relatively small class which defines how the whole application is
+going to run. 
+
+The second line says that our front-end is going to be C<Apache::MVC>,
+which is the Apache C<mod_perl> based version of Maypole; there's also
+a CGI version, C<CGI::Maypole>, and a command-line version for
+debugging, C<Maypole::CLI>, but C<Apache::MVC> is  usually the one you
+want.
+
+Thirdly we're going to need to set up our database with the given DBI
+connection string. Now the core of Maypole itself doesn't know about
+DBI; as we explained in L<Model.pod>, this argument is passed to our
+model class wholesale. As we haven't said anything about a model
+class, we get the default one, C<Maypole::Model::CDBI>, which takes a
+DBI connect string. So this one line declares that we're using a C<CDBI>
+model class and it sets up the database for us. In the same way, we
+don't say that we want a particular view class, so we get the default
+C<Maypole::View::TT>.
+
+At this point, everything is in place; we have our driver class, it uses
+a front-end, we have a model class and a view class, and we have a data
+source.
+
+=head3 Application configuration
+
+The next of our four sections is the configuration for the application itself.
+
+    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
+    BeerDB->config->{rows_per_page} = 10;
+    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
+
+Maypole provides a method called C<config> which returns a hash reference
+of the application's whole configuration. We can use this to set some
+parameters; the C<uri_base> is used as the canonical URL of the base
+of this application, and Maypole uses it to construct links.
+
+By defining C<rows_per_page>, we say that any listings we do with the
+C<list> and C<search> templates should be arranged in sets of pages, with
+a maximum of 10 items on each page. If we didn't declare that, C<list>
+would try to put all the objects on one page, which could well be bad.
+
+Finally, we declare which tables we want our Maypole front-end to
+reference. If you remember from the schema, there's a table called
+C<handpump> which acts as a linking table in a many-to-many relationship
+between the C<pub> and C<beer> tables. As it's only a linking table, we
+don't want people poking with it directly, so we exclude it from the
+list of C<display_tables>.
+
+=head3 Editability
+
+The next section is the following set of lines:
+
+    BeerDB::Brewery->untaint_columns( printable => [qw/name notes url/] );
+    BeerDB::Style->untaint_columns( printable => [qw/name notes/] );
+    BeerDB::Beer->untaint_columns(
+        printable => [qw/abv name price notes/],
+        integer => [qw/style brewery score/],
+        date => [ qw/date/],
+    );
+
+As explained in L<StandardTemplates.pod>, this is an set of instructions to
+C<Class::DBI::FromCGI> regarding how the given columns should be edited.
+If we didn't have this section, we'd be able to view and delete records,
+but adding and editing them wouldn't work. It took me ages to work that
+one out.
+
+=head3 Relationships
+
+Finally, we want to explain to Maypole how the various tables relate to
+each other. This is done so that, for instance, when displaying a beer,
+the brewery does not appear as an integer like "2" but as the name of
+the brewery from the C<brewery> table with an ID of 2.
+
+The usual C<Class::DBI> way to do this involves the C<has_a> and
+C<has_many> methods, but I can never remember how to use them, so I came
+up with the C<Class::DBI::Loader::Relationship> module; this was another
+yak that needed shaving on the way to the beer database:
+
+    use Class::DBI::Loader::Relationship;
+    BeerDB->config->{loader}->relationship($_) for (
+        "a brewery produces beers",
+        "a style defines beers",
+        "a pub has beers on handpumps");
+    1;
+
+C<CDBIL::Relationship> acts on a C<Class::DBI::Loader> object and
+defines relationships between tables in a fairly free-form style.
+The equivalent in ordinary C<Class::DBI> would be:
+
+       BeerDB::Brewery->has_many(beers => "BeerDB::Beer");
+       BeerDB::Beer->has_a(brewery => "BeerDB::Brewery");
+       BeerDB::Style->has_many(beers => "BeerDB::Beer");
+       BeerDB::Beer->has_a(style => "BeerDB::Style");
+
+       BeerDB::Handpump->has_a(beer => "BeerDB::Beer");
+       BeerDB::Handpump->has_a(pub => "BeerDB::Pub");
+       BeerDB::Pub->has_many(beers => [ BeerDB::Handpump => 'beer' ]);
+       BeerDB::Beer->has_many(pubs => [ BeerDB::Handpump => 'pub' ]);
+
+Maypole's default templates will use this information to display, for
+instance, a list of a brewery's beers on the brewery view page.
+
+This is the complete beer database application; Maypole's default templates
+and the actions in the view class do the rest. But what if we want to do a
+little more. How would we begin to extend this application?
+
+=head2 The hard way
+
+Maypole was written because I don't like writing more Perl code than is
+necessary. I also don't like writing HTML. In fact, I don't really get
+on this whole computer thing, to be honest. But we'll start by ways that
+we can customize the beer application simply by adding methods or
+changing properties of the Perl driver code.
+
+The first thing we ought to look into is the names of the columns; most
+of them are fine, but that "Abv" column stands out. I'd rather that was
+"A.B.V.". Maypole uses the C<column_names> method to map between the
+names of the columns in the database to the names it displays in the
+default templates. This is provided by C<Maypole::Model::Base>, and
+normally, it does a pretty good job; it turns C<model_number> into
+"Model Number", for instance, but there was no way it could guess that
+C<abv> was an abbreviation. Since it returns a hash, the easiest way
+to correct it is to construct a hash consisting of the bits it got
+right, and then override the bits it got wrong:
+
+    package BeerDB::Beer;
+    sub column_names { 
+        (shift->SUPER::column_names(), abv => "A.B.V.")
+    }
+
+Similarly, the order of columns is a bit wonky. We can fix this by
+overriding the C<display_columns> method; this is also a good way to
+hide away any columns we don't want to have displayed, in the same way
+as declaring the C<display_tables> configuration parameter let us hide
+away tables we weren't using:
+
+    sub display_columns { 
+        ("name", "brewery", "style", "price", "score", "abv", "notes")
+    }
+
+Hey, have you noticed that we haven't done anything with the
+beers/handpumps/pubs thing yet? Good, I was hoping that you hadn't.
+Ayway, this is because Maypole can't tell easily that a C<BeerDB::Beer>
+object can call C<pubs> to get a list of pubs. Not yet, at least; we're
+working on it. In the interim, we can explicitly tell Maypole which
+accessors are related to the C<BeerDB::Beer> class like so:
+
+    sub related { "pubs" }
+
+Now when we view a beer, we'll have a list of the pubs that it's on at.
diff --git a/lib/Maypole/Manual/BuySpy.pod b/lib/Maypole/Manual/BuySpy.pod
new file mode 100644 (file)
index 0000000..ef3d872
--- /dev/null
@@ -0,0 +1,347 @@
+=head1 The Maypole iBuySpy Portal
+
+I think it's good fun to compare Maypole
+
+We begin with a length process of planning and investigating the
+sources. Of prime interest is the database schema and the initial data,
+which we convert to a Mysql database. Converting MS SQL to Mysql is not fun.
+I shall spare you the gore. Especially the bit where the default insert IDs
+didn't match up between the tables.
+
+The C<ibsportal> database has a number of tables which describe how the
+portal should look, and some tables which describe the data that should
+appear on it. The portal is defined in terms of a set of modules; each
+module takes some data from somewhere, and specifies a template to be
+used to format the data. This is quite different from how Maypole
+normally operates, so we have a choice as to whether we're going to
+completely copy this design, or use a more "natural" implementation in 
+terms of having the portal display defined as a template itself, with
+all the modules specified right there in Template Toolkit code rather
+than picked up from the database. This would be much faster, since you
+get one shot of rendering instead of having to process each module's
+template independently. The thing is, I feel like showing off
+precisely how flexible Maypole is, so we'll do it the hard way.
+
+The first thing we need to do is get the database into some sort of
+useful shape, and work out the relationships between the tables. This of
+course requires half a day of playing with GraphViz, Omnigraffle and
+mysql, but ended up with something like this:
+
+=for html
+<img src="ibs-schema.png">
+
+This leads naturally to the following driver code:
+
+    package Portal;
+    use base 'Apache::MVC';
+    Portal->setup("dbi:mysql:ibsportal");
+    use Class::DBI::Loader::Relationship;
+    Portal->config->{loader}->relationship($_) for (
+        "A module has a definition",  "A module has settings",
+        "A tab has modules",          "A portal has tabs",
+        "A role has a portal",        "A definition has a portal",
+        "A module has announcements", "A module has contacts",
+        "A module has discussions",   "A module has events",
+        "A module has htmltexts",     "A module has links",
+        "A module has documents",
+        "A user has roles via userrole"
+    );
+    1;
+
+As you can see, a portal is made up of a number of different tabs;
+the tabs contain modules, but they're separated into different panes,
+so a module knows whether it belongs on the left pane, the right pane
+or the center. A module also knows where it appears in the pane.
+
+We'll begin by mocking up the portal view in plain text, like so:
+
+    use Portal;
+    my $portal = Portal::Portal->retrieve(2);
+    for my $tab ($portal->tabs) {
+        print $tab,"\n";
+        for my $pane (qw(LeftPane ContentPane RightPane)) {
+            print "\t$pane:\n";
+            for (sort { $a->module_order <=> $b->module_order }
+                $tab->modules(pane => $pane)) {
+                print "\t\t$_:\t", $_->definition,"\n";
+            }
+        }
+        print "\n";
+    }
+
+This dumps out the tabs of our portal, along with the modules in each
+tab and their types; this lets us check that we've got the database
+set up properly. If we have, it should produce something like this:
+
+    Home
+            LeftPane:
+                    Quick link:     Quicklink
+            ContentPane:
+                    Welcome to the IBuySpy Portal:  Html Document
+                    News and Features:      announcement
+                    Upcoming event: event
+            RightPane:
+                    This Week's Special:    Html Document
+                    Top Movers:     XML/XSL
+
+    ...
+
+Now we want to get the front page up; for the moment, we'll just have it
+display the module names and their definitions like our text mock-up,
+and we'll flesh out the actual modules later.
+
+But before we do that, we'll write a front-end URL handler method, to
+allow us to ape the ASP file names. Why do we want to make a Maypole
+site look like it's running C<.aspx> files? Because we can! - and
+because I want to show we don't necessarily B<have> to follow the
+Maypole tradition of having our URLs look like
+C</I<table>/I<action>/I<id>/I<arguments>>. 
+
+    our %pages = (
+        "DesktopDefault.aspx" => { action => "view", table => "tab" },
+        "MobileDefault.aspx"  => { action => "view_mobile", table => "tab" },
+    );
+
+    sub parse_path {
+        my $self = shift;
+        $self->{path} ||= "DesktopDefault.aspx";
+        return $self->SUPER::parse_path if not exists $pages{$self->{path}};
+        my $page = $pages{$self->{path}} ;
+        $self->{action} = $page->{action};
+        $self->{table} = $page->{table};
+        my %query = $self->{ar}->args;
+        $self->{args} = [ $query{tabid} || $query{ItemID} || 1];
+    }
+
+    1;
+
+Here we're overriding the C<parse_path> method which takes the C<path>
+slot from the request and populates the C<table>, C<action> and
+C<arguments> slots. If the user has asked for a page we don't know
+about, we ask the usual Maypole path handling method to give it a try;
+this will become important later on. We turn the default page,
+C<DesktopDefault.aspx>, into the equivalent of C</tab/view/1> unless
+another C<tabid> or C<ItemID> is given in the query parameters; this allows us
+to use the ASP.NET-style C<DesktopDefault.aspx?tabid=3> to select a tab.
+
+Now we have to create our C<tab/view> template; the majority of
+this is copied from the F<DesktopDefault.aspx> source, but our panes
+look like this:
+
+    <td id="LeftPane" Width="170">
+        [% pane("LeftPane") %]
+    </td>
+    <td width="1">
+    </td>
+    <td id="ContentPane" Width="*">
+        [% pane("ContentPane") %]
+    </td>
+    <td id="RightPane" Width="230">
+        [% pane("RightPane") %]
+    </td>
+    <td width="10">
+        &nbsp;
+   </td>
+
+The C<pane> macro has to be the Template Toolkit analogue of the Perl code
+we used for our mock-up:
+
+    [% MACRO pane(panename) BLOCK;
+        FOR module = tab.modules("pane", panename);
+            "<P>"; module; " - "; module.definition; "</P>";
+        END;
+    END;
+
+Now, the way that the iBuySpy portal works is that each module has a
+definition, and each definition contains a path to a template:
+C<$module-E<gt>definition-E<gt>DesktopSrc> returns a path name for an C<ascx>
+component file. All we need to do is convert those files from ASP to the
+Template Toolkit, and have Maypole process each component for each module,
+right?
+
+=head2 Components and templates
+
+Dead right, but it was here that I got too clever. I guess it was the word
+"component" that set me off. I thought that since the page was made up of a
+large number of different modules, all requiring their own set of objects, I
+should use a seperate Maypole sub-request for each one, as shown in the
+"Component-based pages" recipe in L<Request.pod>.
+
+So this is what I did. I created a method in C<Portal::Module> that would
+set the template to the appropriate C<ascx> file:
+
+    sub view_desktop :Exported {
+        my ($self, $r) = @_;
+        $r->{template} = $r->objects->[0]->definition->DesktopSrc;
+    }
+
+and changed the C<pane> macro to fire off a sub-request for each module:
+
+    [% MACRO pane(panename) BLOCK;
+        FOR module = tab.modules("pane", panename);
+            SET path = "/module/view_desktop/" _ module.id;
+            request.component(path);
+        END;
+    END; %]
+
+This did the right thing, and a call to C</module/view_desktop/12> would
+look up the C<Html Document> module definition, find the C<DesktopSrc> to
+be F<DesktopModules/HtmlModule.ascx>, and process module 12 with that
+template. Once I had converted F<HtmlModule.ascx> to be a Template Toolkit
+file (and we'll look at the conversion of the templates in a second) it
+would display nicely on my portal.
+
+Except it was all very slow; we were firing off a large number of Maypole
+requests in series, so that each template could get at the objects it
+needed. Requests were taking 5 seconds.
+
+That's when it dawned on me that these templates don't actually need different
+objects at all. The only object of interest that C</module/view_desktop> is
+passing in is a C<module> object, and each template figures everything out by
+accessor calls on that. But we already have a C<module> object, in our C<FOR>
+loop - we're using it to make the component call, after all! Why not just
+C<PROCESS> each template inside the loop directly?
+
+    [% MACRO pane(panename) BLOCK;
+        FOR module = tab.modules("pane", panename);
+            SET src = module.definition.DesktopSrc;
+            TRY;
+                PROCESS $src;
+            CATCH DEFAULT;
+                "Bah, template $src broke on me!";
+            END;
+        END;
+    END; %]
+
+This worked somewhat better, and took request times from 5 seconds down
+to acceptable sub-second levels again. I could take the C<view_desktop>
+method out again; fewer lines of code to maintain is always good. Now
+all that remained to do for the view side of the portal was to convert
+our ASP templates over to something sensible.
+
+=head2 ASP to Template Toolkit
+
+They're all much of a muchness, these templating languages. Some of
+them, though, are just a wee bit more verbose than others. For instance,
+the banner template which appears in the header consists of 104 lines
+of ASP code; most of those are to create the navigation bar of tabs
+that we can view. Now I admit that we're slightly cheating at the moment
+since we don't have the concept of a logged-in user and so we don't
+distinguish between the tabs that anyone can see and those than only an
+admin can see, but we'll come back to it later. Still, 104 lines, eh?
+
+The actual tab list is presented here: (reformated slightly for sanity)
+
+    <tr>
+        <td>
+            <asp:datalist id="tabs" cssclass="OtherTabsBg" 
+ repeatdirection="horizontal" ItemStyle-Height="25" 
+ SelectedItemStyle-CssClass="TabBg" ItemStyle-BorderWidth="1" 
+ EnableViewState="false" runat="server">
+                <ItemTemplate>
+                    &nbsp;<a href='<%= Request.ApplicationPath %>/
+ DesktopDefault.aspx?tabindex=<%# Container.ItemIndex %>&tabid=
+ <%# ((TabStripDetails) Container.DataItem).TabId %>' class="OtherTabs">
+ <%# ((TabStripDetails) Container.DataItem).TabName %></a>&nbsp;
+                </ItemTemplate>
+                <SelectedItemTemplate>
+                    &nbsp;<span class="SelectedTab">
+ <%# ((TabStripDetails) Container.DataItem).TabName %></span>&nbsp;
+                </SelectedItemTemplate>
+            </asp:datalist>
+        </td>
+    </tr>
+
+But it has to be built up in some 22 lines of C# code which creates and
+populates an array and then binds it to a template parameter. See those
+C<E<lt>%#> and C<E<lt>%=> tags? They're the equivalent of our Template
+Toolkit C<[% %]> tags. C<Request.ApplicationPath>? That's our C<base>
+template argument. 
+
+In our version we ask the portal what tabs it has, and display the
+list directly, displaying the currently selected tab differently:
+
+    <table id="Banner_tabs" class="OtherTabsBg" cellspacing="0" border="0">
+        <tr>
+    [% FOR a_tab = portal.tabs %]
+        [% IF a_tab.id == tab.id %]
+            <td class="TabBg" height="25">
+                &nbsp;<span class="SelectedTab">[%tab.name%]</span>&nbsp;
+        [% ELSE %]
+            <td height="25">
+                &nbsp;<a href='[%base%]DesktopDefault.aspx?tabid=[%a_tab.id%]' 
+                class="OtherTabs">[%a_tab.name%]</a>&nbsp;
+        [% END %]
+            </td>
+    [% END %]
+        </tr>
+    </table>
+
+This is the way the world should be. But wait, where have we pulled this
+C<portal> variable from? We need to tell the C<Portal> class to put the
+default portal into the template arguments:
+
+    sub additional_data {
+        shift->{template_args}{portal} = Portal::Portal->retrieve(2);
+    }
+
+Translating all the other ASP.NET components is a similar exercise in drudgery;
+on the whole, there was precisely nothing interesting about them at all - we
+merely converted a particularly verbose templating language (and if I never see
+C<asp:BoundColumn> again, it'll be no loss) into a rather more sophisticated
+one.
+
+The simplest component, F<HtmlModule.ascx>, asks a module for its associated
+C<htmltexts>, and then displays the C<DesktopHtml> for each of them in a table.
+This was 40 lines of ASP.NET, including more odious C# to make the SQL calls
+and retrieve the C<htmltexts>. But we can do all that retrieval by magic, so
+our F<HtmlModule.ascx> looks like this:
+
+    [% PROCESS module_title %]
+    <portal:title EditText="Edit" EditUrl="~/DesktopModules/EditHtml.aspx" />
+    <table id="t1" cellspacing="0" cellpadding="0">
+        <tr valign="top">
+            <td id="HtmlHolder">
+            [% FOR html = module.htmltexts; html.DesktopHtml; END %]
+            </td>
+        </tr>
+    </table>
+
+Now I admit that we've cheated here and kept that C<portal:title> tag
+until we know what to do with it - it's obvious that we should turn
+it into a link to edit the HTML of this module if we're allowed to.
+
+The next simplest one actually did provide a slight challenge;
+F<ImageModule.ascx> took the height, width and image source properties
+of an image from the module's C<settings> table, and displayed an C<IMG>
+tag with the appropriate values. This is only slightly difficult because
+we have to arrange the array of C<module.settings> into a hash of
+C<key_name> => C<setting> pairs. Frankly, I can't be bothered to do this
+in the template, so we'll add it into the C<template_args> again. This
+time C<addition_data> looks like:
+
+    sub additional_data {
+        my $r = shift;
+        shift->{template_args}{portal} = Portal::Portal->retrieve(2);
+        if ($r->{objects}->[0]->isa("Portal::Module")) {
+            $r->{template_args}{module_settings} =
+                { map { $_->key_name, $_->setting } 
+                  $r->{objects}->[0]->settings };
+        }
+    }
+
+And the F<ImageModule.ascx> drops from the 30-odd lines of ASP into:
+
+    [% PROCESS module_title; %]
+    <img id="Image1" border="0" src="[% module_settings.src %]" 
+      width="[% module_settings.width %]" 
+      height="[% module_settings.height %]" />
+    <br>
+
+Our portal is taking shape; after a few more templates have been translated,
+we now have a complete replica of the front page of the portal and all its
+tabs. It's fast, it's been developed rapidly, and it's less than 50 lines
+of Perl code so far. But it's not finished yet.
+
+=head2 Adding users
+
diff --git a/lib/Maypole/Manual/Flox.pod b/lib/Maypole/Manual/Flox.pod
new file mode 100644 (file)
index 0000000..f42bc2e
--- /dev/null
@@ -0,0 +1,492 @@
+=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 - 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 student population.
+
+Flox is still in, uh, flux, but it does the essentials. 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...
+
+=head2 Mapping the concepts
+
+Any Maypole application should start with two things: a database schema,
+and some idea of what the pages involved are going to look like.
+Usually, these pages will be tying to displaying or editing some element
+of the database, so these two concepts should come hand in hand.
+
+When I started looking at social networking sites, I began by
+identifying the concepts which were going to make up the tables of the
+application. At its most basic, a site like Orkut or Flox has two
+distinct concepts: a user, and a connection between two users.
+Additionally, there's the idea of an invitation to a new user, which can
+be extended, accepted, declined or ignored. These three will make up the
+key tables; there are an extra two tables in Flox, but they're
+essentially enumerations that are a bit easier to edit: each user has an
+affiliation to a particular college or department, and a status in the
+university. (Undergraduate, graduate, and so on.)
+
+For this first run-through, we're going to ignore the ideas of societies
+and communities, and end up with a schema like so:
+
+    CREATE TABLE user (
+        id int not null auto_increment primary key,
+        first_name varchar(50),
+        last_name varchar(50),
+        email varchar(255),
+        profile text,
+        password varchar(255),
+        affiliation int,
+        unistatus int,
+        status ENUM("real", "invitee"),
+        photo blob,
+        photo_type varchar(30)
+    );
+
+    CREATE TABLE connection (
+        id int not null auto_increment primary key,
+        from_user int,
+        to_user int,
+        status ENUM("offered", "confirmed")
+    );
+
+    CREATE TABLE invitation (
+        id char(32) not null primary key,
+        issuer int,
+        recipient int,
+        expires date
+    );
+
+Plus the definition of our two auxilliary tables:
+
+    CREATE TABLE affiliation (
+        id int not null auto_increment primary key,
+        name varchar(255)
+    );
+
+    CREATE TABLE unistatus (
+        id int not null auto_increment primary key,
+        name varchar(255)
+    );
+
+Notice that, for simplicity, invitations and friendship connections are
+quite similar: they are extended from one user to another. This means
+that people who haven't accepted an invite yet still have a place in the
+user table, with a different C<status>. Similarly, a connection between
+users can be offered, and when it is accepted, its status is changed to
+"confirmed" and a reciprocal relationship put in place.
+
+We also have some idea, based on what we want to happen, of what pages
+and actions we're going to define. Leaving the user aside for the
+moment, we want an action which extends an invitation from the current
+user to a new user. We want a page the new user can go to in order to
+accept that invitation. Similarly, we want an action which offers a
+friendship connection to an existing user, and a page the user can go to
+to accept or reject it. This gives us five pages so far:
+
+    invitation/issue
+    invitation/accept
+
+    user/befriend
+    connection/accept
+    connection/reject
+
+Notice that the C<befriend> action is performed on a user, not a
+connection. This is distinct from C<invitation/issue> because when
+befriending, we have a real user on the system that we want to do
+something to. This makes sense if you think of it in terms of object
+oriented programming - we could say
+
+    Flox::Connection->create(to => $user)
+
+but it's clearer to say
+
+    $user->befriend
+
+Similarly, we could say
+
+    Flox::User->create({ ... })->issue_invitation_to
+
+but it's clearer to say
+
+    Flox::Invitation->issue( to => Flox::User->create({ ... }) )
+
+because it more accurately reflects the principal subject and object of
+these actions.
+
+Returning to look at the user class, we want to be able to view a user's
+profile, edit one's own profile, set up the profile for the first
+time, upload pictures and display pictures. We also need to handle the
+concepts of logging in and logging out.
+
+As usual, though, we'll start with a handler class which sets up the
+database:
+
+    package Flox;
+    use base qw(Apache::MVC);
+    Flox->setup("dbi:mysql:flox");
+    Flox->config->{display_tables} = [qw[user invitation connection]];
+    1;
+
+Very simple, as these things are meant to be. Now let's build on it.
+
+=head2 Authentication
+
+The concept of a current user is absolutely critical in a site like
+Flox; it represents "me", the viewer of the page, as the site explores
+the connections in my world. We've described the authentication hacks
+briefly in the L<Request.pod> chapter, but now it's time to go into a
+little more detail about how user handling is done.
+
+XXX
+
+We also want to be able to refer to the current user from the templates,
+so we use the overridable C<additional_data> method to give us a C<my>
+template variable:
+
+    sub additional_data { 
+        my $r = shift; $r->{template_args}{my} = $r->{user}; 
+    }
+
+I've called it C<my> rather than C<me> because we it lets us check 
+C<[% my.name %]>, and so on.
+
+=head2 Viewing a user
+
+The first page that a user will see after logging in will be their own
+profile, so in order to speed development, we'll start by getting a
+C<user/view> page up.
+
+The only difference from a programming point of view between this action
+and the default C<view> action is that, if no user ID is given, then we
+want to view "me", the current user. Remembering that the default view
+action does nothing, our C<Flox::User::view> action only needs to do
+nothing plus ensure it has a user in the C<objects> slot, putting
+C<$r-E<gt>{user}> in there if not:
+
+    sub view :Exported {
+        my ($class, $r) = @_;
+        $r->{objects} = [ $r->{user} ] unless @{$r->{objects}||[]};
+    }
+
+Maypole, unfortunately, is very good at making programming boring. The
+downside of having to write very little code at all is that we now have
+to spend most of our time writing nice HTML for the templates.
+
+XXX
+
+The next stage is viewing the user's photo. Assuming we've got the photo
+stored in the database already (which is a reasonable assumption for the
+moment since we don't have a way to upload a photo quite yet) then we
+can use the a variation of the "Displaying pictures" hack from the 
+Requests chapter:
+
+    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;
+        } else {
+           # Read no-photo photo
+           $r->{content_type} = "image/png";
+           $r->{output} = slurp_file("images/no-photo.png");
+        }
+    }
+
+We begin by getting a user object, just like in the C<view> action: either
+the user whose ID was passed in on the URL, or the current user. Then
+we check if a C<photo_type> has been set in this user's record. If so,
+then we'll use that as the content type for this request, and the data
+in the C<photo> attribute as the data to send out. The trick here is
+that setting C<$r-E<gt>{output}> overrides the whole view class processing
+and allows us to write the content out directly.
+
+In our template, we can now say
+
+    <IMG SRC="/user/view_picture/[% user.id %]">
+
+and the appropriate user's mugshot will appear.
+
+However, if we're throwing big chunks of data around like C<photo>, it's
+now worth optimizing the C<User> class to ensure that only pertitent
+data is fetched by default, and C<photo> and friends are only fetched on
+demand. The "lazy population" section of C<Class::DBI>'s man page
+explains how to group the columns by usage so that we can optimize
+fetches:
+
+    Flox::User->columns(Primary   => qw/id/);
+    Flox::User->columns(Essential => qw/status/);
+    Flox::User->columns(Helpful   => qw/ first_name last_name email password/)
+    Flox::User->columns(Display   => qw/ profile affiliation unistatus /);
+    Flox::User->columns(Photo     => qw/ photo photo_type /);
+
+This means that the status and ID columns will always be retrieved when
+we deal with a user; next, any one of the name, email or password
+columns will cause that group of data to be retrieved; if we go on to
+display more information about a user, we also load up the profile,
+affiliation and university status; finally, if we're throwing around
+photos, then we load in the photo type and photo data.
+
+These groupings are somewhat arbitrary, and there needs to be a lot of
+profiling to determine the most efficient groupings of columns to load,
+but they demonstrate one principle about working in Maypole: this is the
+first time in dealing with Maypole that we've had to explicitly list the
+columns of a table, but Maypole has so far Just Worked. There's a
+difference, though, between Maypole just working and Maypole working
+well, and if you want to optimize your application, then you need to
+start putting in the code to do that. The beauty of Maypole is that you
+can do as much or as little of such optimization as you want or need.
+
+So now we can view users and their photos. It's time to allow the users
+to edit their profiles and upload a new photo.
+
+=head2 Editing users
+
+XXX Editing a profile
+
+I introduced Flox to a bunch of friends and told them to be as ruthless
+as possible in finding bugs and trying to break it. And break it they
+did; within an hour the screens were thoroughly messed up as users had
+nasty HTML tags in their profiles, names, email addresses and so on. 
+This spawned another hack in the request cookbook: "Limiting data for
+display". I changed the untaint columns to use C<html> untainting, and
+all was better:
+
+    Flox::User->untaint_columns(
+        html      => [qw/first_name last_name profile/],
+        printable => [qw/password/],
+        integer   => [qw/affiliation unistatus /],
+        email     => [qw/email/]
+    );
+
+The next stage was the ability to upload a photo. We unleash the "Uploading
+files" recipe, with an additional check to make sure the photo is of a
+sensible size:
+
+    use constant MAX_IMAGE_SIZE => 512 * 1024;
+    sub do_upload :Exported {
+        my ($class, $r) = @_;
+        my $user = $r->{user};
+        my $upload = $r->{ar}->upload("picture");
+        if ($upload) {
+            my $ct = $upload->info("Content-type");
+            return $r->error("Unknown image file type $ct")
+                if $ct !~ m{image/(jpeg|gif|png)};
+            return $r->error("File too big! Maximum size is ".MAX_IMAGE_SIZE)
+                if $upload->size > MAX_IMAGE_SIZE;
+
+            my $fh = $upload->fh;
+            my $image = do { local $/; <$fh> };
+
+            use Image::Size;
+            my ($x, $y) = imgsize(\$image);
+            return $r->error("Image too big! ($x, $y) Maximum size is 350x350")
+                if $y > 350 or $x > 350;
+            $r->{user}->photo_type($ct);
+            $r->{user}->photo($image);
+        }
+
+        $r->objects([ $user ]);
+        $r->{template} = "view";
+    }
+
+Now we've gone as far as we want to go about user editing at the moment.
+Let's have a look at the real meat of a social networking site: getting
+other people involved, and registering connections between users. 
+
+=head2 Invitations
+
+We need to do two things to invitations working: first provide a way to
+issue an invitation, and then provide a way to accept it. Since what
+we're doing in issuing an invitation is essentially creating a new
+one, we'll use our usual practice of having a page to display the form
+to offer an invitation, and then use a C<do_edit> method to actually do
+the work. So our C<issue> method is just an empty action:
+
+    sub issue :Exported {}
+
+and the template proceeds as normal:
+
+    [% PROCESS header %]
+    <h2> Invite a friend </h2>
+
+    <FORM ACTION="[%base%]/invitation/do_edit/" METHOD="post">
+    <TABLE>
+
+Now we use the "Catching errors in a form" recipe from L<Request.pod> and
+write our form template:
+
+    <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>
+    [% 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 %]
+    <TR>
+    ...
+
+Now we need to work on the C<do_edit> action. This has to validate the
+form parameters, create the invited user, create the row in the C<invitation>
+table, and send an email to the new user asking them to join.
+
+We'd normally use C<create_from_cgi> to do the first two stages, but this time
+we handle the untainting manually, because there are a surprising number of
+things we need to check before we actually do the create. So here's the
+untainting of the parameters:
+
+    my ($self, $r) = @_;
+    my $h = CGI::Untaint->new(%{$r->{params}});
+    my (%errors, %ex);
+    for (qw( email forename surname )) {
+        $ex{$_} = $h->extract(
+                "-as_".($_ eq "email" ? "email" : "printable") => $_
+        ) or $errors{$_} = $h->error;
+    }
+
+Next, we do the usual dance of throwing the user back at the form in case
+of errors:
+
+    if (keys %errors) {
+        $r->{template_args}{message} = "There was something wrong with that...";
+        $r->{template_args}{errors} = \%errors;
+        $r->{template} = "issue";
+        return;
+    }
+
+We've introduced a new template variable here, C<message>, which we'll use
+to display any important messages to the user.
+
+The first check we need to do is whether or not we already have a user
+with that email address. If we have, and they're a real user, then we
+abort the invite progress and instead redirect them to viewing that user's 
+profile.
+
+    my ($user) = Flox::User->search({ email => $ex{email} });
+    if ($user) {
+        if ($user->status eq "real") {
+            $r->{template_args}{message} =
+                "That user already seems to exist on Flox. ".
+                "Is this the one you meant?";
+
+            $self->redirect_to_user($r,$user);
+        } 
+
+Where C<redirect_to_user> looks like this:
+
+    sub redirect_to_user {
+        my ($self, $r, $user) = @_;
+        $r->{objects} = [ $user ];
+        $r->{template} = "view";
+        $r->{model_class} = "Flox::User"; # Naughty.
+    }
+
+This is, as the comment quite rightly points out, naughty. We're currently
+doing a C</invitation/do_edit/> and we want to turn this into a
+C</user/view/xxx>, changing the table, template and arguments all at once.
+To do this, we have to change the Maypole request object's idea of the model
+class, since this determines where to look for the template: if we didn't,
+we'd end up with C<invitation/view> instead of C<user/view>.
+
+Ideally, we'd do this with a Apache redirect, but we want to get that
+C<message> in there as well, so this will have to do. This isn't good practice;
+we put it into a subroutine so that we can fix it up if we find a better way
+to do it.
+
+Anyway, this is what we should do if a user already exists on the system
+and has accepted an invite already. What if we're trying to invite a user but
+someone else has invited them first and they haven't replied yet?
+
+         } else {
+            # Put it back to the form
+            $r->{template_args}{message} =
+            "That user has already been invited; ".
+            "please wait for them to accept";
+            $r->{template} = "issue";
+        }
+        return;
+    }
+
+Race conditions suck.
+
+Okay. Now we know that the user doesn't exist, and so can create the new 
+one:
+
+    my $new_user = Flox::User->create({
+        email => $ex{email},
+        first_name => $ex{forename},
+        last_name  => $ex{surname},
+        status => "invitee"
+    });
+
+We want to give the invitee a URL that they can go to in order to
+accept the invite. Now we don't just want the IDs of our invites to
+be sequential, since someone could get one invite, and then guess the
+rest of the invite codes. We provide a relatively secure MD5 hash as
+the invite ID:
+
+    my $random = md5_hex(time.(0+{}).$$.rand);
+
+For additional security, we're going to have the URL in the form
+C</invitation/accept/I<id>/I<from_id>/I<to_id>>, encoding the user ids
+of the two users. Now we can send email to the invitee to ask them to
+visit that URL:
+
+    my $newid = $new_user->id;
+    my $myid  = $r->{user}->id;
+    _send_mail(to => $ex{email}, url => "$random/$myid/$newid", 
+               user => $r->{user});
+
+I'm not going to show the C<_send_mail> routine, since it's boring.
+We haven't actually created the C<Invitation> object yet, so let's
+do that now.
+
+    Flox::Invitation->create({
+        id => $random,
+        issuer => $r->{user},
+        recipient => $new_user,
+        expires => Time::Piece->new(time + LIFETIME)->datetime
+    });
+
+You can also imagine a daily cron job that cleans up the C<Invitation>
+table looking for invitations that ever got replied to within their
+lifetime:
+
+   ($_->expires > localtime && $_->delete)
+       for Flox::Invitation->retrieve_all;
+
+Notice that we don't check whether the ID is already used. We could, but,
+you know, if MD5 sums start colliding, we have much bigger problems on
+our hands.
+
+Anyway, now we've got the invitation created, we can go back to whence we
+came: viewing the original user:
+
+    $self->redirect_to_user($r, $r->{user});
+
+Now our invitee has an email, and goes B<click> on the URL. What happens?
+
+XXX
+
+=head2 Friendship Connections
+
+=head2 
diff --git a/lib/Maypole/Manual/Model.pod b/lib/Maypole/Manual/Model.pod
new file mode 100644 (file)
index 0000000..bc54ffd
--- /dev/null
@@ -0,0 +1,109 @@
+=head1 Maypole Model Classes
+
+=head2 Class::DBI
+
+=head2 Maypole::Model::CDBI
+
+Maypole model classes are pretty evil. The very first thing a Maypole
+model class will do in a Maypole application is to cause a load of
+table-based classes to come into being, and then assimilate them.
+
+What I mean by this is that when you set up a Maypole application, in
+your driver class, you'll say something like this:
+
+    BeerDB->setup("dbi:mysql:beerdb");
+
+C<setup> is a Maypole method, and it hands its parameter to the model
+class. In our case, the model class is a DBI connect string, because
+that's what C<Maypole::Model::CDBI>, the C<Class::DBI>-based model
+expects. C<Maypole::Model::CDBI> has a method called C<setup_database>
+that creates all the C<Class::DBI> table classes after connecting to the
+database with that connect string. It does this by using
+C<Class::DBI::Loader>, a utility module which asks a database
+about its schema and sets up classes such as C<BeerDB::Beer> to inherit
+from C<Class::DBI>. This is just doing automatically what we did
+manually in our examples above.
+
+Now it gets interesting. The names of these classes are stashed away in
+the application's configuration, and then Maypole forcibly has these
+classes inherit from the model class. Our C<BeerDB::Beer> now inherits
+both from C<Class::DBI> and C<Maypole::Model::CDBI>.
+
+This is useful for two reasons. The first reason is that
+C<Maypole::Model::CDBI> is stuffed full of C<Class::DBI> goodies that
+make writing Maypole applications a lot easier:
+
+    package Maypole::Model::CDBI;
+    use base qw(Maypole::Model::Base Class::DBI);
+    use Class::DBI::AsForm;
+    use Class::DBI::FromCGI;
+    use Class::DBI::Loader;
+    use Class::DBI::AbstractSearch;
+    use Class::DBI::Plugin::RetrieveAll;
+    use Class::DBI::Pager;
+
+We'll meet most of these goodies in L<StandardTemplates.pod>, where we
+explain how C<Maypole::Model::CDBI> works.
+
+The second reason why we want our table classes to inherit from
+C<Maypole::Model::CDBI> is because C<CDBI> provides a useful set of 
+default actions. So what's an action, and why are they useful?
+
+=head2 Extending a model class with actions
+
+Maypole operates primarily by turning URLs into method calls on a model
+class. All that the model stage of Maypole's operation does, when it
+comes down to it, is maintain a mapping of tables to classes, and
+despatch a HTTP request to a method call on the relevant table class. This
+means that if you request a URL such as
+
+    http://localhost/beerdb/brewery/delete/20
+
+Maypole's first stage of operation is to turn that into
+C<BeerDB::Brewery-E<gt>delete(20)>. Now, it's slightly more complex than
+that. Firstly because it doesn't actually pass the parameter C<20>, but
+it passes an object representing row 20 in the database, but we can
+gloss over that for the second. No, the real issue is that Maypole does
+not allow you to call any method in the table class; that would be
+somewhat insecure. 
+
+Instead, Maypole makes a distinction between the kind of methods that
+only the class itself and other Perl code can call, and the kind of
+methods that anyone can call from a URL. This latter set of methods are
+called B<exported> methods, and exporting is done with by means of Perl
+attributes. You define a method to be exported like so:
+
+    sub drink :Exported {
+
+This will allow the user to access C</beerdb/beer/drink> over the web.
+An exported method accompanied with a template to render its output is
+sometimes called an B<action>. 
+
+Maypole model classes like C<Maypole::Model::CDBI> come with a
+relatively handy set of actions which are all you need to set up a CRUD
+database front-end: viewing a row in a database, editing it, adding a
+new one, deleting, and so on. The most important thing about Maypole,
+though, is that it doesn't stop there. You can add your own.
+
+For instance, in our beer database application, we could create a
+C<BeerDB::Beer> package, and put some additional actions in there.
+
+    package BeerDB::Beer;
+    sub top_five :Exported {
+        my ($class, $r) = @_;
+        $r->{objects} = [ ($r->retrieve_all_sorted_by("score"))[-5..-1] ];
+    }
+
+Our action is called as a class method with the Maypole request object.
+It uses the C<Class::DBI::Plugin::RetrieveAll> module's
+C<retrieve_all_sorted_by> mixin to get the top five scoring beers, and
+puts these in the C<objects> slot of the request of object. Next, the
+view class will come along and process the C<top_five> template with
+these five beers.
+
+We'll look more at how to put together actions in the
+L<StandardTemplates.pod> chapter and our case studies.
+
+=head2 What Maypole wants from a model
+
+=head2 Building your own model class
diff --git a/lib/Maypole/Manual/Overview.pod b/lib/Maypole/Manual/Overview.pod
new file mode 100644 (file)
index 0000000..e5e6151
--- /dev/null
@@ -0,0 +1,32 @@
+=head1 Overview of Maypole Documentation
+
+The Maypole documentation is arranged over several files; this is a good
+one to start with.
+
+Once you've read this, you should probably look at L<About.pod>, the
+guide to what Maypole is and how the Maypole request works. It also
+describes how to set up a simple CRUD web application in Maypole.
+
+The next two chapters are quite thorough, and you might want to skip
+over them if you already know how L<Class::DBI> and the L<Template>
+toolkit work. L<Model.pod> and L<View.pod> describe these technologies
+and their relationship to Maypole.
+
+Now we present the default actions and templates - the F<factory>
+templates - in L<StandardTemplates.pod>. When you have read these
+chapters, you are ready to start building more complex applications in
+Maypole than just a simple CRUD interface. L<Beer.pod> reintroduces the
+beer database application and shows how to move from the "magic" of the
+automatically supplied templates and actions to a customized application
+with user-specified actions.
+
+L<Request.pod> contains more information about the Maypole request
+object and provides some cookbook-style techniques: how to provide
+authentication, how to provide a REST interface, how to override various
+stages of the content generation process, and so on.
+
+The final chapters are examples of how to construct large web
+applications in Maypole: L<Flox.pod> describes a "social network" site
+similar to Friendster and Orkut; L<PetStore.pod> implements the Java/C#
+benchmark Pet Store application; and L<BuySpy.pod> implements the
+ASP.NET sample portal application.
diff --git a/lib/Maypole/Manual/Request.pod b/lib/Maypole/Manual/Request.pod
new file mode 100644 (file)
index 0000000..bc2b303
--- /dev/null
@@ -0,0 +1,760 @@
+=head1 Maypole Request Hacking Cookbook
+
+Hacks; design patterns; recipes: call it what you like, this chapter is a
+developing collection of techniques which can be slotted in to Maypole
+applications to solve common problems or make the development process easier.
+
+As Maypole developers, we don't necessarily know the "best practice" for
+developing Maypole applications ourselves, in the same way that Larry Wall
+didn't know all about the best Perl programming style as soon as he wrote
+Perl. These techniques are what we're using at the moment, but they may
+be refined, modularized, or rendered irrelevant over time. But they've
+certainly saved us a bunch of hours work.
+
+=head2 Frontend hacks
+
+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
+some place outside of the whole Apache/mod_perl/HTTP/Internet/browser circus.
+
+B<Solution>: Use the C<Maypole::CLI> module to go directly from a URL to
+standard output, bypassing Apache and the network altogether.
+
+C<Maypole::CLI> is not a standalone front-end, but to allow you to debug your
+applications without having to change the front-end they use, it temporarily
+"borgs" an application. If you run it from the command line, you're expected
+to use it like so:
+
+    perl -MMaypole::CLI=Application -e1 'http://your.server/path/table/action'
+
+For example:
+
+    perl -MMaypole::CLI=BeerDB -e1 'http://localhost/beerdb/beer/view/1?o2=desc'
+
+You can also use the C<Maypole::CLI> module programatically to create
+test suites for your application. See the Maypole tests themselves or
+the documentation to C<Maypole::CLI> for examples of this.
+
+=head3 Changing how URLs are parsed
+
+You don't like the way Maypole URLs look, and want something that either
+fits in with the rest of your site or hides the internal workings of the
+system.
+
+C<Solution>: So far we've been using the C</table/action/id/args> form
+of a URL as though it was "the Maypole way"; well, there is no Maypole
+way. Maypole is just a framework and absolutely everything about it is 
+overridable. 
+
+If we want to provide our own URL handling, the method to override in
+the driver class is C<parse_path>. This is responsible for taking
+C<$r-E<gt>{path}> and filling the C<table>, C<action> and C<args> slots
+of the request object. Normally it does this just by splitting the path
+on C</>s, but you can do it any way you want, including getting the
+information from C<POST> form parameters or session variables. 
+
+For instance, suppose we want our URLs to be of the form
+C<ProductDisplay.html?id=123>, we could provide a C<parse_path> method
+like so:
+
+    sub parse_path {
+        my $r = shift;
+        $r->{path} ||= "ProductList.html";
+        ($r->{table}, $r->{action}) = 
+            ($r->{path} =~ /^(.*?)([A-Z]\w+)\.html/);
+        $r->{table}  = lc $r->{table};
+        $r->{action} = lc $r->{action};
+        my %query = $r->{ar}->args;
+        $self->{args} = [ $query{id} ];
+    }
+
+This takes the path, which already has the query parameters stripped off
+and parsed, and finds the table and action portions of the filename,
+lower-cases them, and then grabs the C<id> from the query. Later methods
+will confirm whether or not these tables and actions exist.
+
+See L<BuySpy.pod> for another example of custom URL processing.
+
+=head3 Maypole for mobile devices
+
+You want Maypole to use different templates to display on particular
+browsers.
+
+B<Solution>: There are several ways to do this, but here's the neatest
+we've found. Maypole chooses where to get its templates either by
+looking at the C<template_root> config parameter or, if this is not
+given, calling the C<get_template_root> method to ask the front-end to
+try to work it out. We can give the front-end a little bit of help, by
+putting this method in our driver class:
+
+    sub get_template_root {
+        my $r = shift;
+        my $browser = $r->{ar}->headers_in->get('User-Agent');
+        if ($browser =~ /mobile|palm|nokia/i) {
+            "/home/myapp/templates/mobile";
+        } else {
+            "/home/myapp/templates/desktop";
+        }
+    }
+
+(Maybe there's a better way to detect a mobile browser, but you get the
+idea.)
+
+=head2 Content display hacks
+
+These hacks deal primarily with the presentation of data to the user,
+modifying the C<view> template or changing the way that the results of
+particular actions are displayed.
+
+=head3 Null Action
+
+You need an "action" which doesn't really do anything, but just formats
+up a template.
+
+B<Solution>: There are two ways to do this, depending on what precisely
+you need. If you just need to display a template, C<Apache::Template>
+style, with no Maypole objects in it, then you don't need to write any
+code; just create your template, and it will be available in the usual
+way.
+
+If, on the other hand, you want to display some data, and what you're
+essentially doing is a variant of the C<view> action, then you need to
+ensure that you have an exported action, as described in
+L<StandardTemplates.pod>:
+
+    sub my_view :Exported { }
+
+=head3 Template Switcheroo
+
+An action doesn't have any data of its own to display, but needs to display
+B<something>.
+
+B<Solution>: This is an B<extremely> common hack. You've just issued an
+action like C<beer/do_edit>, which updates the database. You don't want
+to display a page that says "Record updated" or similar. Lesser
+application servers would issue a redirect to have the browser request
+C</beer/view/I<id>> instead, but we can actually modify the Maypole
+request on the fly and, after doing the update, pretend that we were
+going to C</beer/view/I<id>> all along. We do this by setting the
+objects in the C<objects> slot and changing the C<template> to the
+one we wanted to go to.
+
+In this example from L<Flox.pod>, we've just performed an C<accept>
+method on a C<Flox::Invitation> object and we want to go back to viewing
+a user's page.
+
+    sub accept :Exported {
+        my ($self, $r) = @_;
+        my $invitation = $r->objects->[0];
+        # [... do stuff to $invitation ...]
+        $r->{objects} = [$r->{user}];
+        $r->{model_class} = "Flox::User";
+        $r->{template} = "view";
+    }
+
+This hack is so common that it's expected that there'll be a neater
+way of doing this in the future.
+
+=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, a Word document, 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->{content_type} = $user->photo_type;
+        $r->{output} = $user->photo;
+    }
+
+Of course, the file doesn't necessarily need to be in the database
+itself; if your file is stored in the filesystem, but you have a file
+name or some other pointer in the database, you can still arrange for
+the data to be fetched and inserted into C<$r-E<gt>{output}>.
+
+=head3 REST
+
+You want to provide a programmatic interface to your Maypole site.
+
+B<Solution>: The best way to do this is with C<REST>, which uses a
+descriptive URL to encode the request. For instance, in L<Flox.pod> we
+describe a social networking system. One neat thing you can do with
+social networks is to use them for reputation tracking, and we can use
+that information for spam detection. So if a message arrives from
+C<person@someco.com>, we want to know if they're in our network of
+friends or not and mark the message appropriately. We'll do this by
+having a web agent (say, L<WWW::Mechanize> or L<LWP::UserAgent>) request
+a URL of the form
+C<http://flox.simon-cozens.org/user/relationship_by_email/person%40someco.com>.
+Naturally, they'll need to present the appropriate cookie just like a
+normal browser, but that's a solved problem. We're just interested in
+the REST request.
+
+The request will return a single integer status code: 0 if they're not
+in the system at all, 1 if they're in the system, and 2 if they're our
+friend.
+
+All we need to do to implement this is provide the C<relationship_by_email>
+action, and use it to fill in the output in the same way as we did when
+displaying a picture. Since C<person%40someco.com> is not the ID of a
+row in the user table, it will appear in the C<args> array:
+
+    use URI::Escape;
+    sub relationship_by_email :Exported {
+        my ($self, $r) = @_;
+        my $email = uri_unescape($r->{args}[0]);
+        $r->{content_type} = "text/plain";
+        my $user;
+        unless (($user) = Flox::User->search(email => $email)) {
+            $r->{content} = "0\n"; return;
+        }
+
+        if ($r->{user}->is_friend($user)) { $r->{content} = "2\n"; return; };
+        $r->{content} = "1\n"; return;
+    }
+
+=head3 Component-based Pages
+
+You're designing something like a portal site which has a number of
+components, all displaying different bits of information about different
+objects. You want to include the output of one Maypole request call while
+building up another. 
+
+B<Solution>: Use C<Maypole::Component>. By inheriting from this, you can
+call the C<component> method on the Maypole request object to make a 
+"sub-request". For instance, if you have a template
+
+    <DIV class="latestnews">
+    [% request.component("/news/latest_comp") %]
+    </DIV>
+
+    <DIV class="links">
+    [% request.component("/links/list_comp") %]
+    </DIV>
+
+then the results of calling the C</news/latest_comp> action and template
+will be inserted in the C<latestnews> DIV, and the results of calling
+C</links/list_comp> will be placed in the C<links> DIV. Naturally, you're
+responsible for exporting actions and creating templates which return 
+fragments of HTML suitable for inserting into the appropriate locations.
+
+Alternatively, if you've already got all the objects you need, you can
+probably just C<[% PROCESS %]> the templates directly.
+
+=head3 Bailing out with an error
+
+Maypole's error handling sucks. Something really bad has happened to the
+current request, and you want to stop processing now and tell the user about
+it.
+
+B<Solution>: Maypole's error handling sucks because you haven't written it
+yet. Maypole doesn't know what you want to do with an error, so it doesn't
+guess. One common thing to do is to display a template with an error message
+in it somewhere.
+
+Put this in your driver class:
+
+    sub error { 
+        my ($r, $message) = @_;
+        $r->{template} = "error";
+        $r->{template_args}{error} = $message;
+        return OK;
+    }
+
+And then have a F<custom/error> template like so:
+
+    [% PROCESS header %]
+    <H2> There was some kind of error... </H2>
+    <P>
+    I'm sorry, something went so badly wrong, we couldn't recover. This
+    may help:
+    </P>
+    <DIV CLASS="messages"> [% error %] </DIV>
+
+Now in your actions you can say things like this:
+
+    if (1 == 0) { return $r->error("Sky fell!") }
+
+This essentially uses the template switcheroo hack to always display the
+error template, while populating the template with an C<error> parameter.
+Since you C<return $r-E<gt>error>, this will terminate the processing
+of the current action.
+
+The really, really neat thing about this hack is that since C<error>
+returns C<OK>, you can even use it in your C<authenticate> routine:
+
+    sub authenticate {
+        my ($self, $r) = @_;
+        $r->get_user;
+        return $r->error("You do not exist. Go away.")
+            if $r->{user} and $r->{user}->status ne "real";
+        ...
+    }
+
+This will bail out processing the authentication, the model class, and
+everything, and just skip to displaying the error message. 
+
+Non-showstopper errors or other notifications are best handled by tacking a
+C<messages> template variable onto the request:
+
+    if ((localtime)[6] == 1) {
+        push @{$r->{template_args}{messages}}, "Warning: Today is Monday";
+    }
+
+Now F<custom/messages> can contain:
+
+    [% IF messages %]
+    <DIV class="messages">
+    <UL>
+        [% FOR message = messages %]
+           <LI> [% message %] </LI>
+        [% END %]
+    </UL>
+    </DIV>
+    [% END %]
+
+And you can display messages to your user by adding C<PROCESS messages> at an
+appropriate point in your template; you may also want to use a template
+switcheroo to ensure that you're displaying a page that has the messages box in
+it.
+
+=head2 Authentication hacks
+
+The next series of hacks deals with providing the concept of a "user" for
+a site, and what you do with one when you've got one.
+
+=head3 Logging In
+
+You need the concept of a "current user".
+
+B<Solution>: Use something like
+C<Maypole::Authentication::UserSessionCookie> to authenticate a user
+against a user class and store a current user object in the request
+object.
+
+C<UserSessionCookie> provides the C<get_user> method which tries to get
+a user object, either based on the cookie for an already authenticated
+session, or by comparing C<username> and C<password> form parameters
+against a C<user> table in the database. Its behaviour is highly
+customizable, so see the documentation, or the authentication paper at
+C<http://maypole.simon-cozens.org/docs/authentication.html> for examples.
+
+=head3 Pass-through login
+
+You want to intercept a request from a non-logged-in user and have
+them log in before sending them on their way to wherever they were
+originally going.
+
+B<Solution>:
+
+    sub authenticate {
+        my ($self, $r) = @_;
+        $r->get_user;
+        return OK if $r->{user};
+        # Force them to the login page.
+        $r->{template} = "login";
+        return OK;
+    }
+
+This will display the C<login> template, which should look something
+like this:
+
+    [% INCLUDE header %]
+
+      <h2> You need to log in </h2>
+
+    <DIV class="login">
+    [% IF login_error %]
+       <FONT COLOR="#FF0000"> [% login_error %] </FONT>
+    [% END %]
+      <FORM ACTION="/[% request.path%]" METHOD="post">
+    Username: 
+        <INPUT TYPE="text" NAME="[% config.auth.user_field || "user" %]"> <BR>
+    Password: <INPUT TYPE="password" NAME="password"> <BR>
+    <INPUT TYPE="submit">
+    </FORM>
+    </DIV>
+
+Notice that this request gets C<POST>ed back to wherever it came from, using
+C<request.path>. This is because if the user submits correct credentials,
+C<get_user> will now return a valid user object, and the request will pass
+through unhindered to the original URL.
+
+=head3 Logging Out
+
+Now your users are logged in, you want a way of having them log out
+again and taking the authentication cookie away from them, sending
+them back to the front page as an unprivileged user.
+
+B<Solution>: This action, on the user class, is probably overkill, but
+it does the job:
+
+    sub logout :Exported {
+        my ($class, $r) = @_;
+        # Remove the user from the request object
+        my $user = delete $r->{user};
+        # Destroy the session
+        tied(%{$r->{session}})->delete;
+        # Send a new cookie which expires the previous one
+        my $cookie = Apache::Cookie->new($r->{ar},
+            -name => $r->config->{auth}{cookie_name},
+            -value => undef,
+            -path => "/"
+            -expires => "-10m"
+        );
+        $cookie->bake();
+        # Template switcheroo
+        $r->template("frontpage");
+    }
+
+=head3 Multi-level Authentication
+
+You have both a global site access policy (for instance, requiring a
+user to be logged in except for certain pages) and a policy for
+particular tables. (Only allowing an admin to delete records in some
+tables, say, or not wanting people to get at the default set of methods
+provided by the model class.) 
+
+You don't know whether to override the global C<authenticate> method or
+provide one for each class.
+
+B<Solution>: Do both. Have a global C<authenticate> method which calls 
+a C<sub_authenticate> method based on the class:
+
+    sub authenticate {
+        ...
+        if ($r->{user}) {
+            return $r->model_class->sub_authenticate($r)
+                if $r->model_class->can("sub_authenticate");
+            return OK;
+        }
+        ...
+    }
+
+And now your C<sub_authenticate> methods can specify the policy for
+each table:
+
+    sub sub_authenticate { # Ensure we can only create, reject or accept
+        my ($self, $r) = @_;
+        return OK if $r->{action} =~ /^(issue|accept|reject|do_edit)$/;
+        return;
+    }
+
+=head2 Creating and editing hacks
+
+These hacks particularly deal with issues related to the C<do_edit>
+built-in action.
+
+=head3 Limiting data for display
+
+You want the user to be able to type in some text that you're later
+going to display on the site, but you don't want them to stick images in
+it, launch cross-site scripting attacks or otherwise insert messy HTML.
+
+B<Solution>: Use the C<CGI::Untaint::html> module to sanitize the HTML
+on input. C<CGI::Untaint::html> uses C<HTML::Sanitizer> to ensure that
+tags are properly closed and can restrict the use of certain tags and
+attributes to a pre-defined list.
+
+Simply replace:
+
+    App::Table->untaint_columns(
+        text      => [qw/name description/]
+    );
+
+with:
+
+    App::Table->untaint_columns(
+        html      => [qw/name description/]
+    );
+
+And incoming HTML will be checked and cleaned before it is written to
+the database.
+
+=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.
+
+=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.
+
+B<Solution>: It's messy.
+
+First, we set up an upload form, in an ordinary dummy action. Here's
+the action:
+
+    sub upload_picture : Exported {}
+
+And here's the template:
+
+    <FORM action="/user/do_upload" enctype="multipart/form-data" method="POST">
+
+    <P> Please provide a picture in JPEG, PNG or GIF format:
+    </P>
+    <INPUT TYPE="file" NAME="picture">
+    <BR>
+    <INPUT TYPE="submit">
+    </FORM>
+
+(Although you'll probably want a bit more HTML around it than that.)
+
+Now we need to write the C<do_upload> action. At this point we have to get a
+little friendly with the front-end system. If we're using C<Apache::Request>,
+then the C<upload> method of the C<Apache::Request> object (which
+C<Apache::MVC> helpfully stores in C<$r-E<gt>{ar}>) will work for us:
+
+    sub do_upload :Exported {
+        my ($class, $r) = @_;
+        my $user = $r->{user};
+        my $upload = $r->{ar}->upload("picture");
+
+This returns a C<Apache::Upload> object, which we can query for its
+content type and a file handle from which we can read the data. It's
+also worth checking the image isn't going to be too massive before we
+try reading it and running out of memory, and that the content type is
+something we're prepared to deal with. 
+
+    if ($upload) {
+        my $ct = $upload->info("Content-type");
+        return $r->error("Unknown image file type $ct")
+            if $ct !~ m{image/(jpeg|gif|png)};
+        return $r->error("File too big! Maximum size is ".MAX_IMAGE_SIZE)
+            if $upload->size > MAX_IMAGE_SIZE;
+
+        my $fh = $upload->fh;
+        my $image = do { local $/; <$fh> };
+
+Now we can store the content type and data into our database, store it
+into a file, or whatever:
+
+        $r->{user}->photo_type($ct);
+        $r->{user}->photo($image);
+    }
+
+And finally, we use our familiar template switcheroo hack to get back to
+a useful page:
+
+        $r->objects([ $user ]);
+        $r->{template} = "view";
+    }
+
+Now, as we've mentioned, this only works because we're getting familiar with
+C<Apache::Request> and its C<Apache::Upload> objects. If we're planning to use
+C<CGI::Maypole> instead, or want to write our application in a generic way so
+that it'll work regardless of front-end, then we need to replace the C<upload>
+call with an equivalent which uses the C<CGI> module to get the upload data.
+This is convoluted and horrific and we're not going to show it here, but it's
+possible.
+
+Combine with the "Displaying pictures" hack above for a happy time.
diff --git a/lib/Maypole/Manual/StandardTemplates.pod b/lib/Maypole/Manual/StandardTemplates.pod
new file mode 100644 (file)
index 0000000..e5eb9f0
--- /dev/null
@@ -0,0 +1,288 @@
+
+=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
diff --git a/lib/Maypole/Manual/View.pod b/lib/Maypole/Manual/View.pod
new file mode 100644 (file)
index 0000000..c469100
--- /dev/null
@@ -0,0 +1,510 @@
+=head1 Maypole View Classes
+
+In a large application, you will almost certainly want to customize the
+layout and design of the output pages. This task may even be the purview
+of a separate team of HTML designers rather than the programmers. Since
+a typical programmer will try to avoid touching HTML as much as possible
+and a typical designer will try to avoid touching Perl code, programmers
+have evolved a system of templating to separate the concerns of
+programming and designing. 
+
+One of the core concepts in Maypole is the I<view class>, and this is
+responsible for routing the data produced in the model class into the
+templates produced by the designers. Of course, there are a great many
+possible templating systems and styles, and so there can be a great many
+possible Maypole view classes. Each view class will take the data from
+the controller, locate a template to be processed, and hand the whole
+lot to its preferred templating module, which will then do the hard work
+of filling in the template and coming up with the output.
+
+You can choose whatever Maypole view class you want, but the default
+view class is C<Maypole::View::TT>, and it feeds its data and templates
+to a module called the Template Toolkit.
+
+=head2 The Template Toolkit
+
+The Template Toolkit, written by Andy Wardley, is a very powerful and
+generic templating system. It provides its own little formatting language
+which supports loops, conditionals, hash and array dereferences and
+method calls, macro processing and a plug-in system to connect it to
+external Perl modules. There are several good introductions to the
+Template Toolkit available: you should have one installed as
+L<Template::Tutorial::Datafile>; there's one at
+L<http://www.perl.com/pub/a/2003/07/15/nocode.html>, and of course
+there's the "Badger Book" - I<The Perl Template Toolkit>, by Andy et al.
+
+We'll present a brief introduction here by deconstructing some of the 
+templates used by Maypole applications. For more deconstruction, see
+L<StandardTemplates.pod>, which is an entire chapter dealing with the
+factory supplied templates.
+
+Here's the template which is called for the front page of the standard
+beer database application, C<custom/frontpage>.
+
+    [% INCLUDE header %]
+
+    <h2> The beer database </h2>
+
+    <TABLE BORDER="0" ALIGN="center" WIDTH="70%">
+    [% FOR table = config.display_tables %]
+    <TR>
+    <TD>
+    <A HREF="[%table%]/list">List by [%table %]</A>
+    </TD>
+    </TR>
+    [% END %]
+    </TABLE>
+
+The first thing to note about this is that everything outside of the
+Template Toolkit tags (C<[%> and C<%]>) is output verbatim. That is,
+you're guaranteed to see 
+
+    <h2> The beer database </h2>
+
+    <TABLE BORDER="0" ALIGN="center" WIDTH="70%">
+
+in the output somewhere. Inside the tags, magic happens. The first piece
+of magic is the C<[% INCLUDE header %]> directive. This goes away and
+finds a file called F<header> - don't worry about how it finds that yet,
+we'll come to that later on - and processes the file's contents as
+though they were right there in the template. Our F<header> file happens
+not to contain any C<[% %]> tags, but if it did, they would be processed
+in the same way as the ones in F<frontpage>. 
+
+The next piece of magic is this line:
+
+    [% FOR table = config.display_tables %]
+
+We're seeing a lot of things here at once. C<config> is where we should
+start looking. This is a template variable, which is what templates are
+all about - templating means getting data from somewhere outside and
+presenting it to the user in a useful way, and the C<config> hash is a
+prime example of data that we want to use. It's actually the hash of
+configuration parameters for this Maypole application, and one of the
+keys in that hash is C<display_tables>, the database tables that we're
+allowed to play with. In the application, we probably said something
+like
+
+    BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
+
+This stores the four values - C<beer>, C<brewery>, C<pub> and C<style> -
+in an array, which is placed in the config hash under the key
+C<display_tables>. Now we're getting them back again.
+
+The Template Toolkit's dot operator is a sort of do-the-right-thing
+operator; we can say C<array.0> to get the first element of an array,
+C<hash.key> to look up the C<key> key in a hash, and C<object.method> to
+call C<method> on an object. So, for instance, if we said
+C<config.display_tables.2>, we'd look up the C<display_tables> key in
+the configuration hash and get our array back, then look up the 2nd
+element and get C<pub>.
+
+The C<FOR> loop will repeat the code four times, setting our new
+variable C<table> to the appropriate array element. This code:
+
+    [% FOR table = config.display_tables %]
+        Hello [% table %]!
+    [% END %]
+
+will produce something like
+
+    Hello beer!
+    Hello brewery!
+    Hello pub!
+    Hello style!
+
+In our case, though, we're printing out a table element linking to each
+database table in turn.
+
+Here's a slightly more complicated example, adapted from F<factory/pager>.
+This template is responsible for printing the little page menu at the
+bottom of a listing if there are more rows in the listing than we want
+on a single page.
+
+    [% PROCESS macros %]
+    <P ALIGN="center">Pages:
+    [%
+         FOREACH num = [pager.first_page .. pager.last_page];
+              IF num == pager.current_page;
+                "["; num; "] ";
+              ELSE;
+                SET args = "?page=" _ num;
+                SET label = "[" _ num _ "]";
+                link(classmetadata.moniker, "list", args, label);
+              END;
+         END;
+    %]
+    </P>
+
+Maypole will be providing a whole bunch of variables to this template,
+and we'll look at them all in a moment, but the only ones we need to care
+about are C<pager> and C<classmetadata>. 
+
+We start by loading in a bunch of macros. Macros are Template Toolkit's
+functions - you can provide them some parameters and they'll run a little
+sub-template based on them. The C<macros> file contains some handy macros
+that I've found useful for constructing Maypole templates; again, these
+will be covered in full detail in L<StandardTemplates.pod>.
+
+We're going to be displaying something like this:
+
+    Pages: [1] [2] [3] [4]
+
+with most of those numbers being a link to the appropriate page. This
+mean we're going to have to have a list of numbers, and the C<FOREACH> loop
+provides this: (C<FOREACH> and C<FOR> are identical, just like in Perl.)
+
+         FOREACH num = [pager.first_page .. pager.last_page];
+
+Here we're manually constructing an array of numbers, using the range
+operator (C<..>) to fill in all the numbers from the C<first_page> (1)
+to the C<last_page> (4). The same dot operator is used to ask the C<pager>
+what its C<first_page> and C<last_page> is. Remember when we said 
+C<config.display_tables>, we were looking up the C<display_tables> key
+in the C<config> hash? Well, this time we're not looking anything up in
+a hash. C<pager> is an object, and C<first_page> is a method. Thing is,
+you don't have to care. You can pretend it's a hash if you want. The
+syntax is the same, and Template Toolkit knows the right thing to do.
+
+Now we're going to be executing this loop four times, once each for C<num>
+being set to 1, 2, 3, and 4. At some point, we'll come across the page
+that we're actually on right now:
+
+      IF num == pager.current_page;
+
+and in that case, we don't want to produce a link to it. We just want
+to output it as text, surrounded by square brackets:
+
+                "["; num; "] ";
+
+We're using string literals to output the brackets. We don't have to
+do that. We could say it this way:
+
+    [% ...
+      IF num == pager.current_page;
+    %]
+        [ [% num %] ] 
+    [% ELSE %]
+       ...
+    [% END %]
+
+But you know, I quite like it my way.
+
+Now if the number we're printing isn't the number of the current page,
+we want to make a link. Here's how we do it:
+
+    SET args = "?page=" _ num;
+    SET label = "[" _ num _ "]";
+    link(classmetadata.table, "list", args, label);
+
+C<SET> declares a new variable of our own. If there was anything called
+C<args> before, there isn't now. It's going to be the result of our
+statement C<"?page=" _ num>. C<_> is the concatenation operator, and
+glues C<?page=> onto the front of our number. So if we want to link to
+page 4, then the C<args> variable will contain C<?page=4>. Similarly,
+the C<label> variable will be C<[4]>.
+
+Now we call a macro, C<link> with these two variables and the value of
+C<classmetadata.table>. This macro takes four arguments, C<table>, 
+C<action>, C<args> and C<label>, and constructs a link of the form
+
+    <A HREF="[% config.base_url %]/[% table %]/[% action %][% args %]">
+    [% label %]
+    </A>
+
+In our case, it'll be filled in like so:
+
+    <A HREF="[% config.base_url %]/[% classmetadata.table %]/list?page=4">
+    [ 4 ]
+    </A>
+
+Where C<classmetadata.table> will actually be the name of the current
+table, and C<config.base_url> will be replaced by the appropriate URL for
+this application.
+
+=head2 Locating Templates
+
+Another feature of C<Maypole::View::TT> which may not be present in
+alternate view class implementations - although they are strongly
+encouraged to provide it - is the way that templates are located.
+(Remember, I B<did> say I'd tell you about that later.) Template Toolkit
+allows whatever uses it to provide a path for template files to be
+located in. C<Maypole::View::TT> feeds it up to three possible
+directories to look things up in, and it will try to find a template in
+each of these in turn.
+
+When you configure a Maypole application, you can tell it the base
+directory of your templates like so:
+
+    BeerDB->config->{template_root} = "/var/www/beerdb/templates";
+
+If you don't do this, most Maypole front-ends will use the current
+directory, which is generally what you want anyway. Off this directory,
+Maypole will look for a set of subdirectories.
+
+For instance, I said we were in the middle of processing the front page
+and looking up a template file called F<header>. Maypole will first look
+for this file in the F<custom> subdirectory. (say,
+F</var/www/beerdb/templates/custom>) If it doesn't find one, then it
+looks in the F<factory> subdirectory. If it doesn't find one there, then
+it gives up and dies with an error. But that's your fault, since you've
+called for a template which doesn't exist. Don't do that. 
+
+This behaviour means that you can provide your own site-specific
+templates, but if you don't do so, then you get to use a generic one
+provided by Maypole. Maypole's "factory setting" templates are written
+in such a way as to try and do the right thing no matter what your
+application does. They are occasionally successful at this. 
+
+Now the front page was a pretty simple example, since Maypole only looks
+up two directories. In most cases, it checks an additional directory,
+and this directory depends entirely on what Maypole is doing.
+
+If you're writing an e-commerce application, for example, you may well
+have a table which represents the product catalogue and all the products
+you can buy. Let's call this the C<product> table. You'll also have a
+data source which is specific to the user which contains all the
+products that they're buying on this particular visit to the site. In
+time-honoured tradition, we'll call this the C<basket> table.
+
+Now it ought to be reasonably apparent that you don't want the basket
+to be displayed in exactly the same way as the product catalogue. The
+templates for C<product/list> and C<basket/list> need to be different.
+This is where the third directory comes in. The other directory, which
+Maypole checks very first of all, is specific to the table that you're
+viewing. So if you go to C<http://your.shop.com/basket/list>, Maypole
+will look in the F<basket> directory first for a file called F<list>,
+and second in the F<custom> directory for a site-wide list template,
+and then fall-back to the F<factory> directory for a generic list
+template. It should be obvious that you probably want to provide all
+of F<basket/list>, F<basket/view>, F<product/list>, F<product/view>
+and any other combination of classes and actions that you can think of.
+
+=head2 What Maypole provides to a template
+
+C<Maypole::View::TT> provides quite a variety of template variables to
+the template. As these are the building blocks of your pages, it's worth
+looking at precisely what variables are available.
+
+The most important variable is called C<objects>, and is a list of all
+the objects that this page is going to deal with. For instance,
+in the template F</beer/view>, C<objects> will contain the C<BeerDB::Beer>
+object for the 23rd item in the database, while F</brewery/list> will
+fill C<objects> will all the breweries; or at least, all the breweries
+on the current page.
+
+This variable is so important that to help design templates with it,
+C<Maypole::View::TT> provides a helpful alias to it depending on
+context. For instance, if you're writing your own F</brewery/list>
+template, the data in C<objects> is also available in a template
+variable called C<breweries>. If you're working on F</brewery/view>,
+though, it's available in C<brewery>, since there's only one brewery to
+be displayed.
+
+Additionally, you can get the base URL for the application from the
+C<base> template variable; this allows you to construct links, as we
+saw earlier:
+
+    <A HREF="[% base %]/brewery/edit/[% brewery.id %]">Edit this brewery</A>
+
+You can also get at the rest of the configuration for the site with the
+C<config> variable as we saw above, and the entire request object in 
+C<request>, should you really need to poke at it. (I've only found this
+useful when working with authentication modules which stash a current user
+object in C<request.user>.)
+
+To allow the construction of the "generic" templates which live in
+F<factory>, Maypole also passes in a hash called C<classmetadata>,
+which contains all sorts of useful information about the class under
+examination:
+
+=over 3
+
+=item C<table>
+
+This is the name of the table that is represented by the class.
+
+=item C<class>
+
+This is the Perl's idea of the class; you don't need this unless you're
+doing really tricky things.
+
+=item C<moniker>
+
+This is a more human-readable version of the table name, that can be
+used for display.
+
+=item C<plural>
+
+The same, but a correctly-formed plural. For instance, "breweries".
+
+=item C<columns>
+
+The list of columns for display; see the section "Customizing Generic
+CRUD Applications" in L<StandardTemplates.pod>.
+
+=item C<colnames>
+
+This is a hash mapping the database's name for a column to a more
+human-readable name. Again, see "Customizing Generic CRUD Applications>.
+
+=item C<cgi>
+
+This is a slightly trickier one. It is a hash mapping column names to
+a C<HTML::Element> suitable for entering data into a new instance of
+that class. That is, for the C<beer> table, C<classmetadata.cgi.style>
+should be a C<HTML::Element> object containing a drop-down list of
+beer styles. This is explained in L<StandardTemplates.pod>.
+
+=item C<description>
+
+This is the human-readable description provided by a class.
+
+=item C<related_accessors>
+
+This is a list of accessors which can be called on an object to get
+lists of other things that this object "has". For instance, on a
+brewery, it would return C<beers>, since calling C<brewery.beers> would
+give you a list of beers produced by the brewery. Note that this only
+caters for accessors defining one-to-many relationships, not the
+ordinary one-to-one relationships, such as C<style>.
+
+=back
+
+=head2 Other view classes
+
+Please note that these template variables, C<config>, C<classmetadata>,
+C<objects> and its user-friendly alias, as well as the rest of them are
+a function of one particular view class, the default
+C<Maypole::View::TT> class. Other view classes may need to present an
+entirely different set of template variables, since the default ones
+might not make sense. The templates may look wildly different in other
+view class implementations. But that's OK, because you couldn't
+necessarily use the same templates with a different templating system
+anyway.
+
+For instance, in really dumb templating languages which can't handle
+dereferencing hashes or arrays - no wait, that's most of them - passing
+in a hash reference like C<classmetadata> won't help you since you can't
+get at any of its elements. So you'll need to take a look at the
+documentation for the appropriate view class to see what template
+variables it provides.
+
+So if, for some perverse reason, the Template Toolkit just isn't good
+enough for you, then you can set your own view class while configuring
+your application:
+
+   package BeerDB;
+   use base 'Apache::MVC';
+   ...
+   BeerDB->setup("dbi:SQLite:t/beerdb.db");
+   BeerDB->config->{uri_base} = "http://localhost/beerdb/";
+   BeerDB->config->{rows_per_page} = 10;
+   BeerDB->config->{view} = "Maypole::View::Mason"; 
+
+Where do these alternate view classes come from? Gentle reader, they
+come from B<you>.
+
+=head2 Building your own view class
+
+I<You should probably skip this section for the first few readings of this manual. It's only intended for people extending Maypole.>
+
+Imagine you've found a brand new templating system that's B<much better>
+than the Template Toolkit. I know I'm stretching your imagination a bit
+here, but try. You'd like to use it with Maypole, which means writing your
+own view class. How is it done?
+
+We'll demonstrate by implementing a view class for C<HTML::Mason>,
+although no value judgement is implied. C<HTML::Mason> is a templating
+system which embeds pure Perl code inside its magic tags. The good side
+of this is that it can get into hash references and objects, and so
+providing C<classmetadata>, C<config> and the Maypole request object
+will work out just fine. The down side is that C<HTML::Mason> is used to
+running more or less standalone, and having all the template variables
+it wants already at its disposal through CGI parameters and the like, so
+we have to fiddle a bit to get these variables into our template.
+
+The key to building view classes is C<Maypole::View::Base>. This is the
+base class that you're going to inherit from and, to be honest, it does
+pretty much everything you need. It provides a method called C<vars>
+which returns a hash of all the template variables described above, so
+it would be good to feed those into C<HTML::Mason>. It also provides a
+C<paths> method which turns returns the full filesystem path of the
+three possible template paths as shown above. Again, it would be good to
+use this as our component paths if we can. It also has some methods we
+can override if we want to, but they're not massively important, so you
+can see L<Maypole::View::Base> for more about them. 
+
+The module will do the right thing for us if we agree to provide a
+method called C<template>. This is responsible for taking the Maypole
+request object (of which more later) and putting the appropriate output
+either into C<$r-E<gt>{output}> or C<$r-E<gt>{error}>, depending, of
+course, whether things are OK or whether we got an error.
+
+Thankfully, C<HTML::Mason> makes things really easy for us. We B<can>
+use multiple template roots, so we can use the C<paths> method; we
+B<can> pass in a hash full of interesting data structures, so we can use
+the C<vars> method too. In fact, we have to do very little to make
+C<Maypole::View::Mason> work. Which is somewhat annoying, because it
+makes a boring example. But it means I can leave the fun ones to you!
+
+The doing-the-templating, in Mason and in any templating system, depends on
+three things: the paths that we're going to use to find our templates, the
+template name that we've been asked to fill out, and the set of variables that
+are going to be fed to the template. We'll assemble these for reference:
+
+    sub template {
+        my ($self, $r) = @_;
+        my @paths = $self->paths($r);
+        my $template = $r->template;
+        my %vars = $self->args($r);
+
+We'll also declare somewhere to temporarily store the output:
+
+        my $output;
+
+Now comes the part where we have to actually do something
+templating-language specific, so we open up our copy of "Embedding Perl
+in HTML with Mason" and find the bit where it talks about running Mason
+standalone. We find that the first thing we need to do is create a
+C<HTML::Mason::Interp> object which knows about the component roots.
+There's a slight subtlety in that the component roots have to be
+specified as an array of arrays, with each array being a two-element
+list of label and path, like so:
+
+    comproot => [
+        [ class   => "/var/www/beerdb/templates/brewery" ],
+        [ custom  => "/var/www/beerdb/templates/custom" ],
+        [ factory => "/var/www/beerdb/templates/factory" ],
+    ]
+
+We also find that we can set the output method here to capture Mason's
+output into a scalar, and also that we can tell Mason to generate
+sensible error messages itself, which saves us from having to worry
+about catching errors. At the end of all this, we come up with a
+constructor for our C<HTML::Mason::Interp> object which looks like this:
+
+    my $label = "path0";
+    my $mason = HTML::Mason::Interp->new(
+        comproot => [ map { [ $label++ => $_ ] } @paths ],
+        output_method => \$output,
+        error_mode => "output" 
+    );
+
+The next thing we need to do is run the template with the appropriate
+template variables. This turns out to be really easy:
+
+    $mason->exec($template, %vars);
+
+Now we've got the data in C<$output>, we can put it into the request object,
+and return a true value to indicate that we processed everything OK. (If there
+was an error, then Mason will have produced some suitable output, so we can
+pretend that everything's OK anyway.)
+
+    $r->{output} = $output;
+    return 1;
+
+And that's all we need to do. Barely twenty lines of code for the finished
+product. Wasn't that easy? Don't you feel inspired to write Maypole view
+classes for your favourite templating language? Well, don't let me stop you!
+Patches are always welcome!