[Catalyst] uri_for() behaviour
Peter Karman
peter at peknet.com
Wed Oct 3 15:44:26 GMT 2007
Hi.
The refactor of uri_for() in recent Catalyst releases shows a big speed
improvement. Nice.
However, it revealed some abuses of uri_for() in my existing apps, which worked
previously ostensibly because uri_for() used URI internally.
For example, I often have this idiom in my code:
$c->uri_for('/', 'foo', 'bar');
In order to get 'http://myapp/foo/bar' returned. Now it needs to be:
$c->uri_for('/foo', 'bar');
to get the same return result.
Likewise, for external URIs I often did:
$c->uri_for('http://someplace', { foo => 'bar' });
to get 'http://someplace/?foo=bar' returned. Only now it returns
'http://myapp/http://someplace?foo=bar' which obviously is Not What I Meant.
The main reason I used uri_for() for external URIs was for the nice
uri-escaping features when dealing with params.
So now I have uri_for() overriden in my base class to catch these abuses and
carp about them so I can fix them. In the meantime, I mung the input values
before passing on to the core uri_for() so that my apps don't break.
Additionally, I realized I often do this:
$c->res->redirect( $c->uri_for( 'foo' ) );
Which is ok. But I realized it'd be nicer to do this:
$c->redirect( 'foo' );
in a way analogous to detach() or forward(), only using the external redirect
instead of the internal one.
So here's the code below that I am currently using. I wonder if redirect() has
a place in the core Catalyst API? I offer this only as a usability suggestion /
prompt for discussion. The code could probably be improved.
=head2 redirect( I<path>, I<params> )
Wrapper around the common idiom of response->redirect()
and uri_for().
=cut
sub redirect {
my ( $c, $path, @arg ) = @_;
my $uri;
if ( $path =~ m!^\w+://! ) {
$c->log->debug("external redirect: $path");
$uri = $c->external_uri_for( $path, @arg );
}
elsif ( $path eq '/' && @arg ) {
$c->log->debug("munging lone leading slash in redirect");
$arg[0] = join( '', $path, $arg[0] ) unless ref( $arg[0] );
$uri = $c->uri_for(@arg);
}
else {
$uri = $c->uri_for( $path, @arg );
}
$c->response->redirect($uri);
}
=head2 external_uri_for( I<uri>, I<args> )
Like uri_for() but for URIs outside the current application
(i.e., beginning with C<\w+://>).
=cut
sub external_uri_for {
my ( $c, $path, @arg ) = @_;
my $uri = $c->uri_for( $c, $path, @arg );
# remove the pre-pended base uri
my $base = join( '', $c->req->base, $c->namespace, '/' );
$c->log->debug("base URI appears to be $base") if $c->debug;
$uri =~ s,^$base,,;
return $uri;
}
--
Peter Karman . peter at peknet.com . http://peknet.com/
More information about the Catalyst
mailing list