[Catalyst] Re: Using model layers between Catalyst and DBIC

Jason Galea lists at eightdegrees.com.au
Tue Jan 10 06:18:12 GMT 2012


hehe.. you want layers, I got layers..

In addition to everything already mentioned I wanted to get Bread::Board in
on the act..

I've put Lecstor up on GitHub if you're interested along with a Catalyst
app that uses it. Neither really do much but boy is there a lot of
scaffolding! ..and all the tests pass! 8)

The basic hook-up is Catalyst -> Catalyst Models -> Bread::Board Containers
-> Lecstor App/Models -> DBIC and others.. decoupled like a broken bag o
marbles..

the Catalyst Models:
 - LecstorApp - application lifetime
 - LecstorModel - application lifetime
 - LecstorRequest - request lifetime
 - Lecstor - request lifetime

LecstorModel & LecstorRequest return Bread::Board containers.
LecstorApp returns a parameterized Bread::Board container
Lecstor grabs the first two and shoves them into the third to make another
Bread::Board container from which I get my app..

have I gone walkabout!?

https://github.com/lecstor/Lecstor

https://github.com/lecstor/Lecstor-Shop-Catalyst

comments welcome.

cheers,

J

On Tue, Jan 10, 2012 at 12:16 AM, Jason Galea <lists at eightdegrees.com.au>wr=
ote:

>
>
> On Mon, Jan 9, 2012 at 3:14 PM, Bill Moseley <moseley at hank.org> wrote:
>
>>
>>
>> On Monday, January 2, 2012, Jason Galea wrote:
>>
>>>
>>> I think I've added another layer but I'm not sure where you draw the
>>> line.. I have a model layer over DBIC pulling together related result
>>> classes under a single model class. Then the app? layer uses the model
>>> layer to get things done. So I'd probably have one "distribution" that =
is
>>> our DBIC wrapped in a model layer layer and use that in a number of app=
s..
>>> 8) Each app can then be used as the single model in a Catalyst app or
>>> script or whatever.. (I think I need more names for the parts..)
>>>
>>
>> Yes, where to draw the line is difficult to know.   I've only had a few
>> hours to work on this but already I feel like I'm reinventing Catalyst --
>> mostly because my model layer is pulling in much of the components that =
my
>> Catalyst app would normally do -- DBIC, caching, even some concept of the
>> "current user".   Access control is another topic.
>>
>
> The problem parts for me are DBIC and TT. I thought I could just set up
> the components as usual, then load my app with them but it get's tricky
> calling one component from another at setup time, although it all works
> fine if you instantiate the app per request. So now I'm connecting/creati=
ng
> those myself.
>
> For other things provided by plugins I'm working more with Catalyst so for
> caching I will probably have my app accept a cache object at construction
> and pass in the Catalyst cache. For Authentication I've created my own
> store and user for the Catalyst Authentication plugin and they use my app
> to do what they have to. I've also created a store for the session plugin
> which uses my app, so all-in-all my app can see/touch everything that
> Catalyst is doing, and I can still make use of all the Catalyst stuff
> available (hopefully).
>
>
>>
>>> I have "Sets" in lu of ResultSets and "Models" for Results. Although in
>>> most instances a Model will actually cover the usage of multiple Result=
s.
>>> Each Set gets the dbic schema object and knows it's resultset name. Each
>>> model has a data attribute which contains a dbic row object and "handle=
s"
>>> any methods I don't need to override via the Moose "handles" attribute
>>> attribute!?
>>>
>>> Set->create($hash) creates the dbic object and stuffs it into a model
>>> class and returns that.
>>>
>>
>> So you are mirroring DBICs class structure a bit.  I need to consider
>> that approach more as currently my model layer returns the DBIC row obje=
ct
>> directly.  So, I have something like this:
>>
>> my $user_model =3D Model::User->new;
>> my $new_user =3D $user->new_user( $user_data );
>>
>
>> Not as flexible as your approach but my goal currently is to just
>> abstract out the ORM so that Model::User can hide the specifics of the
>> database.   Actually, it's not that hard to do directly with DBIC, eithe=
r.
>>
>
> yeh, I decided a while back that DBIx::Class is complicated enough and I'm
> too lazy to keep trying to work out complicated solutions in the DBIC
> classes to do things I know I can do quickly and easily with regular Moose
> classes.. and I like having nice clean DBIC classes..
>
>
>>
>>
>>> Each result class that has a model class overrides it's inflate_result
>>> method which again stuffs the dbic row object into the model object so
>>> searches on the related dbic resultsets return my model objects.
>>>
>>
>> Can you show a code example of that?  I'm not sure I'm following why you
>> use that approach instead of having your layer on top of DBIC do that.
>>
>
>  and the exception to the rule.. I did have my Set classes (which I now
> refer to as Model Controllers) grabbing search results and looping throug=
h,
> inflating them all into my Model Instances but then I couldn't just grab a
> resultset if I needed to limit/restrict/whatever, and any search or find
> had to be put through that ringer. With inflate_result I know that no
> matter how I get the results they'll be instances of my model. create is
> the only thing that doesn't work for so my controller does the wrapping
> there.
>
> package Lecstor::Schema::Result::Person;
> use base qw/DBIx::Class/;
> __PACKAGE__->load_components(qw/ Core /);
> __PACKAGE__->table('person');
> __PACKAGE__->add_columns('id' ,'firstname','surname');
> __PACKAGE__->set_primary_key('id');
>
> sub inflate_result {
>     my $self =3D shift;
>     my $ret =3D $self->next::method(@_);
>     return unless $ret;
>     return Lecstor::Model::Instance::Person->new( _record =3D> $ret );
> }
>
> 1;
>
>
>>
>>>
>>> Each model class has a validation class based on.. Validation::Class and
>>> create & update run their input through that. If there are errors I stu=
ff
>>> the errors into a very basic exception object and return that. This way=
 I
>>> can return the same exception object no matter where the error comes fr=
om,
>>> eg a dbic exception..
>>>
>>
>> Yes, I'm doing something very similar where validation happens before the
>> method in the model and on validation errors and exception is thrown (if
>> you are on the Moose list you may have seen my example).
>>
>> Thanks for the feedback and the ideas,
>>
>
> no worries at all, happy to be able to provide it.
>
> cheers,
>
> J
>
>
>>
>>
>>
>> --
>> Bill Moseley
>> moseley at hank.org
>>
>> _______________________________________________
>> List: Catalyst at lists.scsys.co.uk
>> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
>> Searchable archive:
>> http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
>> Dev site: http://dev.catalyst.perl.org/
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20120110/ce96c=
e6b/attachment.htm


More information about the Catalyst mailing list