Hi all,

Never used Rose::DB before, but I've heard enough good things about it
that I'm giving it a try.  Some of what I'm writing is probably clunky,
so pointers welcome.

I'm trying to provide my own metadata class and I've run into a problem
I don't quite understand.  Here's my base class:

  package Donhost::Model::Object;
 
  use strict;
  use warnings;

  use base qw(Rose::DB::Object);
  use Donhost::Model::Object::Metadata;

  use aliased 'Donhost::Model';

  Model->default_domain( $ENV{TESTING} ? 'test' : 'cp' );
 
  sub init_db { Model->new('main') }
        
  sub meta_class { 'Donhost::Model::Object::Metadata' } 

  sub is_public {}
  sub is_readonly {}

  1;

And here's my metadata class (the problem is in overriding the setup()
method):

  package Donhost::Model::Object::Metadata;
 
  use strict;
  use warnings;
 
  use base 'Rose::DB::Object::Metadata';
 
  sub overridden_methods {
      my $self  = shift;
      my $table = $self->table;
      return ( "delete_$table", "update_$table" );
  }
 
  sub make_manager_class {
      my $self  = shift;
      my $class = $self->class;
      if ( 1 == @_ && $class->is_readonly ) {
          my $result  = $self->SUPER::make_manager_class(@_);
          my $manager = $class . '::Manager';
 
          foreach my $method ( $self->overridden_methods ) {
              my $overridden = $manager . "::$method";
              no strict 'refs';
              no warnings 'redefine';
              *$overridden = sub {
                  require Carp;
                  Carp::confess(
                      "Manager method '$method' not allowed for
readonly objects"
                  );
              };
          }
          return $result;
      }
 
      # Assume they know what they are doing
      return $self->SUPER::make_manager_class(@_);
  }
 
  sub setup {
      my ( $self, %arg_for ) = @_;
      $self->SUPER::setup(%arg_for);
      foreach my $column ( $self->columns ) {
          my $name = $column->name;

          # here's the problem
          $self->alias_column( $name => "_$name" )
            unless $self->class->is_public($column);
      }
  }
 
  1;

The 'make_manager_class' probably has a better way of overriding
mutators to be read-only, but it's the 'setup' which is causing my
tests to fail.  If I comment out the 'alias_column' line, all is well. 
However, when I uncomment it, I get this:

not ok 26 - os died (load() - Can't locate object method "" via package
"" at /usr/local/lib/perl5/site_perl/5.8.7/Rose/DB/Object.pm line 1287

Here's the code which throws the error:

  can_ok 'Donhost::OS, 'load';
  ok Donhost::OS->load, '... and loading a valid OS should succeed';

Those come from the following two lines in the AUTOLOAD method (which
I'm surprised is called):

  $AUTOLOAD =~ /^(.+)::(\w+)$/;
  Carp::confess qq(Can't locate object method "$2" via package
"$1"$msg);

The value of $AUTOLOAD at that point is 'Donhost::OS::' and the code
which calls this (from the ->load() method)

    if($rows > 0)
    {
      my $methods = $meta->column_mutator_method_names_hash;

      # Empty existing object?
      #%$self = (db => $self->db, meta => $meta, STATE_LOADING() => 1);

      foreach my $name (@$column_names)
      {
        my $method = $methods->{$name};
        $self->$method($row{$name});
      }

So somehow, when aliasing a column, column_mutator_method_names_hash()
appears to return incorrect values or, perhaps, @$column_names is
getting incorrect values.  I'll dig into this more later, but if anyone
can offer insight, I'd appreciate it.

And for completeness, my Donhost::OS class:

  package Donhost::OS;
 
  use strict;
  use warnings;
 
  use base 'Donhost::Model::Object::Readonly';
 
  __PACKAGE__->meta->setup(
      table   => 'os',
      columns => [
          os => {
              type        => 'varchar',
              length      => 31,
              primary_key => 1,
              not_null    => 1
          },
          type         => { type => 'text', not_null => 1 },
          plan_part    => { type => 'text' },
          install_vlan => { type => 'text' },
          short_desc   => { type => 'text' },
          description  => { type => 'text' },
          upgrade_default => { type => 'tinyint', length => 1, default
=> 1 },
      ],
      unique_key => 'description',
  );        
 
  # XXX There should be a simpler way to push this into the base class.
 I have
  # an idea of how to do it, but for now, I'll table it.
  __PACKAGE__->meta->make_manager_class('os');
 
  1;

Note: the 'Readonly' class merely makes the mutators throw exceptions
if called.

Does anyone know what I'm doing wrong?  I think I'm using alias_column
as documented, but I'm scratching my head over this one.

Cheers,
Ovid

--

Buy the book -- http://www.oreilly.com/catalog/perlhks/
Perl and CGI -- http://users.easystreet.com/ovid/cgi_course/

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Rose-db-object mailing list
Rose-db-object@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rose-db-object

Reply via email to