]> git.decadent.org.uk Git - maypole.git/blobdiff - doc/Model.pod
Win32 support
[maypole.git] / doc / Model.pod
index c5f5b18ec9a3db77fd09d8742899433967887750..bc54ffdb8105ef81a9e57e260c820816fbb445f1 100644 (file)
@@ -4,8 +4,106 @@
 
 =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