[Catalyst] Dispatch matching more than the path?
Garrett Goebel
ggoebel at goebel.ws
Tue Aug 22 21:16:54 CEST 2006
On Aug 22, 2006, at 3:49 AM, Matt S Trout wrote:
> > Garrett Goebel wrote:
> >
> > I hacked something into the Path and Regex dispatchers to get
collective
> > matching on method and path working in the prototype.
>
> You shouldn't need to hack anything into these; just use a custom
ActionClass
> that overrides $action->match to introspect onto the request
method and
> anything else you need (this is already how :Args is handled, see the
> Catalyst::Action source for the implementation).
Thanks. I'd found the :Args code in Catalyst::Action last night and
managed to shoehorn the request method and path parameter matching
checks into it. How to subclass or override it was going to be my
next question. I'll check out using a custom ActionClass.
Last night I also sub-classed the Request class to add:
__PACKAGE__->mk_accessors(qw/path_parameters accept_extension/);
And I'm currently subclassing the Dispatcher to override
prepare_action in order to:
o remove uri path parameters from $c->request->path and add to
$c->request->path_parameters
o remove "file" extension from last path segment and add to
$c->request->accept_extension
o filter body parameters from using content_type implied by the
accept_extension (json, yaml, etc) and add to $c->request-
>parameters.
Perhaps I should consider just using the $c->request->content_type?
o check POST requests for hidden _method=DELETE|PUT parameter and
update
$c->request->method accordingly
These are all things I want to do once per request, not once per
action. Certainly there are better places to perform some of these
tasks. And I would like to hear any advice on the best place to
override catalyst for each. In the mean time, at least I've got a
proof of concept working.
My controller now is able to look like:
# GET http://foo.com/model
# GET http://foo.com/model.json
sub index :GET :Path('') Args(0) {
my ($self, $c) = @_;
my @models = grep { UNIVERSAL::can($c->model($_),
'result_source') }
$c->models;
$self->out($c, \@models);
1;
}
# GET http://foo.com/model/Person
sub show :GET :Path('') :Args(1) {
my ($self, $c, $model) = @_;
my @pkcols = $c->model($model)->result_source->primary_columns;
my @pk_tuples = map(
{ my $tuple = $_; csv_encode(map({ $tuple->$_ } @pkcols)) }
$c->model($model)->search(undef,
{columns => \@pkcols,
distinct => 1,
order_by => \@pkcols})
);
$self->out($c, \@pk_tuples);
1;
}
# GET http://foo.com/model/Person;edit
sub edit :GET :Path('') :PathParam(edit) :Args(1) {...}
# GET http://foo.com/model/Person;add
sub add :GET :Path('') :PathParam(add) :Args(1) {...}
# GET http://foo.com/model/Person;column_info
# GET http://foo.com/model/Person.yaml;column_info
sub show_column_info :GET :Path('') :PathParam(column_info) :Args(1) {
my ($self, $c, $model) = @_;
my $rs = $c->model($model)->result_source;
my %column_info = map { $_ => $rs->column_info($_)} $rs->columns;
$self->out($c, \%column_info);
1;
}
# POST http://foo.com/model/Person;new
sub create :POST :Path('') :PathParam(new) :Args(1) {...}
# PUT http://foo.com/model/Person/32
sub update :PUT :Path('') :Args(2) {...}
# DELETE http://foo.com/model/Person/32
sub destroy :DELETE :Path('') :Args(2) {...}
More information about the Catalyst
mailing list