[Catalyst] Catalyst MVC Best Pratices

John Napiorkowski jjn1056 at yahoo.com
Thu May 3 20:24:37 GMT 2007


----- Original Message ----

From: Anthony Gardner <cyclewood_ltd at yahoo.co.uk>

To: catalyst at lists.rawmode.org

Sent: Thursday, May 3, 2007 6:22:12 PM

Subject: [Catalyst] Catalyst MVC Best Pratices



Greetings,



I've had a look at Catalyst and RoR from a basic point of view and like both. I'm also familiar with the concepts of MVC but again, from a basic point of view. I'm also busy learning design patterns etc. 



So, my head is full and maybe I can't see the wood for the trees in what I'm about to ask.



I'm 100% happy with what should go in the View part of MVC, 90% sure of what should go in the Controller and more than confused about what should go in the Model (not exactly true)



I searched the Catalyst mail archives about 'best practice' and came across this (amongst others) and read it in full



http://www.gossamer-threads.com/lists/catalyst/users/1081?search_string=best%20practice;#1081



......... leaving me not confused but with lots of questions.



I've already started my new application and I've set it up like this ...



lib/P4C/Controller/SelectProduct.pm

        /Model/Product.pm

   /P4CSchema/Product.pm (amongst others)

   /P4CSchema.pm

   /P4C.pm





Now, when selectproduct action is called, I want to select all products that match a criteria. In the Catalyst examples, this would be done simply as ........



$c->stash()->{products} = [$c->model('P4CSchema::Product)->all()];



and all would be happy in the world.



But, I might want to do some work on those results before stashing them away so, I may decide to do this in the Controller .......



my $prod = Model::Product->new();

$c->stash()->{products} = [ $prod->get_all_products_that_like_me() ];



and in Model::Product I'd have something like this (maybe)...



sub get_all_products_that_like_me() {

  my $self = shift;



  ## what's the use of schema in this command when it works okay without?

   ##$self->schema()->resultset('P4CSchema::ProductGroup')->all();

  my $prods = $self->resultset('P4CSchema::ProductGroup')->all();



  return $self->do_you_like_him( $prods );



}



But, is this the right place to put this logic as, I have read on the mailing list that people would use Model::* as a wrapper to the business logic code that is elsewhere.



So, would this be better (haven't thought this through because as I said, my head is too full) ? .............



lib/P4C/Controller/SelectProduct.pm

         /Model/Product.pm

   /P4CSchema/Product.pm (amongst others)

   /P4CSchema.pm

   /P4C.pm

   /Logic/Product.pm



and have in Model::Product one of.....



use base qw|Logic::Product Catalyst::Model::DBIC::Schema|; 

use base qw|Catalyst::Model::DBIC::Schema Logic::Product|;



and let Logic::Product do the  ....... 



sub get_all_products_that_like_me() {

  my $self = shift;



  ## what's the use of schema in this command when it works okay without?

  ##$self->schema()->resultset('P4CSchema::ProductGroup')->all();

  my $prods = $self->resultset('P4CSchema::ProductGroup')->all();



  return $self->do_you_like_him( $prods );



}



Is that's what meant by 'wrapper'?



Phew, okay, that's it for now. I have my flame pants on, so go ahead ;)



Many thanks



-Ants




Hi,

I think having a business logic and even an interface logic separate from the main catalyst application
is a good way to go.  I've been trying to keep the actually controllers really thin so that almost all of it
can be handled through action classes and configuration in the controller class.  That way the Models
are mostly a thin wrapper around business classes, maybe with some extra sugar or taking advantage
of the fact you can get the context for the few models that might actually value having the context.  This
way makes it a lot easier to test.

I favored Perl over Ruby because there are a lot of already done things in CPAN that you can glue into
a Catalyst model.  I tend to use models for both accessing and mutating data, kicking off processes
and doing data transformations.  Maybe that last sounds a little like a view but I'm comfortable using the
model for things like the command (GoF) pattern, and similar.

I really like the way the Mango (http://mangoframework.com/) author has separated data access into
Schema, Providers and then Catalyst Models.  I've been looking at that for inspiration.  Also the
Angerwhale project (http://search.cpan.org/~jrockway/Angerwhale-0.04/lib/Angerwhale.pm) has given me
a lot to think about in terms of arranging for data, although that is not currently database driven, yet the
way the framework is written there is no reason you couldn't add one.

One that you might want to stash a reference to your Resultset object rather than getting all the rows
out.  That way if your interface logic needs to perform view oriented things (like paging results) it's
much easier.

Creating solid custom exceptions is another thing worth figuring out.  There was some discussion about
this on a blog I saw but sadly I have that bookmarked on my other computer.

--John









__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 



More information about the Catalyst mailing list