[Dbix-class] accessor generator for has_a methods

David Kamholz davekam at pobox.com
Fri Jul 29 17:07:53 CEST 2005


Greetings,

Here's a bit of code I came up with with the help of mst this  
afternoon. It uses DBIx::Class's native api instead of the CDBI  
emulation layer and shows how you can create has_a relationships  
(including with multiple keys, including primary keys -- woohoo!) and  
create an accessor/mutator for it.

The relationship is created like so:

__PACKAGE__->add_relationship(table_id => 'Foreign::Class',  
{ 'foreign.table_id' => 'self.table_id' });
__PACKAGE__->add_relationship(item_id => 'Foreign::Class',
     { 'foreign.table_id' => 'self.table_id', 'foreign.item_id' =>  
'self.item_id' });

Where the first argument is the relationship name, the second the  
name of the foreign class, the third a hash showing the conditions  
under which it holds. Related elements to an object may be accessed  
through $self->search_related($relationship_name). In this case I've  
named the relationships the same as the most logical column to  
associate them with. Now to create the accessors you do something  
like this:

__PACKAGE__->mk_group_accessors('rel_single', [ table_id =>  
'table_id'], [ item_id => 'item_id' ],
     [ table_link_id => 'table_link_id' ], [ item_link_id =>  
'item_link_id' ]);

Where the first argument is the base for the accessor name, the first  
arg of each arrayref is the accessor name, and the second arg is the  
relationship name. DBIx::C will then call get_* and set_* subs for  
whatever accessor name was given. I have a decent implementation of  
get_rel_single:

sub get_rel_single {
     my ($self,$field) = @_;
     return wantarray ? $self->get_column($field) : ($self- 
 >search_related($field))[0];
}

I've been scratching my head a bit about how to know what value to  
return, here. If it's the context accessor->field, it is certainly  
scalar context and we want to be sure to return the first (and only  
in this case) related object. If it's something like ($obj- 
 >accessor, ... ) though, it's not so obvious. If we return an  
object, it will not necessarily stringify to the column the  
relationship was named for. Realistically, it's just not possible to  
always DWIM with this sort of accessor that overrides the plain  
column accessor. (Fortunately, DBIx::C permits you to be quite  
explicit and name your relationships and accessors however you want.)  
But some kind of clear default behavior would be good.

It wouldn't be so bad to always return an object. In CDBI this  
requires some kind of workaround to get at the real value of the  
field the relationship was based on, but DBIx::C always lets you do  
$self->get_column(field) without inflation. What do people think?

We should also standardize some sort of convenient api, a la CDBI  
has_a and has_many, for creating common relationship types and their  
comcomitant accessors and mutators. It would be nice to do this in a  
way that didn't leave multiple key relationships out of the picture,  
as that would be a nice improvement over CDBI.

Dave (ningu)



More information about the Dbix-class mailing list