Mailing List Archive

Catalyst design philosophy
i have some questions about general design philosophy with catalyst and
controllers.

i have spent the past week and a half porting my app from maypole to
catalyst 4.

to that end, i took some ideas from C::M::CDBI::CRUD, the Hops example, and
Maypole, and created my own M::CDBI::CRUD class that closely emulates
maypole's action dispatching.

other than login and logout, everything is dispatched through MyApp's
!default action.

'!default' => sub {
my ( $self, $c, $table) = @_;

my $model = $self->model;

# model->table_re returns qr/^(its|list|of|tables)$/
if ($table =~ $model->table_re) {
my $class = $model->loader->find_class($table);

# eat table from args before forwarding
shift @{ $c->req->args };
$c->forward( $class );

# check for table-specific template
if (my $t = $c->stash->{template}) {
if (-r $self->config->{root} . "/$table/$t") {
$c->stash->{template} = "$table/$t";
}
}
}
},


the model is grabbed from:

sub model {
my ($self) = @_;
return $self->comp( $self->config->{base_model} );
}


it works, but i'm not totally happy with it.

for one, the action is forwarded to the model class instead of a controller.
the model class's 'sub process' takes care of the rest of the dispacthing:

sub process {
my $self = shift;
my $c = shift;
my $method = shift || 'list';
$c->stash->{item} = $self->retrieve( $_[0] ) if $_[0];
$c->stash->{template} = $method;
$c->stash->{class} = ref $self || $self;
$self->$method( $c, @_ ) if $self->can($method);
}

since all of the table classes get inherited from this model, it is
inherently dangerous since a user can hit /myapp/atable/delete/1
(Class::DBI's delete) rather than /myapp/atable/destroy/1 (my CRUD's
destroy), since it happily calls any available method. i then override 'sub
MyApp::M::CDBI::ATable::list' etc to perform custom actions.

i suppose a single controller could handle the dispatching for the table
actions, limiting the 'if can($method)' problem, but it seems like i am
still missing out on the pluggability with controllers, especially seeing
the direction Cat5 is taking. also, how would the controller know what
tables have been loaded, and thus which url patterns to handle, if it is
separated thusly from the model class (that is, without grabbing a reference
to MyApp from its constructor, and going back through
$self->{myapp}->model->loader, and hoping the models got loaded first)?

my question is, how are others doing this sort of thing? should each table
have its own controller? or at least those tables that override their
list/destroy/etc methods?

thinking to the future when/if i have to convert this to Cat5 .. it looks
like in Cat5 you can't forward to another controller's default action. how
would a Cat5 controller know that it should handle /table/action/ for any
table without me creating redundant sub's for each table name or hard-coding
the list of tables into a :Regex action pattern?

all this confusion has me thinking i am approaching this all wrong from the
start, and i would like to get into the proper mindset before i get too much
further.

i welcome any comments, discussion, etc.

thanks.
michael.
Catalyst design philosophy [ In reply to ]
Am 09.04.2005 um 02:52 schrieb Michael Reece:
> my question is, how are others doing this sort of thing? should each
> table
> have its own controller? or at least those tables that override their
> list/destroy/etc methods?

I call this the Maypole syndrome... ;)
You try to wrap your application around a very restrictive crud
architecture, instead of just using MVC to make your life easier.
CRUD may seem easy and nice at first, but your application gets a messy
collection of hacks very fast.

Take a look at MiniMojo/MojoMojo to get some inspiration.

There is no restrictive philosophy behind Cat.
You just use Controllers to bundle actions that seem logical related.

>
> thinking to the future when/if i have to convert this to Cat5 .. it
> looks
> like in Cat5 you can't forward to another controller's default action.
> how
> would a Cat5 controller know that it should handle /table/action/ for
> any
> table without me creating redundant sub's for each table name or
> hard-coding
> the list of tables into a :Regex action pattern?

Every action gets a unique private address, so you can still forward to
everything.

>
> all this confusion has me thinking i am approaching this all wrong
> from the
> start, and i would like to get into the proper mindset before i get
> too much
> further.

Try to forget Maypole restrictions...

--
sebastian