[Catalyst-commits] r14174 - trunk/examples/CatalystAdvent/root/2011/pen

lecstor at dev.catalyst.perl.org lecstor at dev.catalyst.perl.org
Fri Dec 2 13:27:24 GMT 2011


Author: lecstor
Date: 2011-12-02 13:27:24 +0000 (Fri, 02 Dec 2011)
New Revision: 14174

Added:
   trunk/examples/CatalystAdvent/root/2011/pen/lecstor_fat_model.pod
Log:
Lecstor's Fat Model

Added: trunk/examples/CatalystAdvent/root/2011/pen/lecstor_fat_model.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2011/pen/lecstor_fat_model.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2011/pen/lecstor_fat_model.pod	2011-12-02 13:27:24 UTC (rev 14174)
@@ -0,0 +1,101 @@
+=head1 Get fat this Christmas
+
+This Christmas do yourself a favour and get fat! with a fat model! what could be sweeter?
+
+Of course we're talking about a Catalyst Model as in Model, View, Controller. When I started using Catalyst and eventually got my head around all the parts and where they all fit in, the slot for my "business logic" seemed to be in the Controllers and I think that's a common assumption.
+
+The first thing that got my spidey sense tingling about this approach was when I realised I had multiple Actions with the same code. I'm very, very DRY so that bugged me a lot. Because I was in a Controller my first attempts at fixing this resulted in lots of forwarding between Actions both private and not.. this gets very messy, very quickly.
+
+Ok, so why not regular methods in the Controllers which are called from your Actions? This is a better solution wherever possible but I must admit it makes me feel icky.. a Controller is a place for Actions and for clarity, modularity, etc, I prefer to keep everything else out..
+
+To this end I looked to the model, the next (first?) obvious place to put these common methods. At this stage I was still trying to fit my code into Catalyst and made a couple of attempts at small Models for targeted functionality but then ran into issues from wanting access from one Model to another. At the same time I also discovered the issues involved in accessing Catalyst code from cron scripts and the like..
+
+ok, finally, my current solution? the fat Model. Essentially it's your whole app wrapped up in it's own nice "little" module..
+
+=head2 My App
+
+    package My::App;
+    use Moose;
+
+    has 'config'    => ( isa => 'My::App::Config', is => 'ro', required => 1 );
+
+    has 'schema'    => ( isa => 'DBIx::Class::Schema', is => 'ro', required => 1 );
+
+    has 'template' => ( isa => 'Template', is => 'ro' );
+
+    has 'visitor' => ( isa => 'My::App::Visitor', is => 'ro' );
+
+    has 'products' => ( isa => 'My::App::Products', is => 'ro', lazy_build => 1 );
+
+    sub _build_products{
+        My::App::Products->new({ schema => $_[0]->schema });
+    }
+
+With this as an entry point I can easily write a script which uses this class to access the full functionality of my app. I've also skipped a lot of coercing and auto-building in this example which you can use to make things even simpler.
+
+ok, but I thought we were talking about Models?
+
+=head2 My App Model
+
+    package My::Catalyst::Model::MyApp;
+    use Moose;
+    extends 'Catalyst::Model::Factory::PerRequest';
+
+    __PACKAGE__->config( class => 'My::App' );
+
+    # Instantiate the main app for each request.
+    sub prepare_arguments {
+        my ($self, $c) = @_;
+
+        my $args = $c->config->{'Model::MyApp'}{args};
+
+        $args->{template} = $c->view('TT')->template;
+        $args->{schema} = $c->model('DB')->schema;
+
+        $c->session unless $c->sessionid;
+
+        my $visitor = { session_id => $c->sessionid };
+        $visitor->{user} = $c->user if $c->user_exists;
+
+        $args->{visitor} = My::App::Visitor->new($visitor);
+
+        return $args;
+    }
+
+    no Moose;
+    __PACKAGE__->meta->make_immutable();
+
+    1;
+
+With this model in my Catalyst app I can now access my main app from wherever I need within the Catalsyt system via $c->model('MyApp'). I'm also reusing things that Catalyst makes simple like my database model and template object. I use the template object when creating system emails in my app and there's no reason to instantiate a new Template object each time, and I can set it up once and know the same instance will be used everywhere.
+
+=head2 My Controller
+
+    package My::Catalyst::Controller::Root;
+    use Moose;
+    use namespace::autoclean;
+
+    BEGIN { extends 'Catalyst::Controller' }
+
+    __PACKAGE__->config(namespace => '');
+
+    sub index : Local{
+        my ( $self, $c ) = @_;
+
+        my $app = $c->model('MyApp');
+        
+        $c->stash({
+            template => 'index.tt',
+            latest_products => $app->products->latest
+        });
+    }
+
+Now I can use Catalyst for all the wonderful things it makes so easy while keeping my main app nicely separated from it. Oh, and just quietly.. if the sky turned green and I needed to set up a quick Dancer or Mojolicious app I could do that quite easily too..
+
+cheers,
+
+-- J
+
+=head1 AUTHOR
+
+Jason Galea <jason at lecstor.com>




More information about the Catalyst-commits mailing list