NAME
LIMS::Controller - Perl object layer controlling the LIMS database and its web interface
SYNOPSIS
use LIMS::Controller;
# login and session control
my $database = database->new('My CGI Page');
my $database = database->new_guest('My CGI Page'); # for pages where no user/pass required
# embedded DBI and CGI objects
my $dbh = database->get_dbh;
my $q = database->get_cgi;
# simplified database queries/inserts
$database->sql_fetch_singlefield($statement);
my $insert_id = $database->insert_into_table($table,$values);
# error handling for DBI functions
$database->kill_pipeline if ($database->any_error);
# ....and it even tidies up after itself
$database->finish;
DESCRIPTION
LIMS::Controller is a versatile object-oriented Perl module designed to control a LIMS database and its web interface. Inheriting from the LIMS::Web::Interface and LIMS::Database::Util classes, the module provides automation for many core and advanced functions required of a web/database object layer, enabling rapid development of Perl CGI scripts.
WRITING A LIMS::Controller PLUG-IN
First, look at the LIMS::ArrayPipeLine module. This is the plug-in written along-side LIMS::Controller, to control our laboratory's CGH-microarray LIMS database. There are many standard methods in there that you will probably want/need in your own module. For most situations, simply editing the config file (see below) to set defaults for your own system will suffice to provide you with a working LIMS.
SETTING UP YOUR DATABASE
There are several parameters that must be set in a config file. For our LIMS::ArrayPipeLine plug-in, running on a UNIX/LINUX type system, the path to this file is set as '/etc/pipeline.conf' and defined in LIMS::ArrayPipeLine. Most of the parameters are self-explanatory, including database hostname, database login, the base URL for the web server, etc.
The database being controlled by the module must have a table called 'USER_INFORMATION'
as described in the accompanying documentation. This table handles user login at the WEB/CGI level. At the database level, a user should be defined with relevant privileges for all required WEB/CGI operations, and the user name and password for this account must be set in the config file. If, for some reason, you need to set other privilege levels beyond these, we suggest you do this at the WEB server level on a script-by-script basis. For instance, you might want to provide browse-only access to some members of staff, or reserve some admin functions for other members of staff.
METHODS
Basic functions
There are actually only a few methods that are used on a regular basis in a CGI script.
- new, new_guest, new_script
-
All create a new LIMS::Controller object, but of subtly different flavours.
new()
creates the embedded DBI and CGI objects, and requires two form parameters;'user_name'
, and either'password'
or'session_id'
which it verifies via the'USER_INFORMATION'
table in your database. The methodnew_guest()
is similar but does not require the user parameters and does not verify login. The methodnew_script()
returns a new object without CGI/DBI or user login. So the initial login page to the system would use thenew_guest()
method, and provide a form to enter auser_name
andpassword
. A script receiving a validuser_name/password
combination will then return an object from thenew()
method, and create a valid session_id. Subsequently, thenew()
method will return an object from a validuser_name/session_id
combination. - get_dbh, get_cgi
-
These methods return the embedded DBI database handle and CGI object respectively. The database handle should not be required, since most DBI functions are handled within LIMS::Controller. It is recommended that you use the object-oriented style of calling CGI methods, although you probably don't HAVE to.
- is_back_sensitive
-
Prevents the user from using the back button on their browser by rejecting an old
session_id
. - is_unrepentant
-
Causes the script to die if any errors are thrown, printing out all errors and issuing a
rollback
call to the database. - finish
-
Tidies up at the end of a script; prints a page footer (if there is one), forwards parameters if not already performed, disconnects from the database and closes a log file (if there is one open).
- page_title
-
Returns the page title, set in the
new()
andnew_guest()
methods.
DBI Functions
Most of these methods are simply wrappers for DBI calls, catching possible errors so that the way they are reported can be controlled in the CGI script. Why not use Class::DBI? Well you can if you prefer - table classes are already loaded via Class::DBI::Loader.
Simple SQL 'fetch' methods
Methods fetching the results of SELECT
queries are offered in a variety of flavours, returning results in different Perl data structures. Pass these methods a string 'SELECT'
query.
- sql_fetch_singlefield
-
Return a single row, single value, as a scalar
- sql_fetch_multisinglefield
-
Multiple rows of a single value are returned as an array reference
- sql_fetcharray_singlerow
-
Wrapper for the DBI method
fetchrow_arrayref()
. A single row of multiple values is returned as an array reference - sql_fetchlist_singlerow
-
Wrapper for the DBI method
fetchrow_array()
. A single row of multiple values is returned as an array - sql_fetcharray_multirow
-
Wrapper for the DBI method
fetchall_arrayref()
. Multiple rows of multiple values are returned as a reference to a 2D array - sql_fetch_twofieldhash
-
Special use; If you have a query that returns a row of two values, where the first value is a primary key or other unique index. This method will return a reference to a hash whose keys/values are the first/second values of each row
- sql_fetchhash_singlerow
-
Wrapper for the DBI method
fetchrow_hashref()
. A single row of multiple values is returned as a reference to a hash, whose keys are the column names, and whose values are the row values - sql_fetchhash_multirow
-
Multiple rows of multiple values are returned as a reference to an array of hashes
- retrieve_file_blob
-
Utilises
sql_fetch_singlefield()
, but sets the DBI {LongReadLen} variable to a default value of 32Mb in order to return long BLOB fields
SQL Insert and Update methods
Please note: LIMS::Controller does not control database privileges - it is assumed that the database login used by the module is only Grant[ed] privileges necessary/suitable for your application. Therefore, if the login does not have update/insert privileges, these methods will return relevant database errors caught by DBI.
- insert_into_table
-
Pass this method the table name together with the values to be inserted as a pre-formatted string, in the correct table column order. The method will generate the field values which will not include an auto-increment primary key. If you need/want to specify the field values, you can pass them as a pre-formatted string after the insert values - in which case the order of the two should match but do not have to be the table column order
- insert_with_placeholders
-
Use this method for inserts of multiple rows of data, or if you need to insert quoted strings. This method is called similar to
insert_into_table()
, except that the values are passed as a reference to a 2D array of values to be inserted. If you need to pass the table fields, then you also need to pass a string of the correct number of placeholders. OK, so this isn't so tidy, but I was lost for a better way to do it.Unlike other methods, this will call
kill_pipeline()
if any errors are caught, orcommit_session()
upon successful completion of all inserts. If the insert statament returns aninsert_id
, and the call to this method requests an array, it will return a list of the insert_ids created by each executed statement. Otherwise, it will return the number of inserted rows.my $aaValues = [ [ $value1, $value2 ], [ $value3, $value4 ] ]; $database->insert_with_placeholders($table,$aaValues); $database->insert_with_placeholders($table,$aaValues,"field1,field2","?,?");
- simple_update_placeholders
-
Use this method to update a single value in a table row. Pass the table name, the field to be set, the new value, and finally a
'WHERE'
clause.
CGI methods
- param_forward
-
Forwards all current parameters as hidden values. (Hidden in a '4-year old playing hide-and-seek' kind of way - in the HTML).
- min_param_forward
-
Forwards only
'user_name'
and'session_id'
parameters as hidden values - format_url_base_query
-
Formats
'user_name'
and'session_id'
parameter values to append to a cgi script's url - format_redirect
-
Pass a script name to format a url to the script with
'user_name'
and'session_id'
parameter values - format_redirect_full
-
Pass a script name to format a url to the script with all parameters
- javascript
-
Creates a
<script
> tag in the HTML header for defining Javascript code. You can pass either an array ref containing one or more URLs to javascript files, or aHERE
string of formatted javascript code.
Handling Errors
One of the main reasons for writing this module was because I wanted to be able to deal with all errors - Perl, CGI, DBI - in a more efficient manner, all at the same time. If you want your script to die straight away printing relevant errors to the web page, you can set the object to be 'unrepentant' as described above. The default is that the object allows you to be sorry for your coding sins, and then explains nicely what's gone wrong.
Three methods, db_error()
, standard_error()
and any_error()
handle the errors for us, and the kill_pipeline()
method prints them out upon killing the script; db_error()
returns any database (DBI) errors that have been caught; standard_error()
can be used to set any error/complaint in a CGI script, or returns any standard_error that has already been set; while any_error()
returns true if errors of any type have been caught. So one line of code handles most eventualities;
$database->kill_pipeline if ($database->any_error);
If you have a simple situation where you want to kill the script with an error you've caught in your script, you can combine the error with the kill_pipeline()
method;
$database->kill_pipeline('got a problem');
Errors can be returned in text (rather than HTML) format by calling the method text_errors()
, or printed separately without calling kill_pipeline()
using the print_db_errors()
, print_standard_errors()
or print_errors()
methods. If you need to, you can clear errors using the methods clear_db_errors()
, clear_standard_errors()
or clear_all_errors()
.
SEE ALSO
LIMS::Base, LIMS::Web::Interface, LIMS::Database::Util, LIMS::ArrayPipeLine
AUTHORS
Christopher Jones and James Morris, Translational Research Laboratories, Institute for Women's Health, University College London.
http://www.instituteforwomenshealth.ucl.ac.uk/trl
c.jones@ucl.ac.uk, james.morris@ucl.ac.uk
COPYRIGHT AND LICENSE
Copyright 2007 by Christopher Jones
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.