[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