[Catalyst] example of sep db config args (was Re: Accessing DB from external model)

Darren Duncan darren at darrenduncan.net
Sat Nov 6 18:57:18 GMT 2010


P.S.  While answering a question, this email could be adapted for a Catalyst 
cookbook / etc entry if one wants to.

Octavian Rasnita wrote:
> I agree and yes, that sample code could give bad ideas.
> In my case I am the app designer, coder, maintainer, site admin, everything but the web designer and I've done it so for not specifying these settings in more places.

I have the same role in my situation, but I also designed the project so it is 
easier for someone else to come along and maintain it.

> Is there another place where I could put these settings for a certain DBIC schema?
> For example, can I put them in the MyApp/Schema.pm, orsomewhere else? Can you give an example?

I can show you a simplified version of what I have done, but with any 
identifying details changed to protect the innocent.  My version uses straight 
DBI+DBIx::Connector rather than DBIC but you should be able to adapt the design 
to DBIC or any other database API; my version is also Pg-specific but only minor 
tweaks would be needed to work with something else.  Since this is from a 
proprietary application rather than a CPAN module, I can get away with requiring 
and exploiting the latest Perl version, 5.12.x, rather than giving those up to 
support older Perls.

1.  Here is the relevant portion of MyApp.conf, which uses Config::General as 
per Catalyst's default these days.

     <Model DB>
         <args>
             db_host localhost
             db_port 5444
             db_name myproj_v1_db
             db_user myproj_v1_usr_myapp
             db_pass myapppass
         </args>
     </Model>

2.  Here is the slightly simplified version of MyApp/Model/DB.pm, which uses 
Catalyst::Model::Adaptor, and in such a way to support different class and file 
names (requires 0.09+):

     use 5.012002;
     use utf8;
     use warnings FATAL => 'all';

     use MyDBMSLib 0.001;

     package MyApp::Model::DB 0.001;

     use parent 'Catalyst::Model::Adaptor';  # requires >= 0.09

     __PACKAGE__->config( class => 'MyDBMSLib' );

     1;

3.  Here is a complete/template content of MyDBMSLib.pm; the original had 
multiple classes in it but I removed the other ones and simplified the main one; 
the original file was named after a different package than what I kept:

     use 5.012002;
     use utf8;
     use warnings FATAL => 'all';

     use DBIx::Connector;
     use DBI;
     use DBD::Pg;

     ###########################################################################
     ###########################################################################

     { package MyDBMSLib 0.001; # class

         use namespace::autoclean;

         use Try::Tiny;

         use Moose;

         has 'db_host' => (is => 'ro', isa => 'Str', required => 1 );
         has 'db_port' => (is => 'ro', isa => 'Int', required => 1 );
         has 'db_name' => (is => 'ro', isa => 'Str', required => 1 );
         has 'db_user' => (is => 'ro', isa => 'Str', required => 1 );
         has 'db_pass' => (is => 'ro', isa => 'Str', required => 1 );

         # This is the actual (as far as we're concerned) Pg database connection
         # object; the connection is opened the first time the _dbc attr is read
         # and it is closed when the _dbc attr is garbage collected.
         has '_dbc' => (
             is       => 'ro',
             isa      => 'DBIx::Connector',
             required => 1,
             lazy     => 1,
             default  => \&_lazy_default_for_dbc,
         );

     ###########################################################################

     sub _lazy_default_for_dbc {
         my ($process) = @_;
         my $dbc = try {
             my $dsn = sprintf( q{dbi:Pg:dbname=%s;host=%s;port=%s},
                 $process->db_name(), $process->db_host(), $process->db_port() );
             my $dbc = DBIx::Connector->new( $dsn,
                 $process->db_user(), $process->db_pass(),
                 { 'RaiseError' => 1, 'AutoCommit' => 1 },
             );
             my $dbh = $dbc->dbh();
             # SET UP ANY OTHER CLIENT SETTINGS HERE ON $dbh
             return $dbc;
         }
         catch {
             confess sprintf( q{Could not open connection to Pg server or db: 
%s}, $_ );
         };
         return $dbc;
     }

     ###########################################################################

     # PUT OTHER USEFUL MyDBMSLib METHODS HERE

     ###########################################################################

         __PACKAGE__->meta()->make_immutable();

     } # class MyDBMSLib

     ###########################################################################
     ###########################################################################

     1;

For your version, mainly just replace _dbc with an object of whatever initial 
class you have with DBIC that takes the db connection config args.

Your analogy to _lazy_default_for_dbc is where you feed DBIC its actual config 
args, where some can be defined in MyDBMSLib itself and others taken from the 
config file.

-- Darren Duncan



More information about the Catalyst mailing list