2010-12-10 41 views
1

Par exemple:Quelle est la meilleure façon de gérer les arguments url optionnels dans un contrôleur Catalyst?

Je sais comment faire correspondre www.domain.com/foo/21

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

Mais comment puis-je correspondre www.domain.com/foo/21 OU 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 
} 

Merci

Mise à jour: Suite à la suggestion de Daxim, j'ai essayé d'utiliser: Regex

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

Mais cela ne semble pas fonctionner; l'url correspond, mais $ bar_id est toujours undef. Si je supprime l'opperateur optionnel à la fin de la regex alors il saisit $ bar_id correctement, mais alors foo et la barre doivent être présents pour obtenir une correspondance d'URL. Je ne suis pas sûr si c'est un problème de perl regex, ou un problème de Catalyst. Des idées?

Mise à jour:

Comme le souligne Daxim sur, est un problème regex. Je ne vois pas pourquoi l'expression rationnelle ci-dessus ne fonctionne pas, mais j'ai réussi à en trouver un qui ne:

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

(je ne pas utiliser \ d + dans les captures comme Daxim a fait que mes ids peut-être pas être numérique)

Merci à tous pour l'aide et suggestions, j'ai appris beaucoup sur la gestion des urls Catalyst: D

Répondre

2

Voir l'article Motif match (:Regex and :LocalRegex) à Catalyst::Manual::Intro#Action_types.


nick écrit:

Je ne suis pas sûr que ce soit un problème de regex perl, ou un problème de catalyseur. Des idées?

Que diriez-vous simplement de l'essayer?

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; 
+0

Merci pour le pointeur daxim, mais je ne peux pas obtenir l'expression rationnelle optionnelle pour travailler - j'ai mis à jour la question avec les détails. – nick

+0

Oui, c'est un problème de regex - merci! J'ai mis à jour mon message avec le code de travail. – nick

9

L'attribut Args ne pas ont être limité à un certain nombre d'arguments. Par exemple, ce qui suit devrait fonctionner:

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}){ 
    # ... 
    } 
} 

Gardez à l'esprit que tous les des segments d'URL restants après le préfixe de chemin et le nom d'action sera présent dans @remainder. En outre, puisque vous ne spécifiez pas le nombre d'arguments dont vous avez besoin, Catalyst autorisera une URL sans argument pour correspondre à cette action. Validez votre saisie en conséquence!

mis à jour avec: exemple Chained

Les actions suivantes de catalyseur (non testé) vous fournira avec un peu d'action correspondant plus stricte que vous semblez être à la recherche. L'inconvénient est que vous devez compter sur le stockage pour partager des données entre toutes les actions.

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 
} 
+0

Cela correspondra aussi/foo/123/baz/456 ce qui n'est pas ce que je veux. – nick

+0

J'ai mis à jour avec une autre option. Peut-être que c'est plus proche de ce que vous cherchez. –

+0

Hmm, ce n'est pas tout à fait ce que je suis après. Je ne veux pas gérer les cas foo_no_bar et foo_and_bar comme des fonctions séparées, je veux seulement un bloc de code qui gère les deux cas. Je suppose que je pourrais avoir des fonctions séparées pour capturer les args et ensuite passer à une fonction commune, mais cela semble trop compliqué. – nick