[Catalyst] Mapping urls inside catalyst

Robert 'phaylon' Sedlacek rs at 474.at
Sat May 19 21:18:11 GMT 2007


Mark Zealey wrote:
> Hi,
> 
> I'm trying to work out the 'best way' of solving the following problem. 
> Basically, I want to have several entries into my application. One is of the 
> form /foo/<id> where id is an integer primary key. Another 
> is /bar/<other_key> where other_key is some string key, and another is via a 
> virtual host. I want them all to go into my MyApp::C::Foo:: namespace, but I 
> have multiple classes under there eg MyApp::C::Foo::Fred. I thus want the 
> following to be equivalent:
> 
> mysite.com/foo/5/fred/list
> mysite.com/bar/myname/fred/list
> othersite.com/fred/list

Is fred an argument or is he a part of the application? :)

> I was thinking I colud do this using Chained actions; but I don't know much 
> about them and the rest of the app is not using them - it's using :Local for 
> the most part.

Assuming that fred is an argument, I would implement:
  - a controller base class, that chains to a base action in the
    subclass:

      package MyApp::ControllerBase::Fred;
      use strict;
      use base 'Catalyst::Controller';

      # this gets the fred, ties to the 'load' action in the subclass
      sub load_fred: Chained('load') PathPart('') CaptureArgs(1) {
        my ($self, $c, $fred) = @_;
        $c->stash(fred => $fred);
      }

      sub list_fred: Chained('load_fred') PathPart('list') {
        ...
      }

      1;

  - different controllers for every type of invocation. these are the
    actions I would implement:

    in MyApp::Controller::Foo (load gets the id):
      sub base: Chained PathPart('foo') CaptureArgs(0) { ... }
      sub load: Chained('base') PathPart('') CaptureArgs(1) { ... }

    in MyApp::Controller::Bar (load gets the name):
      sub base: Chained PathPart('bar') CaptureArgs(0) { ... }
      sub load: Chained('base') PathPart('') CaptureArgs(1) { ... }

    in MyApp::Controller::ViaHost (load uses host to find the item):
      sub base: Chained PathPart('') CaptureArgs(0) { ... }
      sub load: Chained('base') PathPart('') CaptureArgs(0) { ... }

In any case, you could omit the base actions and load directly. I just
like the convention of naming the chained base action in a controller
'base.' All need to have their base class set to the one above.

This is all untested of course. But you should get the chains

  /foo/*/*/list - Foo::base, Foo::load, Fred::load_fred, Fred::list_fred
  /bar/*/*/list - Bar::base, Bar::load, Fred::load_fred, Fred::list_fred
  /*/*/list     - ViaHost::base, ViaHost::load, Fred::load_fred,
                  Fred::list_fred

If 'fred' is an action, but not an argument, just change the 'load_fred'
action to a simple chained action that tales no args. Make it a base if
it's just a namespace element. Maybe you should also consider putting
the chain that goes via the domain under another namespace, if fred is
indeed an argument, to avoid collisions.


.phaylon



More information about the Catalyst mailing list