ENV ATTRIBUTES FOR DEV SERVER:
useage: export ATTR=1
  OVERRIDE_LOCK - prevents record being 'locked' by request status
  HTTP_REPORT   - returns report as web-page instead of PDF
  DB_SESSIONS   - uses session table instead of /sessions directory
  DEBUG_ON      - use in test suite to dump debug info to console

CURRENT ISSUES:
under mod_perl (only) report function issues rollback on request_report table insert in M::Report::update_report(). remove Apache::DBI and issue goes away,
but get 1 -2 new db conenctions for every new web request. override dbi_connect() in LIMS::DB and issue also goes away, but get error if a transaction fails (eg duplicate UK): rollback ineffective with AutoCommit enabled at /home/raj/perl5/lib/perl5/Rose/DB.pm line 1208. set autocommit to 0 and some db edits fail
IDENTIFIED PROBLEM IN M::Roles::RequestUpdate::update_request_status() - APPEARS TO BE DUE TO LIMS::DB::StatusOption->new() ACTION, AND IS FIXED IF TRANSACTION DBH IS USED. 

Other actions causing same failure in same transaction: 
LIMS::DB::AdditionalOption::Manager->get_additional_options in do_additional_options()
LIMS::DB::RequestLabTestStatus::Manager->get_request_lab_test_status() in has_outstanding_tests()
LIMS::DB::StatusOption->new() in _is_authorisation_active()

# from #rdbo (26/3/2010):
14:08 < siracusa> here's what I think is happening
14:08 < siracusa> when you don't explicitly supply a db object, RDBO calls init_db() to make one
14:08 < siracusa> and init_db() eventually leads to DBI->connect() being called
14:08 < siracusa> and under Apache::DBI, DBI->connect looks first in its cache of database handles that are already connected
14:08 < siracusa> it finds an already-connected handle
14:09 < siracusa> but Apache::DBI also resets all the handle attributes to their original values before returning its cached $dbh
14:09 < siracusa> and teh original value for AutoCommit was 1
14:10 < siracusa> so it takes this $dbh which, unbeknownst to it, is still being used in an outstanding transaction
14:10 < siracusa> and sets its AutoCommit to 1
14:10 < siracusa> which apparently angers the transaction in flight and causes the weird rollback issues
14:10 < siracusa> it's always best/safest to explicitly share a db object during the course of a transaction
14:11 < siracusa> which avoids situations like this where Apache::DBI is handing out your transaction $dbh to other objects and resetting its attributes when it does

*********** so solution is to use same shared dbh throughout transaction **************

Template name generation
CAT::TT default is LIMS/App/runmode.tmpl
overridden in tt_config using TEMPLATE_NAME_GENERATOR - generates app/runmode.tt, but only works if runmode is requested, not forwarded. Automatic template generation for forwarded rm's is handled by LIMS::get_template_name

DBH
cgiapp_init() uses LIMS::DB->new->retain_dbh to initialise $self->dbh_config
LIMS::RDBO init_db() returns LIMS::DB->new_or_cached
They are not the same dbh as $dbi->{Profile} = DBI::Profile->new set in cgiapp_init prints login sql to console, but rest of sql calls by RDBO are not. Can set $dbh->{Profile} in LIMS::RDBO but sql never output. Seems to depend on whether new_or_cached set, and whether retain_dbh used.
Might be mis-using db connections: [Dispatch] ERROR' for request '/hmds/admin/lab_section': Error executing class callback in init stage: DBI connect('database=hmds_lims;host=localhost','raj',...) failed: Too many connections at /home/raj/perl5/lib/perl5/Rose/DB.pm line 887
SHOW PROCESSLIST shows sleeping processes increasing for each request, under lims_server (not mod_perl). Re-start lims_server resets to 0. Have set wait_timeout = 120 in my.cnf until this is fixed. FIXED - need to call new_or_cached->retain_dbh instead of new->retain_dbh in cgiapp_init

Transactions:
If using RDBO do_transaction(), methods in anon sub MUST use same db as parent method - see:
http://groups.google.com/group/rose-db-object/browse_thread/thread/a30231b7c0be219d

Sub-selects:
1) 'request_report.request_id' => { eq => undef }, with_objects => 'request_report'
2) my $subselect = q!NOT EXISTS (SELECT request_id FROM request_report rr WHERE rr.request_id = id)!;
   $data = RBDO::Manager->get_objects( clauses => [ $subselect ] );

DBH sharing - might be dangerous in commit/roll-back situations where rollback undoes previous commits in unrelated sections of code - see http://thread.gmane.org/gmane.comp.lang.perl.modules.dbi.rose-db-object/2570/focus=2575
might be safer to use new dbh for transactions.

Database selection in LIMS::DB
defaults to test - overridden in lims_server.pl and mod_perl config using env variable ROSEDB_DEVINIT which points to config/rosedb_devinit_[devel|prod].pl which uses modify_db() method to change db to devel/production. dbi_connect returns DBIx::Log4perl enabled dbh if ROSEDB_DEVINIT flag set, so we don't get t/ files dumping sql to console.

Variable persistence:
Using CAD::Server, passing id in url eg /admin/update/2 and retrieving via $data->{id} = $self->param('id') causes value to persist across subsequent requests, so if next request is to generate new record, previous id is retained and record gets updated with new data instead of creating new record - safer to hand id in hidden param in form. CA::Server & mod_perl don't suffer from this. FIXED - use CA::Server instead.

mod_perl or fastcgi:
See 'is my app caching db connection ?' in cgiapp list for issues regarding FastCGI and transactions:
Incidentally, I hope you have something in there to catch errors at the top level of your FastCGI adapter and issue a rollback on any open database handles.  If you don't, you might leave some partially completed uncommitted data around that the next request would commit. Aoache::DBI solves this for mod_perl by doing a rollback on all open
connections after every request, in case the request exited abnormally.

Debug:
$self->debug( scalar, arrayref, hashref, obj or subroutine ref; followed by optional number 1 ..7) - uses Log::Dispatch either via CAP::LogDispatch or LIMS::LogDispatch - setup at top of LIMS.pm
If using LIMS::LogDispatch, $self->log_dispatch->log(message => sub{Dumper $foo}, level => 'bar') also works - use for expensive ops like Data::Dumper expansion of object, which may be discarded if log level too low. TODO - integrate with debug() - need to test for presence of subroutine in args

Config:
Files in config directory labelled lims_*.pl are automatically loaded in LIMS::Dispatch

RBDO errors:
Cannot load MyApp::DB::Foo without a primary key (id) with a non-null value or another unique key with at least one non-null value - creating a new record on a table with no unique keys (except PK), using MyApp::DB::Foo->new(%data)->insert_or_update() - it can't - behaviour fixed in 0.775 - see ChangeLog

ErrorHandler:
LIMS::Local::ErrorHandler uses a $SIG{__DIE__} handler which interfers with CAP::Redirect (see http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg05184.html)
Copied CAP::Redirect function into LIMS::Base::redirect(), omitting eval block causing problem with SIG{__DIE__}
Works under test_harness & mod_perl but not fastcgi - get std server error msg

capture SIGDIE in test harness mode: 
export DEBUG_ON=1; perl -Ilib -e '$SIG{__DIE__} = sub { warn $_[0]; die $_[0]; }; do "t/test.t";'

New db tables:
SQL to setup/lims.sql, any dependency data to setup/data.sql.
Test db creation in rebuild.pl - set db to test or lims_scratch.
Generate DB classes with script/make_classes.pl -> setup/classes.pl -> DB/Foo.pm

MySQL binary logfiles:
To turn off log-bin, edit /etc/mysql/my.cnf and comment out log-bin:
#log-bin = /var/log/mysql/mysql-bin.log
This will save 100MBs of space if you have a fast insert going on.
You also have to comment out the following if you comment out log-bin or mysqld will not start:
#expire_logs_days = 10

Autosuggest js:
bsn.Autosuggest.jQuery.js is a compressed version of bsn.Autosuggest_2.1.3.js, with true/false changes made to 'onKeyPress bubble', so that 'return/enter' keypress just selects from list & doesn't submit form - see last posting by Igor - http://www.brandspankingnew.net/archive/2007/02/ajax_auto_suggest_v2.html

DFV messages:
see: http://sourceforge.net/mailarchive/forum.php?thread_name=20080108163239.GA12455%40apartia.fr&forum_name=cascade-dataform
The 'msgs' hashref refers to constraint names, not field names. For this to work, you have to call the "name_this" method inside of the custom FV_URI_HTTP method.

HTMLDOC:
from wdir: sh .configure --prefix=/home/raj/perl-lib/htmldoc; make; make install
ln -s /home/raj/www/perl-lib/htmldoc/bin/htmldoc /usr/local/bin/htmldoc; cpan HTML::HTMLDoc

ASPELL:
need to apt-get install aspell-en if not aleady installed
Win32 - see http://www.nosq.com/blog/2005/07/aspell-0603-for-win32/

svk:
svk mirror http://address.of.repo //mirror/mirror_name
svk sync //mirror/mirror_name

svk cp //mirror/hmds_lims/trunk //mirror/hmds_lims/branches/foo -m 'creating branch for
version 0.01' then, from root dir: svk up -s
svk cp //mirror/hmds_lims/trunk //mirror/hmds_lims/tags/0.01 -m 'tagging version 0.01'
svk mirror --detach //mirror/hmds-lims
svk co --purge
svk checkout --list
svk checkout --relocate //mirror/mirror_name /path/to/new/location
svk mirror //mirror/hmds_lims https://www.jti.org.uk/svn/hmds_lims
to merge trunk & branches: cd app/branches/foo; svk push; cd app/trunk; svk up -s
'svk pull' in your branch pulls all changes from trunk down to your branch

Moose:
use Moose; extends foo; works in Model classes, but in all Controller classes, get: 
Invalid CODE attribute: StartRunmode
OR: can't locate object method 'add_callback' in RunmodeDeclare (if using Sugar)

REQUEST STATUS:
new request automatically gets status_option_id 1 (new) - 'requests' table default value
screening -> status_option_id 2 (screened)
reporting: 
	if 'authorise' status_option inactive and no outstanding tests, status_option_id = 5 (completed) 
	else status_option_id = 3 (reported)
authorising (available in template only if request reported & 'authorise' option is active):
	if no oustanding tests, status_option_id = 5 (completed)
	else status_option_id = 4 (authorised)
final_diagnosis - tmpl param enabled if request authorised (or reported if 'authorise' option inactive) AND status NOT complete AND no outstanding tests: 
	status_option_id = 5 (completed)
new lab_tests -> reverts status_option to <5 (complete) if appropriate

EMAIL ALERT RULES:
1) Authorised & status = new / relapse & have e-mail contact (overriden for age / PNH)
2) test = TBCulture & diagnosis = 'Granulomatous inflammation' & LTH case
3) special rules for diagnosis = 'DLBCL or Burkitt lymphoma - further tests pending'

DateTime:
Unfortunately, DateTime does not seem to provide a good way to set the
default stringification format for DateTime objects.  A hack to do that
would be to put this code somewhere in your app:

    use DateTime;
    no warnings 'redefine';
    sub DateTime::_stringify { shift->strftime('%Y-%m-%d %H:%M:%S') }

Then all DateTime objects will stringify "without the T" everywhere in your
code, yielding:

    $dt = $user->expires; # a DateTime object, but...

    print $dt; # prints a string like "2003-12-31 12:34:56" -- no "T"!

