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

Joshua Miller unrtst at gmail.com
Tue Sep 23 15:32:36 EDT 2008


On Tue, Sep 23, 2008 at 10:07 AM, Porta <julian.porta at gmail.com> 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.


More information about the cgiapp mailing list