Каков наилучший способ передать необязательные аргументы URL в контроллере 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
}
Спасибо
Обновление: следуя совету Даксима, я попытался использовать:Regex
sub foo : Regex('foo/(.+?)(?:/bar/(.+))?') {
my ( $self, $c ) = @_;
my ( $foo_id, $bar_id ) = @{ $c->req->captures };
}
Но это не похоже на работу; URL совпадает, но $ bar_id всегда undef. Если я удаляю опциональный оператор из конца регулярного выражения, то он правильно захватывает $ bar_id, но тогда должны присутствовать и foo, и bar, чтобы получить соответствие URL. Я не уверен, является ли это проблемой регулярного выражения Perl или проблемой Catalyst. Есть идеи?
Обновить:
Как указывает Даксим, это вопрос регулярных выражений. Я не могу понять, почему вышеприведенное регулярное выражение не работает, но мне удалось найти такое, которое работает:
sub foo : Regex('foo/([^/]+)(?:/bar/([^/]+))?') {
my ( $self, $c ) = @_;
my ( $foo_id, $bar_id ) = @{ $c->req->captures };
}
(Я не использовал \d+ в снимках, как Даксим, потому что мои идентификаторы не были числовыми)
Спасибо всем за помощь и предложения, я многое узнал об обработке URL в Catalyst:D
2 ответа
Посмотреть пункт Pattern-match(:Regex and :LocalRegex)
в Catalyst:: Manual:: Intro # Action_types.
Ник пишет:
Я не уверен, является ли это проблемой регулярного выражения 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;
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}){
# ...
}
}
Помните, что все оставшиеся сегменты URL после префикса пути и имени действия будут присутствовать в @remainder
, Кроме того, поскольку вы не указываете, сколько аргументов вам нужно, Catalyst разрешит 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
}