NAME
CGI::Application::Demo::Basic
- A vehicle to showcase CGI::Application
Synopsis
basic.cgi:
#!/usr/bin/perl
use strict;
use warnings;
use CGI::Application::Demo::Basic;
# -----------------------------------------------
delete @ENV{'BASH_ENV', 'CDPATH', 'ENV', 'IFS', 'PATH', 'SHELL'}; # For security.
CGI::Application::Demo::Basic -> new -> run;
Description
CGI::Application::Demo::Basic
showcases CGI::Application
-based applications, via these components:
- o A set of 7 CGI instance scripts
- o A set of 4 text configuration files
- o A CSS file
- o A data file to help bootstrap populating the database
- o A set of 5 command line scripts, to bootstrap populating the database
- o A set of 10 HTML::Templates
- o A set of 11 Perl modules
-
- o CGI::Application::Demo::Basic
- o CGI::Application::Demo::Basic::One
-
The five modules One.pm .. Five.pm, and Basic.pm, have been designed so as to be graduated in complexity from simplistic to complex, to help you probe the preculiarities of a strange environment.
Each module ships with a corresponding config file, instance script and template. Well, actually, One.pm and Two.pm are too simple to warrant their own config files, and One.pm does not even need a template.
- o CGI::Application::Demo::Basic::Two
- o CGI::Application::Demo::Basic::Three
- o CGI::Application::Demo::Basic::Four
- o CGI::Application::Demo::Basic::Five
- o CGI::Application::Demo::Basic::Base
- o CGI::Application::Demo::Basic::Faculty
- o CGI::Application::Demo::Basic::Util::Config
- o CGI::Application::Demo::Basic::Util::Create
-
The code to drop tables, create tables, and populate tables is all in this module.
This was a deliberate decision. For example, when everything is up and running, there is no need for your per-table modules such as
Faculty.pm
to contain code to do with populating tables, especially constant tables (asfaculty
is in this demo). - o CGI::Application::Demo::Basic::Util::LogDispatchDBI
This module, CGI::Application::Demo::Basic
, demonstrates various features available to programs based on CGI::Application
:
- o Probing a strange environment
- o Run modes and their subs
- o Disk-based session handling
- o Using the session to store user-changeable options
- o Using
Class::DBI
andClass::DBI::Loader
to auto-generate code per database table -
Yes, I know
Class::DBI
has been superceded byDBIx::Class
andRose
. - o Using
HTML::Template
style templates - o Changing the run mode with Javascript
- o Overriding the default query object
-
This replaces a
CGI
object with a lighter-weightCGI::Simple
object.And yes, bug fixes for
CGI::Simple
have not kept up with those forCGI
.This is a demo, ok?
- o Initialization via a configuration file
- o Switching database servers via the config file
- o Logging to a database table
- o Multiple inheritance, to support MySQL, Oracle, Postgres and SQLite neatly
-
See
CGI::Application::Demo::Basic::Util::LogDispatchDBI
.
Note: Because I use Class::DBI::Loader
, which wants a primary key in every table, and I use CGI::Session
, I changed the definition of my 'sessions' table - compared to what is recommended in the CGI::Session
docs - from this:
create table sessions
(
id char(32) not null unique,
a_session text not null
);
to this:
create table sessions
(
id char(32) not null primary key, # I.e.: 'unique' => 'primary key'.
a_session text not null # For Oracle, 'text' => 'long'.
);
Also, as you add complexity to this code, you may find it necessary to change line 10 of Base.pm from this:
use base 'Class::DBI';
to something like this:
use base $^O eq 'MSWin32' ? 'Class::DBI' : 'Class::DBI::Pg'; # Or 'Class::DBI::Oracle';
Distributions
This module is available as a Unix-style distro (*.tgz).
See http://savage.net.au/Perl-modules/html/installing-a-module.html
for help on unpacking and installing distros.
Patching config file and templates, and running CGI scripts
Unpack the distro, and you will see various files which may need to be patched before running the CGI scripts.
Almost all config options are in text files, to handle different operating environments.
Files and patches:
- o scripts/test.conf.pl
-
No patches needed, so run it now.
- o scripts/create.pl
-
This uses lib/CGI/Application/Demo/Basic/Util/basic.conf, so patch this file (i.e. the dsn).
If not using SQLite, you will need to create a database at this point.
Then run this script to create the tables.
- o scripts/populate.pl
-
This uses the same config file as scripts/create.pl, so you can run populate.pl straight away.
- o scripts/drop.pl
-
Later, you can start over by running drop.pl, and then create.pl and populate.pl.
- o scripts/create.1.table.pl
-
This just demonstates how to re-create a single table.
- o cgi-bin/ca.demo.basic/lib.cgi
-
Copy all cgi-bin/ca.demo.basic/*.cgi scripts to your cgi-bin/ dir now.
Under Debian, this is /usr/lib/cgi-bin, and you will need sudo.
lib.cgi does not use any modules from this distro, so you can run it immediately, just to make sure things outside this distro are working.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/lib.cgi
.When that is working, move on.
- o cgi-bin/ca.demo.basic/one.cgi
-
If using local::lib, edit line 3, otherwise delete it.
This uses One.pm. It has no config file and no template file.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/one.cgi
.This adds usage of a module based on
CGI::Application
, but the module itself has, deliberately, no complexity of its own. It simple displays a built-in web page.When that is working, move on.
- o cgi-bin/ca.demo.basic/two.cgi
-
If using local::lib, edit line 3, otherwise delete it.
This uses Two.pm. It has no config file, but does have a template file, htdocs/assets/templates/CGI/Application/Demo/Basic/Util/two.tmpl.
Copy all htdocs/assets/templates/CGI/Application/Demo/Basic/Util/*.tmpl files to somewhere suitable.
Under Debian, I use /var/www/assets/templates/CGI/Application/Demo/Basic/Util/, and my docroot is /var/www.
So, I use:
sudo cp -r htdocs/assets/* /var/www/assets
This copies the CSS file too.
These templates use
HTML::Template
.Patch line 42 of Two.pm, which hard codes the path to the template file.
Later modules (you will be glad to know) have this path in a config file.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/two.cgi
.This adds:
- o Replacing
CGI
withCGI::Simple
-
See
sub cgiapp_get_query
. - o Using
HTML::Template
-style templates -
See
sub cgiapp_init
andsub start
.
When that is working, move on.
- o Replacing
- o cgi-bin/ca.demo.basic/three.cgi
-
If using local::lib, edit line 3, otherwise delete it.
This uses Three.pm. It has both a config file, lib/CGI/Application/Demo/Basic/Util/three.conf, and a template file, htdocs/assets/templates/CGI/Application/Demo/Basic/three.tmpl.
Nothing in three.tmpl needs editing, but you will need to patch the tmpl_path in three.conf.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/three.cgi
.This adds:
- o Using
CGI::Application::Demo::Basic::Util::Config
andConfig::Tiny
-
Here for the first time we read a config file.
When that is working, move on.
- o Using
- o cgi-bin/ca.demo.basic/four.cgi
-
If using local::lib, edit line 3, otherwise delete it.
This uses Four.pm. It has both a config file, lib/CGI/Application/Demo/Basic/Util/four.conf, and a template file, htdocs/assets/templates/CGI/Application/Demo/Basic/four.tmpl.
Nothing in four.tmpl needs editing, but you will need to patch css_url, dsn and tmpl_path in four.conf.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/four.cgi
.This adds:
- o Using a CSS file
- o Getting the URL of the CSS file from the config file
- o Getting a DSN, username, password and attributes from the config file
-
So, now we are testing a more complex config file.
- o Use
DBI
-
And we use those parameters to test a direct connexion to the database.
We use this connexion to display all records in the
faculty
table..The
faculty
table has no purpose other than to provide data to be displayed, either viaDBI
or viaClass::DBI
.
When that is working, move on.
- o cgi-bin/ca.demo.basic/five.cgi
-
If using local::lib, edit line 3, otherwise delete it.
This uses Five.pm. It has both a config file, lib/CGI/Application/Demo/Basic/Util/five.conf, and a template file, htdocs/assets/templates/CGI/Application/Demo/Basic/five.tmpl.
Nothing in five.tmpl needs editing, but you will need to patch css_url, dsn and tmpl_path in five.conf.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/five.cgi
.This adds:
- o Using a base module,
Base.pm
, for all table modules -
Actually, there is only per-table module, Faculty.pm, at this time, but at least you can see how to use a base module to share code across table modules.
- o Using a dedicated module for the
faculty
table:Faculty.pm
- o Using
Class::DBI::Loader
-
This uses
Class::DBI
to automatically load a module-per-table.As above, we just display all records in the
faculty
table.
By now, if successful, you will have tested all the components one-by-one.
So, the next step is obvious...
- o Using a base module,
- o cgi-bin/ca.demo.basic/basic.cgi
-
If using local::lib, edit line 3, otherwise delete it.
This uses Basic.pm. It has both a config file, lib/CGI/Application/Demo/Basic/Util/basic.conf, and a template file, htdocs/assets/templates/CGI/Application/Demo/Basic/basic.tmpl.
This is the same basic.conf whose dsn you patched above before running create.pl.
Nothing in basic.tmpl needs editing, but you will need to patch css_url and tmpl_path in basic.conf.
Hit
http://127.0.0.1/cgi-bin/ca.demo.basic/basic.cgi
.This adds
- o Using
CGI::Application::Plugin::LogDispatch
-
Now we log things to a database table via
LogDispatchDBI.pm
(below). - o Using
CGI::Application::Plugin::Session
-
Now we use sessions stored in the database via
CGI::Session
.Install my module
CGI::Session::Driver::oracle
, if necessary. - o
Base.pm
-
A module to share code between all per-table modules.
- o
Faculty.pm
-
A module dedicated to a specific table.
- o
LogDispatchDBI.pm
-
A module to customize logging via
Log::Dispatch::DBI
.
- o Using
Order of Execution of subs within a CGI::Application
-based script:
The section gives some background information on what takes place when a script based on CGI::Application
is executed.
See also this article on the wiki: http://cgi-app.org/index.cgi?OrderOfOperations
.
Initializing your module
The instance script (basic.cgi - see Synopsis) contains 'use CGI::Application::Demo::Basic', which causes Perl to load the file /perl/site/lib/CGI/Application/Demo/Basic.pm.
At this point the instance script is initialized, in that package CGI::Application::Demo::Basic
has been loaded. The script has not yet started to run.
This package contains "use parent 'CGI::Application'", meaning CGI::Application::Demo::Basic
is a descendent of CGI::Application
. That is, CGI::Application::Demo::Basic
is-a CGI::Application
.
This (CGI::Application::Demo::Basic
) is what I will call our application module.
What is confusing is that application modules can declare various hooks (a hook is an alias for a sub) to be run before the sub corresponding to the current run mode.
Two of these hooked subs are called cgiapp_init (hook is 'init'), and cgiapp_prerun (hook is 'prerun').
Further, a sub prerun_mode is also available.
None of these 3 sub are called yet, if at all.
Calling new()
Now CGI::Application::Demo::Basic -> new is called.
This is, it initializes a new object of type CGI::Application
.
This includes calling the 'init' hook (sub cgiapp_init) and sub setup, if any.
Since we did in fact declare a sub cgiapp_init (hook is 'init'), that gets called, and since we also declared a sub setup, that then gets called too.
You can see the call to setup at the very end of sub new within CGI::Application
.
Oh, BTW, during the call to cgiapp_init, there was a call to sub setup_db_interface, which, via the magic of Class::DBI::Loader
, tucks away an array ref of a list of classes, one per database table, in the statement $self -> param(cgi_app_demo_classes => $classes), and an array ref of a list of table names in the statement $self -> param(cgi_app_demo_tables => $tables).
Calling run()
Now CGI::Application::Demo::Basic -> run is called.
First, this calls our sub cgiapp_get_query via a call to sub query, which we declared in order to use a light-weight object of type CGI::Simple
, rather than an object of type CGI
.
Then, eventually, our application module's run mode sub is called, which defaults to sub start.
So, sub start is called, and it does whatever we told it to do. The app is up and running, finally.
A Note about HTML::Entities
In general, a CGI::Application-type app could be outputting any type of data whatsoever, and will need to protect that data by encoding it appropriately. For instance, we want to stop arbitrary data being interpreted as HTML.
The sub HTML::Entities::encode_entities
is designed for precisely this purpose. See that module's docs for details.
Now, in order to call that sub from within a double-quoted string, we need some sort of interpolation facility. Hence the module HTML::Entities::Interpolate
. See its docs for details.
This demo does not yet need or use HTML::Entities::Interpolate
.
Test Environments
I tested the new CGI::Application::Demo::Basic
in these environments:
- Debian, Perl 5.10.1, SQLite 3.6.22, Apache 2.2.14
- Debian, Perl 5.10.1, Postgres 8.4.2, Apache 2.2.14
I tested the original CGI::Application::Demo
in these environments:
- GNU/Linux, Perl 5.8.0, Oracle 10gR1, Apache 1.3.33
- GNU/Linux, Perl 5.8.0, Postgres 7.4.7, Apache 2.0.46
- Win2K, Perl 5.8.6, MySQL 4.1.9, Apache 2.0.52
Credits
I drew significant inspiration from code in the CGI::Application::Plugin::BREAD
project:
http://charlotte.pm.org/kwiki/index.cgi?BreadProject
(off-line 2010-04-23).
Author
CGI::Application::Demo::Basic
was written by Ron Savage <ron@savage.net.au> in 2005.
Home page: http://savage.net.au/index.html
.
Copyright
Australian copyright (c) 2005, Ron Savage. All Programs of mine are 'OSI Certified Open Source Software'; you can redistribute them and/or modify them under the terms of The Artistic License, a copy of which is available at: http://www.opensource.org/licenses/index.html