NAME
Kelp::Module::RDBO - Kelp interface to Rose::DB::Object
SYNOPSIS
# conf/config.pl
{
modules => [qw/RDBO/],
modules_init => {
RDBO => {
prefix => 'MyApp::DB',
default_domain => 'development',
default_type => 'main',
source => [
{
domain => 'development',
type => 'main',
driver => 'mysql',
...
},
{
domain => 'development',
type => 'readonly',
driver => 'mysql',
...
}
],
},
}
}
# lib/MyApp.pm
...
sub get_song {
my ( $self, $song_id ) = @_;
$self->rdb->do_transaction( ... )
my $song = $self->rdbo('Song')->new( id => $song_id )->load;
}
DESCRIPTION
This Kelp module creates a Rose::DB connection at application startup,
provides an interface to it, and uses it behind the scenes to pass it to
all Rose::DB::Object derived objects. This way, the application
developer doesn't have to worry about passing a database object to each
new RDBO instance.
REGISTERED METHODS
This module registers the following methods into your application:
rdb
A reference to the default Rose::DB database object.
$self->rdb->do_transaction(sub{ ... });
To access a database of different type or domain, use parameters:
my $db = $self->rdb( domain => 'production', type => 'readonly' );
$db->do_transaction( sub { ... } );
rdbo
A helper method, which prepares and returns a Rose::DB::Object child
class.
get '/author/:id' => sub {
my ( $self, $author_id ) = @_;
my $author = $self->rdbo('Author')->new( id => $author_id )->load;
return $author->as_tree;
};
Under the hood, the "rdbo" method looks for "MyApp::DB::Author",
assuming that the name of your application is "MyApp". A different
prefix may be specified via the "prefix" configuration option. Then, the
module is loaded, and if it does not have its own "init_db" method, one
is injected into it, containing the already initialized "Rose::DB"
object.
To understand the full benefit of this method, one should first make
themselves familiar with how RDBO objects are initialized. The RDBO docs
provide several ways to do that. One of them is to pass a "db" parameter
to each constructor.
my $item = MyDB::Item->new( db => ... );
If the "db" parameter is missing, RDBO will look for an "init_db"
method. The "rdbo" method described here initializes that behind the
scenes, so you don't have to worry about any of the above.
To access a database of different type or domain, use parameters:
my $author = $self->rdbo('Author', type => 'readonly')
->new( id => $author_id )
->load;
CONFIGURATION
The configuration of this module is very robust, and as such it may seem
a bit complicated in the beginning. Here is a list of all keys used:
source
Source is a hashref or an array of hashrefs, containing arguments for
the "register_db" in Rose::DB method. To give you an example, directly
copied from the RDB docs:
modules_init => {
RDBO => {
source => [
{
domain => 'development',
type => 'main',
driver => 'Pg',
database => 'dev_db',
host => 'localhost',
username => 'devuser',
password => 'mysecret',
server_time_zone => 'UTC',
}, {
domain => 'production',
type => 'main',
driver => 'Pg',
database => 'big_db',
host => 'dbserver.acme.com',
username => 'dbadmin',
password => 'prodsecret',
server_time_zone => 'UTC',
}
]
}
}
If you only have a single source, you may use a hashref as the "source"
value.
default_type
Specifies a value for "default_type" in Rose::DB.
default_domain
Specifies a value for "default_domain" in Rose::DB.
modules_init => {
RDBO => {
default_type => 'main',
default_domain => 'development'
}
};
prefix
Specifies the prefix for your RDBO classes. If missing, it will use the
name of your application class, plus "::DB". For example, if your app
class is called "MyApp", then the default prefix will be "MyApp::DB".
modules_init => {
RDBO => {
prefix => 'RDBO::Nest'
}
};
# This will look for RDBO::Nest::Song now
$self->rdbo('Song')->new;
preload
Setting this option to a non-zero value will cause the module to load
all RDBO classes under the specified "prefix" at startup. It is advised
that you have this option on in your deployment config.
Preloading all modules may cause a noticeable delay after restarting the
web application. If you are impatient and dislike waiting for your
application to restart (like the author of this module), you are advised
to set this option to a false value in your development config.
LINK BACK TO APP
This module injects a new method "app" into "Rose::DB::Object", making
it available to all deriving classes. This method is a reference to the
application instance, and it can be accessed by all object classes that
inherit from "Rose::DB::Object". A typical example of when this is
useful is when you want to use other modules initialized by your app
inside an object class. The following example uses the
Kelp::Module::Bcrypt module to bcrypt the user password:
package MyApp::DB::User;
__PACKAGE__->meta->setup(
table => 'users',
auto => 1,
);
# Add a triger to column 'password' to bcrypt it when it's being set.
__PACKAGE__->meta->column('password')->add_trigger(
on_set => sub {
my $self = shift;
$self->password( $self->app->bcrypt( $self->password ) );
}
);
AUTHOR
Stefan G. minimal <at> cpan.org
SEE ALSO
Kelp, Rose::DB, Rose::DB::Object
LICENSE
Perl