[cgiapp] Model design in C::A/Titanium

2008-09-23 Thread Richard Jones
I know we've been around here before in some related topics, but I would 
appreciate some feedback on a possible MVC structure for a 
Titanium/CGI::App that I am currently building.


I'm using CA::Dispatch to allow multiple apps with a small number of 
rm's each. Views are handled by CAP::TT. Just the Model aspect is 
proving a little challenging. I'm trying to ensure that all database 
calls are handled outside the controllers, and to this end am using a 
module called WebApp::Model


#
package WebApp::Model;

BEGIN {
  setmoduledirs('/path/to/app'); # Module::Find
  useall WebApp::DB; # Rose::DB::Object classes
}

sub new {
my $class = shift;
bless { }, $class;
}

sub get_foo { }
sub update_bar { }
sub delete_baz { }
#

WebApp::Model initially loads all WebApp::DB::* (Rose::DB::Object) 
classes, and is made available to the WebApp object via cgiapp_init:


#
sub cgiapp_init {
  my $c = shift;
  ..
  $c-param( 'model' = WebApp::Model-new );
}


Each controller run-mode uses $c-param( 'model') to get its data:

##
sub foo : Runmode { # CAP::AutoRunmode
  my $c = shift;
  ..
  my $data = $c-param('model')-get_foo;
}
##

This seems to work well, but the problem is that WebApp::Model is 
growing, as ever more (unrelated) db-related methods are added. Perhaps 
I could/should sub-class this one? Ideally I would move the 
WebApp::Model methods into their respective WebApp::DB class (eg 
get_foo() goes into WebApp::DB::Foo), but then I can't access it any 
longer from $c-param('model')-get_foo.


But the main question is whether this is the right approach to start 
with - stuffing WebApp::Model into the WebApp object and retrieving it 
in the run-modes via a param_name. Advantages include decoupling the 
model from the controllers - they don't know/care how get_foo() gets its 
data, and I can change the db-related stuff (eg RDBO = DBIC) without 
affecting the controllers. Disadvantage (so far) is lumping all methods 
into one (WebApp::Model) module. Comments  thoughts most welcome.

--
Richard Jones

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




[cgiapp] Re: Model design in C::A/Titanium

2008-09-23 Thread Mark Stosberg

Richard,

In your design, you have a single entry point to the model, as you
describe, this point is growing too large for comfort.

I think of the Model as a layer, made of up of potentially lots of
model modules.

In my own projects, these almost always end up looking like
CGI::Application plugins. That's because I want a few CGI::App methods
available to them, like 'query()', 'cfg()' and 'dbh()'

Sometimes it's cleaner to use completely separate objects, like Rose::DB
or CGI::Uploader.

If I'm going to use these repeatedly, I wrap them in their own little
wrapper class that simplifies initialization.  

This is much like some CGI::App plugins work, like Session plugin for
example.

And one other suggestion: If you find you are doing this a lot:

$c-param('model')

Go ahead and make a simple shortcut method for it, so you can just say

 $c-model;

It will be fast to create, cleans up your code, and gives you more
flexibility about implementation in the future. I suggest that as
someone who used param() in just the same way for some time.

Mark

-- 
 . . . . . . . . . . . . . . . . . . . . . . . . . . . 
   Mark StosbergPrincipal Developer  
   [EMAIL PROTECTED] Summersault, LLC 
   765-939-9301 ext 202 database driven websites
 . . . . . http://www.summersault.com/ . . . . . . . .



#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Model design in C::A/Titanium

2008-09-23 Thread Joshua Miller
On Tue, Sep 23, 2008 at 10:07 AM, Porta [EMAIL PROTECTED] wrote:


 Ideally I would move the WebApp::Model methods into their respective
 WebApp::DB class (eg get_foo() goes into WebApp::DB::Foo), but then I
 can't access it any longer from $c-param('model')-get_foo.

 I guess that I'm missing something here, because I don't see why you
 need to crowd all the models into a single one. You can still decouple
 the models from the controllers if every subclass of WebApp::DB knows
 how to interact with the database. Then, instead of

$c-param('mode')-get_foo();

 you'll do:

my $foo = WebApp::DB::Foo-new;
$foo-get_all();

 Where get_all is a sub inherited from WebApp::DB.


My 2 cents... I'd rather call it like so:

$c-model-foo-get()

Have a base class of WebApp::DB;
Have WebApp::DB::Foo inherit from base class;
Make the base class smart enough to auto-load WebApp::DB::Foo and
instantiate it when needed.
A little autoloader magic goes a long way, and you get to get rid of all the
get_foo stuff, and just do foo-get().

Using autoloader to only require in the subclasses when needed will also
keep memory usage down, as rarely used modules won't get loaded unless
they're actually called.

Here's a very basic example of that. I use something similar in a bunch of
my apps, but this snippet hasn't been tested on its own, so my apologies if
there's a typo :-)

sub AUTOLOAD
{
my $self = shift;
my $attr = $AUTOLOAD;
croak Undeclared subroutine call [$attr] unless ref($self);

$attr =~ s/.*:://;
return if $attr eq 'DESTROY';

# return already initialized object, if it exists
if (defined($self-{_objstash}{$attr}) 
ref($self-{_objstash}{$attr})) {
return $self-{_objstash}{$attr};
}

my $package = WebApp::DB::$attr;

# catch odd case of infinite loop
# (child class calling method in parent that calls a method in that
child class)
if (ref($self) eq $package) {
$self-{$attr} = $self;
weaken $self-{$attr};
return $self;
}

# instantiate object
unless (eval require $package) {
croak Unable to load module [$attr].;
}

my $obj = $package-new() or croak unable to instatiate [$attr].;
$self-{_objstash}{$attr} = $obj;
return $obj;
}


Help that helps,
--
Josh I.

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Model design in C::A/Titanium

2008-09-23 Thread Rhesa Rozendaal

Joshua Miller wrote:

On Tue, Sep 23, 2008 at 10:07 AM, Porta [EMAIL PROTECTED] wrote:


I guess that I'm missing something here, because I don't see why you
need to crowd all the models into a single one. You can still decouple
the models from the controllers if every subclass of WebApp::DB knows
how to interact with the database. Then, instead of

   $c-param('mode')-get_foo();

you'll do:

   my $foo = WebApp::DB::Foo-new;
   $foo-get_all();

Where get_all is a sub inherited from WebApp::DB.



My 2 cents... I'd rather call it like so:

$c-model-foo-get()



Or $c-model('Foo')-get();

rhesa

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Model design in C::A/Titanium

2008-09-23 Thread Michael Peters

Joshua Miller wrote:


Using autoloader to only require in the subclasses when needed will also
keep memory usage down, as rarely used modules won't get loaded unless
they're actually called.


Are you running under normal CGI (do people still do that?).

If not, and you're running on a good OS (one with copy-on-write memory) and you're using a forking 
environment (mod_perl, or most FastCGI implementations) you should pre-load all of you modules up 
front. This will actually decrease memory usage. Or course if you have a really, really rarely used 
module that is really, really big you might reconsider this advice. Unless I'm missing something?


--
Michael Peters
Plus Three, LP


#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Re: Model design in C::A/Titanium

2008-09-23 Thread Richard Jones

Hi Mark,

Appreciate the reply.

Mark Stosberg wrote:

And one other suggestion: If you find you are doing this a lot:

$c-param('model')

Go ahead and make a simple shortcut method for it, so you can just say

 $c-model;


Did you have something like this in mind:

sub model {
  my $c = shift;

  return $c-param('model');
}

Seems a bit, erm,  'trivial' ?

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Model design in C::A/Titanium

2008-09-23 Thread Joshua Miller
On Tue, Sep 23, 2008 at 4:09 PM, Michael Peters [EMAIL PROTECTED]wrote:

 Joshua Miller wrote:

  Using autoloader to only require in the subclasses when needed will also
 keep memory usage down, as rarely used modules won't get loaded unless
 they're actually called.


 Are you running under normal CGI (do people still do that?).

 If not, and you're running on a good OS (one with copy-on-write memory)
 and you're using a forking environment (mod_perl, or most FastCGI
 implementations) you should pre-load all of you modules up front. This will
 actually decrease memory usage. Or course if you have a really, really
 rarely used module that is really, really big you might reconsider this
 advice. Unless I'm missing something?


You're not missing anything. I'm running under mod_perl under linux boxen,
and do pre-load a ton of modules that are used often. It's a  million line
system though, so there's a whole lot that doesn't load frequently. The
pre-load all module is a good rule of thumb - it's a lot easier than
defining how many uses a day justifies pre-loading.

The above snippet can be updated to just do a use on all the module at the
top, and remove the require part... but that will also mean that it'll need
updated every time you add a new subclass. The above will automatically find
and use the new subclass, which makes it good generic code (IMHO). And you
can always put the pre-loads in a separate apache startup file anyway.

--
Josh I.

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




[cgiapp] Re: Model design in C::A/Titanium

2008-09-23 Thread Mark Stosberg

 Are you running under normal CGI (do people still do that?).

Yes. Some projects are small, use lightweight frameworks and templating
systems, like CGI::App and HTML::Template, and don't get a ton of traffic.
There is no reason to add the extra complication of persistent memory, or give
these applications dedicated, persistent memory when they don't need it.

Most of the projects I've deployed have been in CGI. (The rest in mod_perl). 

Mark

-- 
 . . . . . . . . . . . . . . . . . . . . . . . . . . . 
   Mark StosbergPrincipal Developer  
   [EMAIL PROTECTED] Summersault, LLC 
   765-939-9301 ext 202 database driven websites
 . . . . . http://www.summersault.com/ . . . . . . . .



#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Re: Model design in C::A/Titanium

2008-09-23 Thread Rhesa Rozendaal

Richard Jones wrote:

Hi Mark,

Appreciate the reply.

Mark Stosberg wrote:

And one other suggestion: If you find you are doing this a lot:

$c-param('model')

Go ahead and make a simple shortcut method for it, so you can just say

 $c-model;


Did you have something like this in mind:

sub model {
   my $c = shift;

   return $c-param('model');
}

Seems a bit, erm,  'trivial' ?


That may be trivial today, but it gives you the freedom to make it much 
smarter, without having to change the calling code. You can't do that if you 
have $c-param('model') littered around the code base.


rhesa

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] Re: Model design in C::A/Titanium

2008-09-23 Thread Joshua Miller
On Tue, Sep 23, 2008 at 5:45 PM, Richard Jones [EMAIL PROTECTED]wrote:

 Rhesa Rozendaal wrote:

 Did you have something like this in mind:

 sub model {
   my $c = shift;

   return $c-param('model');
 }

 Seems a bit, erm,  'trivial' ?


 That may be trivial today, but it gives you the freedom to make it much
 smarter, without having to change the calling code. You can't do that if you
 have $c-param('model') littered around the code base.


 Right. Thanks for that - I was really just checking I'd interpreted Marks
 suggestion correctly.

 Actually I quite like the idea of grouping associated db-related method
 calls into WebApp::Model::Foo, WebApp::Model::Bar, etc, but not sure what is
 the best way to get them into the call to $c-model, so I can call them as
 $c-model('Foo')-get_stuff, $c-model('Bar')-update_stuff, etc. Pointers
 appreciated.


lots of options for that, but this should cover the basic concept:
sub model {
my $c = shift;
my $subclass = shift or die Required attribute missing;

return $c-param(model::$subclass) if $c-param(model::$subclass);

my $obj = new MyApp::DB::$subclass-new();
$c-param(model::$subclass, $obj);
return $obj;
}
(most of the code from my previous post could also fit in here to avoid
infinite loops, and to automatically require the correct classes - tweak as
needed).

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




[cgiapp] RFC: declarative run modes (inspired by Method::Signatures)

2008-09-23 Thread Rhesa Rozendaal

Hi all,

Thanks to Schwern's recent work on Method::Signatures, something clicked with 
me. It looks like Devel::Declare (dangerous as it is) allows for very pretty 
syntactic sugar, without relying on source filters.



Inspired by Method::Signatures, I've been hacking on something specifically 
for use with cgiapp.


  package My::App;

  use base 'CGI::Application';
  use Runmode::Declare; # proof-of-concept name

  startmode hello { Hello }
  runmode world { $self-hello . , World! }

Most of the time, you won't need to call setup() anymore, because this takes 
care of setting the start/run modes for you.
Obviously, it checks that you only have one startmode. And it all works fine 
with inheritance too.



Using signatures:

  # script?rm=invite;party_id=42;names=larry;names=guido;names=matz

  runmode invite($party_id, @names) {
my $party = party_from_id($party_id);
$party-add_invitees(@names);
  }

  # somewhere else:
  $self-invite( 36, qw(me myself I) );

This pulls the named parameters from @_, or $self-query-param, or 
$self-param.


Rename the methods (probably silly, but it was easy and fun to try):

  use Runmode::Declare runmode = 'screen', startmode = 'splash';

  splash hello { Hello }
  screen world { World! }


Is anyone interested in seeing this on CPAN? Or should I just keep this to 
myself, and report back to the asylum? :-)



rhesa

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] RFC: declarative run modes (inspired by Method::Signatures)

2008-09-23 Thread Jason A. Crome
I was thinking that it would be cool just to use Method::Signatures  
with CGI::App, and I was also considering giving CAP::AutoRunmode a  
whirl, but this. this is cool enough to wait for ;)


Does this play nicely with CAP::Authen and CAP::Authz? (ie, will  
anything requiring sub attributes still work?)


Don't forget to make an errormode declaration either.

Great idea
Jason

On Sep 23, 2008, at 6:21 PM, Rhesa Rozendaal wrote:


Hi all,

Thanks to Schwern's recent work on Method::Signatures, something  
clicked with me. It looks like Devel::Declare (dangerous as it is)  
allows for very pretty syntactic sugar, without relying on source  
filters.



Inspired by Method::Signatures, I've been hacking on something  
specifically for use with cgiapp.


 package My::App;

 use base 'CGI::Application';
 use Runmode::Declare; # proof-of-concept name

 startmode hello { Hello }
 runmode world { $self-hello . , World! }

Most of the time, you won't need to call setup() anymore, because  
this takes care of setting the start/run modes for you.
Obviously, it checks that you only have one startmode. And it all  
works fine with inheritance too.



Using signatures:

 # script?rm=invite;party_id=42;names=larry;names=guido;names=matz

 runmode invite($party_id, @names) {
   my $party = party_from_id($party_id);
   $party-add_invitees(@names);
 }

 # somewhere else:
 $self-invite( 36, qw(me myself I) );

This pulls the named parameters from @_, or $self-query-param, or  
$self-param.



Rename the methods (probably silly, but it was easy and fun to try):

 use Runmode::Declare runmode = 'screen', startmode = 'splash';

 splash hello { Hello }
 screen world { World! }


Is anyone interested in seeing this on CPAN? Or should I just keep  
this to myself, and report back to the asylum? :-)



rhesa

#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####





#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




Re: [cgiapp] RFC: declarative run modes (inspired by Method::Signatures)

2008-09-23 Thread Rhesa Rozendaal

Jason A. Crome wrote:
I was thinking that it would be cool just to use Method::Signatures  
with CGI::App, and I was also considering giving CAP::AutoRunmode a  
whirl, but this. this is cool enough to wait for ;)


We're using AutoRunmode at work, and it rocks. It's even slightly better 
because you only need to add the use CAP::AutoRunmode line in your base 
class, and it'll work across all your subclasses. That's not the case with 
Method::Signatures (because the method keyword isn't a method itself).


Does this play nicely with CAP::Authen and CAP::Authz? (ie, will  
anything requiring sub attributes still work?)


No, it doesn't support attributes (yet): 
http://use.perl.org/~schwern/journal/37506

I actually asked the same question there, because I was hoping to be able to do:

   method foo :Runmode {}

using AutoRunmode, but that didn't work. So I rolled my own :)



Don't forget to make an errormode declaration either.


Right. I'll do that.


Great idea


Thanks :)


Jason



#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




[cgiapp] Re: RFC: declarative run modes (inspired by Method::Signatures)

2008-09-23 Thread Mark Stosberg
 Inspired by Method::Signatures, I've been hacking on something specifically 
 for use with cgiapp.
 
package My::App;
 
use base 'CGI::Application';
use Runmode::Declare; # proof-of-concept name
 
startmode hello { Hello }
runmode world { $self-hello . , World! }
 
 Most of the time, you won't need to call setup() anymore, because this takes 
 care of setting the start/run modes for you.
 Obviously, it checks that you only have one startmode. And it all works fine 
 with inheritance too.
 
 
 Using signatures:
 
# script?rm=invite;party_id=42;names=larry;names=guido;names=matz
 
runmode invite($party_id, @names) {
  my $party = party_from_id($party_id);
  $party-add_invitees(@names);
}
 
# somewhere else:
$self-invite( 36, qw(me myself I) );
 
 This pulls the named parameters from @_, or $self-query-param, or 
 $self-param.
 
 Is anyone interested in seeing this on CPAN? Or should I just keep this to 
 myself, and report back to the asylum? :-)

I agree this code is attractive and elegant. (And I hope it also provides
$self or $c) to run modes).  I would like to see on CPAN.

But having just looked at the scary guts of Devel::Declare, I don't expect
to use it for real work soon. This just-filed bug report is the kind of thing
I worry about it:

http://rt.cpan.org/Public/Bug/Display.html?id=34417

Devel::Declare just became incompatible with the latest bleadperl, and
because of the deep C magic, I wouldn't be able to patch it myself, as I would
be for many other CPAN modules I use.

Still, I hope features like this make their way towards stability, and I
applaud and support your efforts to help towards that goal. Plus, it looks fun
to try!

A suggested alternate name:

 CGI::Application::Plugin::RunmodeDeclare;

Mark

-- 
http://mark.stosberg.com/




#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####




[cgiapp] CGI::Application::Server patches now peer reviewed and recommended (was: Re: ::Server vs ::Dispatch::Server: Worth having both?)

2008-09-23 Thread Mark Stosberg

 I realized that I left some of the original code commented out in the
 static-content.patch branch.  I cleaned it up, tested it again,
 updated the copy at http://shrimp.alerce.com/cgiapp, and have attached
 the cleaner copy here for posterity.

I've peer-reviewed all the patches here and recommend them all for inclusion,
with no further modifications. George has already included additional automated
tests for the key functionality. The only bit I see left to do is to update the
'Changes' file. 

( The mega patch applies cleanly and easily to the last release ). 

For the CGI::Application::Server maintainers, would it be helpful if we
published the patches to rt.cpan.org?

Mark

-- 
http://mark.stosberg.com/




#  CGI::Application community mailing list  
####
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp##
####
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:  http://cgiapp.erlbaum.net/ ##
####