Inherited relationships

From ClassDBI

Jump to: navigation, search

This problem was resolved in version 3.0.9 on Sep 23rd 2005, if you still encounter it re-open the bug and/or upgrade to a more recent version

-- Aaron Trevena

Cut & paste from https://rt.cpan.org/NoAuth/Bug.html?id=14878 and some rough edges cleaned up:

If you declare relationships in your base class and then again in a data class, the __meta_info hash will end up containing hash references that are shared among classes. This severely buggers up the relationship definitions, of course.

It's because this (in Class::DBI::_extend_meta):

   my %hash = %{ $class->__meta_info || {} };
   $hash{$type}->{$subtype} = $val;
   $class->__meta_info(\%hash);

dereferences the main metadata hash, but it doesn't dereference $hash{$type}. If there's already a hashref there - because we're inheriting from a class that defined a relationship of that type - then it will remain shared.

In short, if you define a has_a relationship in your base class then all the has_a relationships of all your classes will be assigned to all your classes. It isn't such an odd thing to do, either. I triggered the bug with this in a base class:

   __PACKAGE__->columns(DATE => qw( date cdate ));
   __PACKAGE__->has_a( date => 'Delivery::Machinery::Date' );
   __PACKAGE__->has_a( cdate => 'Delivery::Machinery::Date' );

which is true of all the classes in this particular application and useful to centralise.

The fix is easy, if a little bodgy. Just add an extra dereference to Class::DBI::_extend_meta:

   sub _extend_meta {
       my ($class, $type, $subtype, $val) = @_;
       my %hash = %{ $class->__meta_info || {} };
       my %subhash = %{ $hash{$type} || {} };
       $subhash{$subtype} = $val;
       $hash{$type} = \%subhash;
       $class->__meta_info(\%hash);
   }
Personal tools