[Catalyst-dev] Chained.pm and action choice

Gareth Kirwan gbjk at thermeoneurope.com
Wed Feb 14 15:54:36 GMT 2007


I encountered a problem recently with chained.
The actions are chosen on longest pathpart first, but only at each level of
recursion.
If there exists:
/foo/bar/one/two/*(1) and also
/foo/bar/*
then /foo/bar/* might get chosen because there is no test at that level of
which has the longest pathpart.

The solution to this, it seems to me, must not only store the captures for
each endpoint and chain, but also the pathparts of the endpoint itself, so
they can be compared later.

My solution:

--- Catalyst/Catalyst-Runtime/lib/Catalyst/DispatchType/Chained.old
2007-02-14 15:03:24.000000000 +0000
+++ Catalyst/Catalyst-Runtime/lib/Catalyst/DispatchType/Chained.pm
2007-02-14 15:42:13.000000000 +0000
@@ -101,7 +101,8 @@
 
     my @parts = split('/', $path);
 
-    my ($chain, $captures) = $self->recurse_match($c, '/', \@parts);
+    my ($chain, $captures, $parts) = $self->recurse_match($c, '/',
\@parts);
+    push @{$c->req->args}, @$parts;
 
     return 0 unless $chain;
 
@@ -126,6 +127,7 @@
     my ( $self, $c, $parent, $path_parts ) = @_;
     my $children = $self->{children_of}{$parent};
     return () unless $children;
+    my $best_action;
     my @captures;
     TRY: foreach my $try_part (sort { length($b) <=> length($a) }
                                    keys %$children) {
@@ -152,22 +154,28 @@
                 push(@captures, splice(@parts, 0, $capture_attr->[0]));
 
                 # try the remaining parts against children of this action
-                my ($actions, $captures) = $self->recurse_match(
+                my ($actions, $captures, $action_parts) =
$self->recurse_match(
                                              $c, '/'.$action->reverse,
\@parts
                                            );
                 if ($actions) {
-                    return [ $action, @$actions ], [ @captures, @$captures
];
+		    $best_action = { 	actions => [$action, @$actions],
+					captures=> [@captures, @$captures],
+					parts	=> $action_parts }
+			if (!$best_action || 
+			    $#$action_parts < $#{$best_action->{parts}});
                 }
             } else {
                 {
                     local $c->req->{arguments} = [ @{$c->req->args}, @parts
];
                     next TRY_ACTION unless $action->match($c);
                 }
-                push(@{$c->req->args}, @parts);
-                return [ $action ], [ ];
+		return [$action], [], \@parts;
             }
         }
     }
+    return $best_action->{actions},
+	   $best_action->{captures},
+	   $best_action->{parts} 	if $best_action;
     return ();
 }
 




More information about the Catalyst-dev mailing list