The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
\chapter{A Peek Under the Hood}
\label{chap:gantrytour}

Having seen one simple app in several incarnations, you might be wondering
exactly what Gantry is doing.  This chapter is a sneak peek into what files
bigtop made and how Gantry uses those, plus its own code, to make our app
runs.

\section{The Files}

This section will give you a tour of the files bigtop has been making and
remaking for us.  You probably noticed a few of these like README, Build.PL,
etc.  Those are not particularly interesting.  Here, I'll walk you through
the ones that do real work.  There is one section for each relevant file,
other files are similar to the ones discussed.

\subsection*{app.server}

This is the file you were executing in Chapter \ref{chap:simpleex}:

\begin{verbatim}
#!/usr/bin/perl
use strict;

use lib qw( blib/lib lib );

use Contact qw{ -Engine=CGI -TemplateEngine=TT };

use Gantry::Server;

use Gantry::Engine::CGI;

my $cgi = Gantry::Engine::CGI->new( {
    config => {
        dbconn => 'dbi:Pg:dbname=contact',
        dbuser => 'apache',
        template_wrapper => 'genwrapper.tt',
        root => '/home/pcrow/Contact/html:/home/pcrow/srcgantry/root',
    },
    locations => {
        '/' => 'Contact',
        '/contacts' => 'Contact::Contact',
        '/bday' => 'Contact::BDay',
    },
} );

my $port = shift || 8080;

my $server = Gantry::Server->new( $port );
$server->set_engine_object( $cgi );
$server->run();
\end{verbatim}

The use lib makes sure that the server can find the code modules whether
you use ./Build or not.  But once you use it, you must keep using it, since
it looks in blib/lib first.  Any changes to lib files will not be noticed
once they appear in blib/lib.

Gantry has a stand alone server called Gantry::Server.  It is based on
HTTP::Server::Simple and relies on the CGI engine -- but that doesn't mean
that it forks a process for each request, it is persistent, it just uses
the CGI engine to handle requests.

The CGI engine expects a hash reference with two subhashes, one for config
and the other for locations.  Each location is a url suffix the user can
hit via the server.  If you use Gantry::Conf, you can replace the whole config
subhash with:
\begin{verbatim}
config => { GantryConfInstance => 'contact' }
\end{verbatim}
You may also add the optional GantryConfFile key if you don't use
\verb+/etc/gantry.conf+  See Chapter \ref{chap:deploy} for more details
on Gantry::Conf.  See the section on the CGI Gantry bigtop backend
in Chapter \ref{chap:backends} for instructions on how to set up Gantry::Conf
for app.server and CGI environments via tentmaker.

The server uses port 8080 by default, but accepts an overriding port number
from the command line.  The Gantry::Server constructor is inherited
from HTTP::Server::Simple, so a call to \verb+set_engine_object+ is needed
to load it with our CGI object.  The \verb+run+ method is also supplied
by HTTP::Server::Simple.  A little later we'll look at what happens inside that
method.

\subsection*{Contact.pm}

For small apps the base module is mostly a waste of space.  For larger apps,
it becomes home to common code.  Since the contact app is of the small
veriety, there is not much of interest in Contact.pm:

\begin{verbatim}
package Contact;

use strict;

our $VERSION = '0.01';

use base 'Gantry';

use Contact::Contact;
use Contact::BDay;

##-----------------------------------------------------------------
## $self->init( $r )
##-----------------------------------------------------------------
#sub init {
#    my ( $self, $r ) = @_;
#
#    # process SUPER's init code
#    $self->SUPER::init( $r );
#
#} # END init

1;

=head1 NAME

Contact - the base module of this web app

#... More POD ...
\end{verbatim}

To begin, it is a documentation placeholder.  It explicitly uses the modules
in the app -- at least the ones it knew about when it was written.

There is also a potentially useful init method provided as a comment.
Uncomment it if you need to handle config info that Gantry doesn't know about.
For instance, to handle an SMTP host for genuine emailing, you could use
this init and accessor pair:

\begin{verbatim}
sub init {
    my ( $self, $r ) = @_;

    # process SUPER's init code
    $self->SUPER::init( $r );

    $self->smtp_host_set( $self->fish_config( 'smtp_host' ) );

} # END init

sub smtp_host_set {
    my ( $self, $value )   = @_;
    $self->{__SMTP_HOST__} = $value;
}

sub smtp_host {
    my ( $self ) = @_;
    return $self->{__SMTP_HOST__};
}
\end{verbatim}

By calling \verb+fish_config+, we allow Gantry to use Gantry::Conf if
the app is deployed with it, or a fall back scheme if it is not.  Which
fall back scheme will be determined by the engine.  This is one important
part of engine independence, allowing us to move easily between CGI and
\verb+mod_perl+ for instance.

Again, since all other modules in the app (except the models) inherit
from this package, it is a good place to locate common code.

\subsection*{Contact/Contact.pm}

The controller stub for the contact table looks like this:

\begin{verbatim}
package Contact::Contact;

use strict;

use base 'Contact';
use Contact::GEN::Contact qw(
    do_main
    form
);

use Gantry::Plugins::AutoCRUD qw(
    do_add
    do_edit
    do_delete
    form_name
);

use Contact::Model::contact qw(
    $CONTACT
);

#-----------------------------------------------------------------
# $self->do_main(  )
#-----------------------------------------------------------------
# This method supplied by Contact::GEN::Contact

#-----------------------------------------------------------------
# $self->form( $row )
#-----------------------------------------------------------------
# This method supplied by Contact::GEN::Contact


#-----------------------------------------------------------------
# get_model_name( )
#-----------------------------------------------------------------
sub get_model_name {
    return $CONTACT;
}

#-----------------------------------------------------------------
# text_descr( )
#-----------------------------------------------------------------
sub text_descr     {
    return 'contact';
}

1;

... POD ...
\end{verbatim}

I call this a stub for the obvious reason that it starts empty, except
for use statements.  You might not ever have to put any code here (in
which you could promote the next piece to its place).  But, as with the
base module for the whole app, we often need some special code
for our pages.  This is where it goes.

Otherwise, this is another documentation place holder.  It is meant to be
very easy for someone to open this file and see exactly what it does, even
if there is almost no code.  This is why it has so many comments and
why it explicitly imports everything it uses.

\subsection*{Contact/GEN/Contact.pm}

The real code that manages the contact table is here:

\begin{verbatim}
# NEVER EDIT this file.  It was generated and will be overwritten without
# notice upon regeneration of this application.  You have been warned.
package Contact::GEN::Contact;

use strict;

use base 'Exporter';

our @EXPORT = qw(
    do_main
    form
);

use Contact::Model::contact qw(
    $CONTACT
);

#-----------------------------------------------------------------
# $self->do_main(  )
#-----------------------------------------------------------------
sub do_main {
    my ( $self ) = @_;

    $self->stash->view->template( 'results.tt' );
    $self->stash->view->title( 'Contacts' );

    my $retval = {
        headings       => [
            'Name',
            'Phone',
            'Email',
        ],
        header_options => [
            {
                text => 'Add',
                link => $self->location() . "/add",
            },
        ],
    };

    my @rows = $CONTACT->get_listing();

    foreach my $row ( @rows ) {
        my $id = $row->id;
        push(
            @{ $retval->{rows} }, {
                data => [
                    $row->name,
                    $row->phone,
                    $row->email,
                ],
                options => [
                    {
                        text => 'Edit',
                        link => $self->location() . "/edit/$id",
                    },
                    {
                        text => 'Delete',
                        link => $self->location() . "/delete/$id",
                    },
                ],
            }
        );
    }

    $self->stash->view->data( $retval );
} # END do_main

#-----------------------------------------------------------------
# $self->form( $row )
#-----------------------------------------------------------------
sub form {
    my ( $self, $row ) = @_;

    my $selections = $CONTACT->get_form_selections();

    return {
        name       => '',
        row        => $row,
        fields     => [
            {
                name => 'name',
                label => 'Name',
                type => 'text',
                is => 'varchar',
            },
            {
                name => 'phone',
                optional => 1,
                label => 'Phone',
                type => 'text',
                is => 'varchar',
            },
            {
                name => 'street',
                optional => 1,
                label => 'Street',
                type => 'text',
                is => 'varchar',
            },
            # ... other similar hashes
        ],
    };
} # END form

1;

#... POD ...
\end{verbatim}

The \verb+do_main+ method we created with tentmaker is shown in all its
glory here.  Its purpose is to draw data from the underlying table
and feed it to the standard \verb+results.tt+ template.  That template expects
a hash reference with these keys: \verb+headings+, \verb+header_options+,
and \verb+rows+.  The headings are column labels, the header options usually
just lists Add, which allows users to add rows to the table.  Other options
would likely be reports.  The rows are the data for the table.

The rows are an array of hashes with \verb+data+ and \verb+options+ keys.
The data is just an array of the values from the underlying table.  The
options are things that can be done to the row like Edit or Delete.
Note that the urls of the options are specified (in terms of the location
of the invocant).

When the data structure is ready, it is placed into the stash's view data.

The \verb+form+ method first asks the model for any foreign keys the
user might be allowed to choose.  They go unused here, but come in to
play for the BDay controller.  It requires users to choose a contact family
for each birthday row.

The method builds a hash reference for use by the \verb+form.tt+ template.
This allows a lot of keys, read its docs for details.  Here we need these
keys: row and fields.  The row key contains a reference to the model object
for the current row (if there is one).  The fields key is an array of
fields, in the order they will appear on the screen.  Each array describes
the field so the template knows how to gather input for it.  All of the
keys in the hash are taken directly from tentmaker, except that the
ones beginning with \verb+html_form_+ have the prefix stripped -- so
\verb+html_form_optional+ becomes simple \verb+optional+.

\subsection*{Contact/Model/contact.pm}

\subsection*{Contact/Model/GEN/contact.pm}

\section{Gantry and Its Server}



%\begin{figure}
%\includegraphics[width=6in]{name}
%\caption{Caption.}
%\label{fig:name}
%\end{figure}