什么是在Catalyst控制器中处理可选url参数的最佳方法?

nic*_*ick 1 perl catalyst

例如:

我知道如何匹配www.domain.com/foo/21

sub foo : Path('/foo') Args(1) {
  my ( $self, $c, $foo_id ) = @_;
  # do stuff with foo
}
Run Code Online (Sandbox Code Playgroud)

但是如何匹配www.domain.com/foo/21www.domain.com/foo/21/bar/56

sub foo : <?> {
  my ( $self, $c, $foo_id, $bar_id ) = @_;
  # do stuff with foo, and maybe do some things with bar if present
}
Run Code Online (Sandbox Code Playgroud)

谢谢

更新: 根据Daxim的建议,我尝试使用:正则表达式

sub foo : Regex('foo/(.+?)(?:/bar/(.+))?') {
   my ( $self, $c ) = @_;
   my ( $foo_id, $bar_id ) = @{ $c->req->captures };
}
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用; 网址匹配,但$ bar_id始终为undef.如果我从正则表达式的末尾删除了可选的opperator,那么它会正确捕获$ bar_id,但是必须同时存在foo和bar才能获得url匹配.我不确定这是一个perl正则表达式问题,还是催化剂问题.有任何想法吗?

更新:

正如Daxim指出的那样,它是一个正则表达式问题.我不明白为什么上面的正则表达式不起作用,但我确实设法找到了一个:

sub foo : Regex('foo/([^/]+)(?:/bar/([^/]+))?') {
   my ( $self, $c ) = @_;
   my ( $foo_id, $bar_id ) = @{ $c->req->captures };
}
Run Code Online (Sandbox Code Playgroud)

(我没有像Daxim那样在捕获中使用\ d +,因为我的id可能不是数字)

感谢大家的帮助和建议,我在Catalyst:D中学到了很多关于处理网址的知识

Bri*_*ips 9

Args属性不具备局限于的参数的具体数量.例如,以下应该有效:

sub foo :Args() {    # matches /foo, /foo/123, /foo/123/bar/456, /foo/123/bar/456/*
  my($self, $c, $foo_id, %optional_params) = @_;
  if($optional_params{bar}){
    # ...
  }
}
Run Code Online (Sandbox Code Playgroud)

请记住,路径前缀和操作名称后面的所有剩余URL段都将出现在@remainder.此外,由于您没有指定所需的参数数量,因此Catalyst将允许没有任何args的URL匹配此操作.相应地验证您的输入!

更新:链式示例

以下(未经测试的)催化剂操作将为您提供一些您似乎正在寻找的更严格的动作匹配.缺点是您必须依靠存储来在所有操作之间共享数据.

sub foo :Chained('/') :PathPart :CaptureArgs(1) {
  my($self, $c, $foo_id) = @_;
  $c->stash->{foo_id} = $foo_id; # or whatever
}

sub foo_no_bar :Chained('foo') :Args(0) {
  my($self, $c) = @_;
  # matches on /foo/123 but not /foo/123/bar/456
  my $foo_id = $c->stash->{foo_id}; 
}

sub bar :Chained('foo') :PathPart :Args(1) {
  my($self, $c, $bar_id) = @_;
  my $foo_id = $c->stash->{foo_id};
  # matches on /foo/123/bar/456 but not /foo/123 or /foo/123/baz/456
}
Run Code Online (Sandbox Code Playgroud)