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

时间:2010-12-10 11:35:18

标签: perl catalyst

例如:

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

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

但我怎样才能匹配 www.domain.com/foo/21 www.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
}

由于

更新 根据Daxim的建议,我尝试使用:Regex

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

但这似乎不起作用;网址匹配,但$ 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 };
}

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

感谢大家的帮助和建议,我在Catalyst:D

中学到了很多关于处理网址的知识

2 个答案:

答案 0 :(得分: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}){
    # ...
  }
}

请注意,@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
}

答案 1 :(得分:2)

请参阅Catalyst::Manual::Intro#Action_types中的模式匹配(:Regex and :LocalRegex) 项。


尼克写道:

  

我不确定这是perl正则表达式问题还是Catalyst问题。有什么想法吗?

如何简单地尝试一下?

repl>>> $_ = '/foo/21/bar/56'
/foo/21/bar/56

repl>>> m|foo/(\d+)(?:/bar/(\d+))?|
$VAR1 = 21;
$VAR2 = 56;

repl>>> $_ = '/foo/21'
/foo/21

repl>>> m|foo/(\d+)(?:/bar/(\d+))?|
$VAR1 = 21;
$VAR2 = undef;