=head1 Overview of Gantry This document explains Gantry from a high level. But it starts by explaining how to install the framework and the sample apps which do the most to help you use it. =head1 Prerequisites To use this framework, you need Apache and mod_perl. You may choose either version 1.x or version 2.x for these (but obviously the versions must match). For instructions on how to complete these installations, consult: http://perl.apache.org/docs/1.0/guide/install.html or http://perl.apache.org/docs/2.0/user/install/install.html Following their instructions will ensure that you have the most accurate information. =head1 Installation This project has two distinct parts: the framework and the sample apps. These are developed and distributed separately. The framework and each sample app is a regular Perl distibution like you would find on CPAN (though they may be bundled together). They use Module::Build instead of ExtUtils::MakeMaker. This means that the procedure for installation (after you untar the distribution) is: perl Build.pl ./Build ./Build test ./Build install You need to do this for the framework itself and again for each sample app you want to deploy. =head1 Configuration Once you have installed the framework and a sample app, you need to configure the app. This amounts to including a few directives in your httpd.conf. You can just add this to you system httpd.conf or to a virtual host within it: Include /path/to/Billing/docs/httpd.conf See that file for clues about configuration, details follow later in this doc. To run the billing sample app, you must also set up a database for it. To create the database, use billing.sql in the docs directory of the distibution. Choose any name you like for the database, but change the PerlSetVars in your httpd.conf appropriately (look for the ones that start with db). In order for the apps to serve images and style sheets, you need to copy the css and images directories into your document root and set the PerlSetVars for css_root and img_root to point to the Apache serveable directory where you put them. =head1 A Sample App (or two) There are three sample apps that come in one bundle. You must install them separately. They are: =over 4 =item Billing A private contractor billing system. It keeps track of who you work for, what you did for them, and the invoices you sent to them. The invoices can be viewed as PDFs for printing, but are also stored in the database. =item Dochive A small CMS for storing journal articles. =item KrKit A tiny app to convert uploaded files from one format to another. =back =head1 How It Works Now that you have installed the framework and the sample apps, let's see how the pieces work together to server your users. Consider a typical request to the Billing sample application. The user enters an address (or clicks on a link to it): http://somehost/billing/companies/something/param1/param2 Apache handles the initial dispatch through a C directive like this one from the billing app's httpd.conf: SetHandler perl-script PerlHandler Apps::Billing::Companies The C inherits from C, which in turn inherits from C. The only handler you should ever need is in the C. (Though you could override it, we never have). The handler is a template method, meaning that it performs a standard outline of steps calling particular methods of your subclass as it needs specific help or information. Typically this sequence is init do_something clean_up In init, you typically do two things: fish PerlSetVars out of the request object through its dir_config method and setup your database access. We usually have two inits for the entire app, see init in Billing.pm and Gantry.pm for example. Grouping all of an apps configuration parameters makes them easier to find, since they all live in the same Location directive in the conf file. Further, for those reading the code, they are all in only one or two places, again making them easier to find. In cleanup, you release any resources you need to. But, note that Class::DBI based modules handle the database connection pools for you, so you don't usually need to put database disconnects in cleanup. We usually have a single cleanup for the entire app, see Billing.pm for example. All of the action methods begin with do_. What comes after that is taken directly from the URL. In the do_ method, you perform whatever action you need to for the page the user requested. This includes populating the view data portion of the site object ($site). That view data goes to the template. In reality, the handler is a bit more complex. But you can think of it like it is shown above until you care to adjust its behavior. The main mystery is, "How does it make output?" The short answer is, it calls do_process (after the steps shown above). That method is supplied by the template engine of your choice (ours is TT). When you use C, you do it like so (this is taken from Billing.pm): use Gantry qw/-Engine=MP20 -TemplateEngine=TT/; The Engine here is mod_perl 2.0. The TemplateEngine is Template Toolkit. =head2 Principles There are many principles we used in developing this framework. See principles.pod. =head1 Engines A typical use statement for Gantry looks like this: use Gantry qw/-Engine=MP20 -TemplateEngine=TT/; The framework handles Engine and TemplateEngine options specially. See below for how it handles TemplateEngine options. Engines must be in the Gantry::Engine namespace. The engine is responsible for exporting the following methods (yes, I said exporting and methods): =over 4 =item apache_request Must convert the value in $$site{r} to an apache request object. $$site{r} is the second parameter to the handler when it is called as a method. =item apache_param_hash Receives the apache request object and returns a hash of the form parameters in it. =item err_header_out Like header_out, but for errors (see below). =item header_in Receives the name of a request header. Must return the value in that header. Useful for retrieving cookies. =item header_out Receives a key/value pair for one header. Must store the header so that when output is later generated, it will be sent. =item remote_ip Receives the request object and returns the ip address of the client. =item send_http_header Must ensure that any headers previously store via header_out and err_header_out are sent. (Not all engines need to do anything for this. For example, mod_perl 2 sends headers during the first print.) =item status Receives a status string and returns the corresponding constant which the apache server understands. The possible status strings are: DECLINED OK REDIRECT FORBIDDEN SERVER_ERROR HTTP_BAD_REQUEST HTTP_UNAUTHORIZED =back =head1 Template Engines Template engines handle the view part of MVC processing. Typically, you don't have to write any code for them, you can just use one included in the distribution. But, should you want to use Mason or some other templating system, you will have to write a template engine. These must live in the Mutant::KrKit::Template namespace. A template engine must export the following methods: =over 4 =item do_action This is the actual dispatcher which calls the do_* methods of the modules you write. While most do_methods merely store their data in the site object for later retrieval in the template, some return their output instead. This method is responsible for storin such returned data in the site object stash. =item do_error Makes sure that errors are correctly logged. Note that this does not affect what the user sees, only what is logged. =item do_process Receives the site object and must produce output directed to the requrest object. (It must NOT send headers. They are handled prior to calling do_process). =back =head1 Plugins In addition to loading an engine and a template engine, use Gantry can also load any other plugins you request. All plugins must live in the Gantry::Plugins namespace. Plugins are very simple. They are a lot like mixins from Ruby. Each one is a package which exports methods. These are then available throughout the app as methods of the site object. A plugin could be as simple as: package Gantry::Plugins::TimeStamp; use strict; use Exporter; our @ISA = ( 'Exporter' ); our @EXPORT = ( 'set_stamp' ); sub set_stamp { my $site = shift; $$site{time_stamp} = scalar localtime; } To use this plugin, simply add it to the list in the use statement: use Gantry qw/-Engine=MP20 -TemplateEngine=TT TimeStamp/; Then, whenever you need it, simply call it like so: $site->time_stamp(); =head1 Who Uses Gantry This web application framework was originally developed by Sunflower Broadband of Lawrence, KS (USA). Sunflower continues to use it to deliver both internal and customer facing web sites.