How can I enter a regex to match the first element in a Catalyst URI?

Background:

I use the CRUD structure in Catalyst, which automatically generates forms and lists for all tables in this database. For example: / admin / list / person or / admin / add / person or / admin / edit / person / 3 all dynamically generate pages or forms corresponding to the person table. (In other words, Admin.pm has actions that edit, list, add, delete, etc. that expect a table argument and possibly a row identification argument.)

Question:

In the specific application that I create, the database will be used by several clients, so I want to introduce a URI scheme, where the first element is the client identifier, and then the administrative action / table, etc.:

  • / cust1 / admin / list / person
  • / cust2 / admin / add / person
  • / cust2 / admin / edit / person / 3

This is for branding purposes, as well as to ensure that bookmarks or URLs passed from one user to another do the expected thing.

But I have a lot of problems getting this to work. I would prefer not to modify the children in the existing structure, so I tried to change the following options:

sub customer : Regex('^(\w+)/(admin)$') { my ($self, $c, @args) = @_; #validation of captured arg snipped.. my $path = join('/', 'admin', @args); $c->request->path($path); $c->dispatcher->prepare_action($c); $c->forward($c->action, $c->req->args); } 

But it just won't behave. I have used regular expressions many times, but putting one in the very first โ€œbarrelโ€ of a URI seems unusually traumatic. Any suggestions gratefully received.

+4
source share
2 answers

Do the client action: Chain, and then bind the administrator action to this. For instance:

 sub customer :Chained('/') :PathPart('') :CaptureArgs(1) { # load current customer into the stash } sub admin :Chained('customer') :PathPart('admin') :Args(0) { } 

For more information, see Catalyst :: DispatchType :: Chained

+3
source

I noticed Dimitar's answer as correct, because he put me on the right path to solve this problem. (I never needed to wait longer for FTM-Chained action.)

This is what I got in different controllers, for everyone who is interested.

 === Root.pm === sub customer_home : Path: Args(1) { # eg /cust1 my ($self, $c, $custarg) = @_; ... } sub ourclub :Chained('/') :PathPart('') :CaptureArgs(1) { # eg /cust1/<admin-function> my ($self, $c, $custarg) = @_; ... } === Admin.pm === use base 'Framework::Controller'; # create chained action versions of the framework actions sub admin :Chained('/customer') :PathPart('admin') { shift->SUPER::admin(@_) } sub list :Chained('/customer') :PathPart('list') { shift->SUPER::list(@_) } sub view :Chained('/customer') :PathPart('view') { shift->SUPER::view(@_) } sub add :Chained('/customer') :PathPart('add') { shift->SUPER::add(@_) } sub edit :Chained('/customer') :PathPart('edit') { shift->SUPER::edit(@_) } sub delete :Chained('/customer') :PathPart('delete') { shift->SUPER::delete(@_) } sub search :Chained('/customer') :PathPart('search') { shift->SUPER::search(@_) } sub model :Chained('/customer') :PathPart('model') { shift->SUPER::model(@_) } 

I had a red-hot move that dynamically generated all these submasters through *{$action} = eval "sub ..." and related ideas, but ultimately had to admit defeat.

+1
source

All Articles