Class::DBI is more a mapper from database to object set than the other way around. It's not an intrinsic limitation - it can work either way - but its assumptions and documentation don't fit nearly as well if your starting point is a class hierarchy and you want to express it in database form.

however, there are several ways that it could handle your example. You could do almost exactly what you describe, though i don't think it the best approach. something like this should work:

Package My::Hosts; use base qw(My::Class::DBI::Subclass); __PACKAGE__->table('hosts'); __PACKAGE__->columns(Primary => qw(ID)); __PACKAGE__->columns(Essential => qw(name IPAddress location OS)); Package My::MailServers; use base qw(My::Hosts); __PACKAGE__->columns(mailserver => qw(MTA version)); Package My::WebServers; use base qw(My::Hosts); __PACKAGE__->columns(webserver => qw(httpd version CGI));

which would allow you to use the same table for each class, and webservers would inherit host methods as i think you want. As a child of Schwern, its encapsulation is very sound.

however, that isn't the best way to use the module, nor - imho - a very good way to use the database. I'd probably use three tables and define many to one relationships linking webservers to hosts. You may after all have more than one webserver to describe for each host:

Package My::Hosts; use base qw(My::Class::DBI::Subclass); __PACKAGE__->table('hosts'); __PACKAGE__->columns(Primary => qw(ID)); __PACKAGE__->columns(Essential => qw(name IPAddress location OS)); __PACKAGE__->has_many('mailservers', 'My::MailServers', 'host'); __PACKAGE__->has_many('webservers', 'My::WebServers', 'host'); # has_many also defines a column in the foreign class: # in this case webserver->host # which returns the relevant Hosts object when called. Package My::MailServers; use base qw(My::Class::DBI::Subclass); __PACKAGE__->table('mailservers'); __PACKAGE__->columns(Primary => qw(ID)); __PACKAGE__->columns(Essential => qw(MTA version)); Package My::WebServers; use base qw(My::Class::DBI::Subclass); __PACKAGE__->table('webservers'); __PACKAGE__->columns(Primary => qw(ID)); __PACKAGE__->columns(Essential => qw(httpd version CGI mod_perl port h +ttps));

which is what Class::DBI does best. It will leave you with possibilities like this:

my $webserver = My::WebServers->retrieve($id); my $version = $webserver->version; my $ip = $webserver->host->IPAddress; my @mailservers_on_this_host = $webserver->host->mailservers; my @hosts_with_webservers = map { $_->host } My::WebServer->retrieve_a +ll; my @same thing = grep { $_->webservers } My::Hosts->retrieve_all; # ...

If defining relationships is going to be a pain on the input side - it sometimes is, if you're pulling data in from flat files, for example - then I think the official approach would be something like:

Package My::Hosts; use base qw(My::Class::DBI::Subclass); __PACKAGE__->table('hosts'); __PACKAGE__->columns(Primary => qw(ID)); __PACKAGE__->columns(Essential => qw(name IPAddress location OS)); __PACKAGE__->columns(mailserver => qw(MTA version)); __PACKAGE__->columns(webserver => qw(httpd version CGI)); __PACKAGE__->make_filter(mailservers => 'not MTA is NULL'); __PACKAGE__->make_filter(webservers => 'not httpd is NULL');

Which gives you a single table and reasonably efficient access to the various subsets of your data. I haven't really used it this way, though, and I'm not sure about using 'is NULL' in the filters - think it might be database dependent - but it does serve to demonstrate that there are many ways to do what you require.

The other thing I'd suggest is that you run a factory class in front of the set of data-mapping classes. it's not essential if you're working in a controlled setting, but it greatly adds to the flexibility of the app and makes it easier to grow, and becomes almost essential when you start to use templating systems for output. I've put together a Class::DBI::Factory and associated handler and pager modules that might make their way onto CPAN in a few days if they meet with the approval of the poop-group, but it has all gone a bit over the top in its efforts to be all things to all people, and something much simpler would suffice for the sort of example you've described.


In reply to Re: Inheritance, Class::DBI and POOP by thpfft
in thread Inheritance, Class::DBI and POOP by TGI

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.