Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Add a method to a ResultSet Class in DBIx::Class?

by matija (Priest)
on Jan 09, 2008 at 11:47 UTC ( #661319=perlquestion: print w/ replies, xml ) Need Help??
matija has asked for the wisdom of the Perl Monks concerning the following question:

Oh glorious and incredibly patient fellow monks, can anybody please enlighten me how to add a method to a ResultSet class in DBIx::Class?

Here is what I'm trying to do:
package ThreadedDB::Article; use strict; use warnings; use base 'DBIx::Class'; __PACKAGE__->load_components("Core"); __PACKAGE__->table("article"); __PACKAGE__->add_columns( "id", { data_type => "INT", default_value => undef, is_nullable => 0, size + => 11 }, # etc, etc, etc ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->has_many( "article_texts", "ThreadedDB::ArticleText", { "foreign.article" => "self.id" }, ); # Created by DBIx::Class::Schema::Loader v0.04004 @ 2008-01-03 18:12:1 +2 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Y0WFrRSlgOqaz/fbhRt98A #package ThreadedDB::Article::ResultSet; #use base 'DBIx::Class::ResultSet'; sub insert_article { my ($self, $topic, $parent, $msgtext) = @_; my $articles = $self->resultset('Article'); eval { $self->txn_do (sub { # a complex operation that is not relevant yet }) }; } 1;

In other words, I'd like to find a way to put a method into the Article.pm file in such a way that I could access it by doing $schema->resultset('Article')->insert_article(...)

I've tried directly declaring the class (as commented out, above) but it didn't work. Either I'm misunderstanding what the resulting class should be called, or I'm misunderstanding something else.

I did read Re^2: [DBIX::Class] problem with Arbitrary SQL through a custom ResultSource, but it didn't help since the method I need contains a bunch of code (not all of which can be in SQL), and all of which should be done inside a transaction.

I'd be grateful for any pointers...

Comment on Add a method to a ResultSet Class in DBIx::Class?
Select or Download Code
Replies are listed 'Best First'.
Re: Add a method to a ResultSet Class in DBIx::Class?
by castaway (Parson) on Jan 09, 2008 at 14:35 UTC
    Almost there:
    __PACKAGE__->resultset_class('ThreadedDB::Article::ResultSet'); ## uncomment these package ThreadedDB::Article::ResultSet; use base 'DBIx::Class::ResultSet';
    (And don't forget that $self isa ResultSet after that)

    Done.

    C.

      My favorite often-overlooked method of avoiding having to set resultset_class on all your resultsets is to use load_namespaces instead of load_classes in your DBIx::Class::Schema subclass. For example, I usually set my schema up like this:

      # lib/MyDB.pm package MyDB; use strict; use warnings; use base qw( DBIx::Class::Schema ); __PACKAGE__->load_namespaces( default_resultset_class => 'ResultSet', ); 1; # lib/MyDB/ResultSet.pm package MyDB::ResultSet; use strict; use warnings; use base qw( DBIx::Class::ResultSet ); 1; # lib/MyDB/Result.pm package MyDB::Result; use strict; use warnings; use base qw( DBIx::Class ); __PACKAGE__->load_components(qw( FormFu InflateColumn::DateTime UUIDColumns Core )); 1;

      This way I have a custom base class for both resultsets and results, and if I create a new result class or a new resultset class, it will just work, without having to do anything extra.

      This also lets you add common functionality to your base classes, like I did with loading components I use everywhere in MyDB::Result. If you add custom functionality to your base MyDB::ResultSet class, that will get used whenever you don't have a specific resultset class for a given result class, which is handy for adding things like advanced searching to all your resultsets.

      # lib/MyDB/Result/Article.pm package MyDB::Result::Article; use strict; use warnings; use base qw( MyDB::Result ); __PACKAGE__->table( 'articles' ); __PACKAGE__->columns(qw( updated_time created_time ));

      Now, if I do this:

      my $schema = MyDB->connect( @connection_info ); my $article = $rs->schema( 'Article' )->new({});

      I'll get back a MyDB::Result::Article object that automatically has it's resultset_class set to MyDB::ResultSet. If I later decide I have functionality to add to the resultset just for articles (as you did), I can just create the new class and it will be detected automatically at startup.

      # lib/MyDB/ResultSet/Article.pm package MyDB::ResultSet::Article; use strict; use warnings; use base qw( MyDB::ResultSet ); sub insert_article { my ($self, $topic, $parent, $msgtext) = @_; eval { $self->txn_do( sub {} ) }; } 1;

      And now when doing my $article = $rs->schema( 'Article' )->new({});, the object I get back has it's resultset_class set to MyDB::ResultSet::Article instead, since there is a specific class for it now...


      We're not surrounded, we're in a target-rich environment!

      That's IT!

      It works now.


      Thank you!

Re: Add a method to a ResultSet Class in DBIx::Class?
by Corion (Pope) on Jan 09, 2008 at 11:58 UTC

    I have only done marginal work with DBIx::Class, but I think simply declaring the methods in the appropriate ResultSet subclass should work:

    package ThreadedDB::Article::ResultSet; #use base 'DBIx::Class::ResultSet'; sub insert_article { my ($self, $topic, $parent, $msgtext) = @_; my $articles = $self->resultset('Article'); eval { $self->txn_do (sub { # a complex operation that is not relevant yet }) }; }

    I left out the use base statement, because DBIx::Class will hopefully set up @ISA correctly when it's creating the subclasses.

      I left out the use base statement, because DBIx::Class will hopefully set up @ISA correctly when it's creating the subclasses.

      This only works automatically if you are using load_namespaces instead of load_classes from DBIx::Class::Schema, then they will be detected if they are named ThreadedDB::Result::Article and ThreadedDB::ResultSet::Article. If you aren't doing it this way, then the resultset_class will always be DBIx::Class::ResultSet, which you probably don't want to add things to...


      We're not surrounded, we're in a target-rich environment!

      Nope, that doesn't seem to be it:

      my $articles = $schema->resultset('ThreadedDB::Article'); DB<3> x $articles->can('create') 0 CODE(0x88b1cd4) -> &DBIx::Class::ResultSet::create in /usr/share/perl5/DBIx/Class/R +esultSet.pm:1625-1630 DB<4> x $articles->can('insert_article') 0 undef

        I forgot to say that in my first reply, sorry.

        If that namespace does not work, find out the real namespace of your resultset:

        warn ref ($schema->resultset('ThreadedDB::Article'));

        and then put your routines into that namespace, whatever it is.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://661319]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (10)
As of 2015-07-30 07:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (270 votes), past polls