Fwd: [Catalyst] Model--best practice help

J. Shirley jshirley at gmail.com
Mon Oct 6 19:21:28 BST 2008


I'm an idiot and don't know how to use my mail client.  Somehow this
got offlist, but it really is a good discussion...

---------- Forwarded message ----------
From: J. Shirley <jshirley at gmail.com>
Date: Mon, Oct 6, 2008 at 9:35 AM
Subject: Re: [Catalyst] Model--best practice help
To: bg271828 at yahoo.com


On Mon, Oct 6, 2008 at 9:08 AM, Dr. Jennifer Nussbaum
<bg271828 at yahoo.com> wrote:
> (things trimmed, and also you replied to me personally but not the list, dont know if that was intentional)
>
>
>
> --- On Mon, 10/6/08, J. Shirley <jshirley at gmail.com> wrote:
>
>>
>> > Jen
>>
>> My example -was- simple multiple inheritance.  That is what
>> the
>> multiple packages in "use base" does.
>>
>> >> use base qw/Catalyst::Model::DBIC::Schema
>> MyApp::Model::Book/;
>
> i understand that this was MI, but my point was that if i still have to call the "Cat" model class one way, and the schema model class the other
> way, it doesnt really help. What is need is to call a single model, regardless of what im doing.
>
> Putting it another way, it shouldnt matter to the *Cat* programmer whether a function is in the DBIC schema (like "search" or "find", or even something
> else thats customized in the schema class), or is in the Cat model class. The programmer should just be able to call $c->model('Book') (or anything
> else that's regular).
>

[Full Stop]

If you want this, you can't use Catalyst::Model::DBIC::Schema at all.
It generates a model class for every schema class.

When you call $c->model('Book') what do you want to get back?  What is
MyApp::Model::Book?  What do you want it to be?  Do you want it to be
a MyApp::Model::DBIC::Book class (or whatever your Model::DBIC::Schema
generates as the name)?

>>
>> Eden posted a very simple Moose example to get you going
>> down that
>> path.  If you modified your lib/MyApp/Model/MyApp.pm to
>> inherit from
>> other classes (cat specific or not) then the methods from
>> those would
>> be accessible via
>> $c->model('MyApp')->whatever.  That's the
>> method I
>> showed.
>
> i understand that Edens example was simple and clear, and i do appreciate
> it. But it does still involve learning something about Moose, or in
> some cases convincing one's bosses that a project needs an entirely new OO layer to make it work.
>
>> Basically at this point, without knowing your exact
>> codeframework
>> you're only going to get these vague Multiple
>> Inheritance 101 answers.
>>  Just with or without Moose :)
>
> I appreciate the time youve spent on this, but i dont think its necessary to show my whole codebase. Let me try once more explain what i want to
> do, with a more specific example, then:
>
> Suppose i have a library application with the setup as described before, that is a DBIC schema group of classes set up and a MyApp::Model area.
>
> I want to write a method called get_books_by_purchase_date($foo), where
> $foo is some parameters taken from a Cat search form. In other words
> this function is clearly related to Cat, and not to the database layer,
> because it needs to do something related to my Cat app, and i wouldnt
> call it from an app thats not running on Cat.
>

If $foo is processed, I don't see why that isn't a resultset method, tbh.

$schema->resultset('Book')->get_books_by_purchase_date($criteria);
$c->model('Schema::Book')->get_books_by_purchase_date($criteria);

What is Catalyst specific is generating the search criteria, right?
Could you explain -why- you wouldn't call it from an application that
isn't Catalyst-based?  It seems that is would be a useful method on
the resultset later, and just an artificial restriction that it is
Catalyst-based (but again, don't know the role)

> Where do i put this function? If i put it in MyApp::Model::Books, then i
> have to remember that it's $c->model('Books')->get_books_by_purchase_date($foo), but it's
> $c->model('MyAppDB::Books')->find($id). That's a pain, especially if my real
> example is actually more complicated, and i want to (for instance) have the
> base of a chain that sets the model in the stash, and then in later parts of the chain
> do something based on the model, but i cant do these because for a given
> table i have two different models depending on whether im using a
> DBIC method or my own method.
>
> That is about the clearest i can be. If ive been misunderstanding you all along, i apologize.
>

Well, aside from not understand -why- you want to do it, the answer is
probably "Programming".  Right now you are using
Catalyst::Model::DBIC::Schema which simply creates a map of your
schema classes to a model class.  What you want is to decorate the
model class that is generated and add additional methods to it.  Not
to harp on Moose, but... Moose would make this -much- easier.

To start with, you'll want to read the source for
Catalyst::Model::DBIC::Schema, specifically just "sub new { }" --
there you will see how the model classes are instantiated.

The meat of it is just:
   foreach my $moniker ($self->schema->sources) {
       my $classname = "${class}::$moniker";
       *{"${classname}::ACCEPT_CONTEXT"} = sub {
           shift;
           shift->model($model_name)->resultset($moniker);
       }
   }

What this does is creates a Model::$Name that is simply a ResultSet.
At this point, what you -could- do, is set the resultset class to
something Catalyst specific.  That would give you methods on
$c->model("Schema::$Name").

So, something like:
sub {
   shift;
   my $schema = shift->model($model_name)->schema;
   my $source = $schema->source( $moniker );
   $source->resultset_class("MyApp::Custom::ResultSet");
   $source->resultset;
}

Now, every MyApp::Model::DBIC::* class would have the resultset
methods.  You could only apply this on certain monikers (moniker would
be 'Book', etc).

(I'm sure Eden or Matt can hop in here and do something better while I
go put on my pointy hair)



More information about the Catalyst mailing list