[CDBI] Different subclasses for one table / Factory Pattern?

Oliver Jeeves oj at defuturo.co.uk
Wed Sep 13 13:53:43 BST 2006


Oliver Jeeves wrote:
> Oliver Jeeves wrote:
>> ...
>> However, this leads naturally to my next question; how do I achieve this
>> sort of thing?
>>
>> Currently, I'm thinking of having the base class call retrieve on the
>> derived class, which will probably mean extra DB lookups, but will
>> definatly work. Does anyone have a better solution?
>>
>> -Oli
> 
> Episode IV: A New Hope
> 
> It's been awfully quite on this list recently, where has everyone gone?
> 
> Anyway, I think I now have a working solution; override the construct
> method.
> 
> Looking at the internals of CDBI, it appears that all the constructors
> evenatually call construct (except, maybe, via iterators, but by this
> point I had gone cross eyed, so I'll leave this to someone else to
> check), so my approach is to override construct with a simple wrapper
> that just calls construct on the correct class.
> 
> Initially, this caused an infinite loop as the I was calling construct
> on a derived class which didn't define its own construct method. I got
> around this by calling SUPER::construct unless the class the method was
> called on was equal to __PACKAGE__.
> 
> So The code looks like this:
> 
> sub construct
> {
> 	my $proto	= shift; ## class or obj
> 	my $data	= shift;
> 	
> 	my $class = ref $proto || $proto;
> 	
> 	if ($class eq __PACKAGE__)
> 	{
> 		my $new_class =
> 			'My::Base::Class::' . $data->{'type'};
> 		return $new_class->construct($data);
> 	}
> 	else
> 	{
> 		return $proto->SUPER::construct($data);
> 	}
> }
> 
> In my code, the (Essential) DB column 'type' determines which subclass
> the object should be.
> 
> This means that my derived classes automatically inherit all the CDBI
> relationships from the base class, and can also add their own
> relationships, which you can't do if re-blessing a CDBI object after
> creation.
> 
> I hope this is of help for anyone trying to do something similar, and I
> hope that someone can point out any problems or potential pitfalls with
> this approach before I get myself into serious trouble!
> 
> -Oli

Episode V: The CDBI Strikes Back

Ok, great. Despite the documentation here:

http://search.cpan.org/~tmtm/Class-DBI/lib/Class/DBI.pm#has_a

claiming that a has_a relationship will call retrieve on CDBI objects to
inflate them, it does, infact, not do this at all.

Instead, it calls _simple_bless, which gives you an object containing
only the key value, blessed into the relevant class - bypassing
construct, and completely defeating my object factory.

What's more, subclassing and overriding methods to try and fix this is
made all the more difficult by the fact that it's a 'private' method in
HasA calling a 'private' method in CDBI, meaning that I can't rely on
the interface to stay the same between different versions of CDBI.

For now, my workaround has been to explicitly specify 'retrieve' as the
inflate method on the has_a relationships that use the object factory.
If anyone has a better idea, I'd like to hear it. In particular, can I
get has_a to retrieve the foreign object in the same SQL query that
retrieved its object?

I can understand why has_a calls _simple_bless (potentially avoids
superfluous SQL queries), but the fact that these methods are indicated
as being private (by the leading underscore), and the lack of any decent
documentation about its internals makes the interface to CDBI
increasingly annoying since it discourages any sort of interesting
specialisation in the subclasses.

-Oli

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: OpenPGP digital signature
Url : http://lists.digitalcraftsmen.net/pipermail/classdbi/attachments/20060913/3755d004/signature.pgp


More information about the ClassDBI mailing list