Rose-DB

 view release on metacpan or  search on metacpan

lib/Rose/DB.pm  view on Meta::CPAN

# - Rose::DB fixup rc file - YAML format

sub auto_load_fixups
{
  my($class) = shift;

  # Load a file full of fix-ups for the data sources (usually just passwords)
  # from a "well-known" (or at least "well-specified") location.
  my $fixup_file = $ENV{'ROSEDBRC'};
  $fixup_file = '/etc/rosedbrc'  unless(defined $fixup_file && -e $fixup_file);

  if(-e $fixup_file)
  {
    if(-r $fixup_file)
    {
      $class->load_yaml_fixup_file($fixup_file);
    }
    else
    {
      warn "Cannot read Rose::DB fixup file '$fixup_file'";
    }
  }

  # Load a file or package full of arbitrary Perl used to alter the data
  # source registry.  This is intended for use in development only.
  my $rosedb_devinit = $ENV{'ROSEDB_DEVINIT'};

  my $error;

  if(defined $rosedb_devinit)
  {
    if(-e $rosedb_devinit)
    {
      TRY:
      {
        local $@;
        do $rosedb_devinit;
        $error = $@;
      }
    }
    else
    { 
      TRY:
      {
        local $@;
        eval qq(require $rosedb_devinit);
        $error = $@;
      }

      if($rosedb_devinit->can('fixup'))
      {
        $rosedb_devinit->fixup($class);
      }
    }
  }

  if($error || !defined $rosedb_devinit)
  {
    my $username;

    # The getpwuid() function is often(?) unimplemented in perl on Windows
    TRY:
    {
      local $@;
      eval { $username = lc getpwuid($<) };
      $error = $@;
    }

    unless($error)
    {
      $rosedb_devinit = "Rose::DB::Devel::Init::$username";

      TRY:
      {
        local $@;
        eval qq(require $rosedb_devinit);
        $error = $@;
      }

      if($error)
      {
        TRY:
        {
          local $@;
          eval { do $rosedb_devinit };
          $error = $@;
        }
      }
      else
      {
        if($rosedb_devinit->can('fixup'))
        {
          $rosedb_devinit->fixup($class);
        }
      }
    }
  }
}

# YAML syntax example:
#
# ---
# production:
#  g3db:
#   password: mysecret
# ---
# mqa:
#  g3db:
#   password: myothersecret

our $YAML_Class;

sub load_yaml_fixup_file
{
  my($class, $file) = @_;

  my $registry = $class->registry;

  unless($YAML_Class)
  {
    my $error;

    TRY:
    {
      local $@;

lib/Rose/DB.pm  view on Meta::CPAN

      ...
    );

    My::DB->default_domain('dev');
    My::DB->default_type('main');

In one program, a C<My::DB> object is L<frozen|Storable/freeze> using L<Storable>:

    # my_freeze_script.pl

    use My::DB;
    use Storable qw(nstore);

    # Create My::DB object
    $db = My::DB->new(domain => 'dev', type => 'main');

    # Do work...
    $db->dbh->db('CREATE TABLE some_table (...)');
    ...

    # Serialize $db and store it in frozen_data_file
    nstore($db, 'frozen_data_file');

Now another program wants to L<thaw|Storable/thaw> out that C<My::DB> object and use it.  To do so, it must be sure to load the L<My::DB> module (which registers all its data sources when loaded) I<before> attempting to deserialize the C<My::DB> obje...

    # my_thaw_script.pl

    # IMPORTANT: load db modules with all data sources registered before
    #            attempting to deserialize objects of this class.
    use My::DB; 

    use Storable qw(retrieve);

    # Retrieve frozen My::DB object from frozen_data_file
    $db = retrieve('frozen_data_file');

    # Do work...
    $db->dbh->db('DROP TABLE some_table');
    ...

Note that this rule about loading a L<Rose::DB>-derived class with all its data sources registered prior to deserializing such an object only applies if the serialization was done in a different process.  If you L<freeze|Storable/freeze> and L<thaw|S...

=head1 ENVIRONMENT

There are two ways to alter the initial L<Rose::DB> data source registry.

=over 4

=item * The ROSEDB_DEVINIT file or module, which can add, modify, or remove data sources and alter the default L<domain|Rose::DB/domain> and L<type|Rose::DB/type>.

=item * The ROSEDBRC file, which can modify existing data sources.

=back

=head2 ROSEDB_DEVINIT

The C<ROSEDB_DEVINIT> file or module is used during development, usually to set up data sources for a particular developer's database or project.  If the C<ROSEDB_DEVINIT> environment variable is set, it should be the name of a Perl module or file.  ...

If the C<ROSEDB_DEVINIT> environment variable is not set, or if the specified file does not exist or has errors, then it defaults to the package name C<Rose::DB::Devel::Init::username>, where "username" is the account name of the current user.

B<Note:> if the L<getpwuid()|perlfunc/getpwuid> function is unavailable (as is often the case on Windows versions of perl) then this default does not apply and the loading of the module named C<Rose::DB::Devel::Init::username> is not attempted.

The C<ROSEDB_DEVINIT> file or module may contain arbitrary Perl code which will be loaded and evaluated in the context of L<Rose::DB>.  Example:

    Rose::DB->default_domain('development');

    Rose::DB->modify_db(domain   => 'development', 
                        type     => 'main_db',
                        database => 'main',
                        username => 'jdoe',
                        password => 'mysecret');

    1;

Remember to end the file with a true value.

The C<ROSEDB_DEVINIT> file or module must be read explicitly by calling the L<auto_load_fixups|/auto_load_fixups> class method.

=head2 ROSEDBRC

The C<ROSEDBRC> file contains configuration "fix-up" information.  This file is most often used to dynamically set passwords that are too sensitive to be included directly in the source code of a L<Rose::DB>-derived class.

The path to the fix-up file is determined by the C<ROSEDBRC> environment variable.  If this variable is not set, or if the file it points to does not exist, then it defaults to C</etc/rosedbrc>.

This file should be in YAML format.  To read this file, you must have either L<YAML::Syck> or some reasonably modern version of L<YAML> installed (0.66 or later recommended).  L<YAML::Syck> will be preferred if both are installed.

The C<ROSEDBRC> file's contents have the following structure:

    ---
    somedomain:
        sometype:
            somemethod: somevalue
    ---
    otherdomain:
        othertype:
            othermethod: othervalue

Each entry modifies an existing registered data source.   Any valid L<registry entry|Rose::DB::Registry::Entry> object method can be used (in place of "somemethod" and "othermethod" in the YAML example above).

This file must be read explicitly by calling the L<auto_load_fixups|/auto_load_fixups> class method I<after> setting up all your data sources.  Example:

    package My::DB;

    use Rose::DB;
    our @ISA = qw(Rose::DB);

    __PACKAGE__->use_private_registry;

    # Register all data sources
    __PACKAGE__->register_db(
      domain   => 'development',
      type     => 'main',
      driver   => 'Pg',
      database => 'dev_db',
      host     => 'localhost',
      username => 'devuser',
      password => 'mysecret',
    );

    ...



( run in 1.589 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )