[Catalyst-commits] r14551 - trunk/examples/CatalystAdvent/root/2014

jnapiorkowski at dev.catalyst.perl.org jnapiorkowski at dev.catalyst.perl.org
Thu Dec 18 15:26:40 GMT 2014


Author: jnapiorkowski
Date: 2014-12-18 15:26:40 +0000 (Thu, 18 Dec 2014)
New Revision: 14551

Added:
   trunk/examples/CatalystAdvent/root/2014/18.pod
Log:
18

Added: trunk/examples/CatalystAdvent/root/2014/18.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2014/18.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2014/18.pod	2014-12-18 15:26:40 UTC (rev 14551)
@@ -0,0 +1,72 @@
+=head1 Redispatching to a public path
+
+=head1 Overview
+
+Catalyst provides well-known dispatch API methods such as C<< $c->forward >>, 
+C<< $c->go >> and C<< $c->visit >> to call/jump to from one controller action to 
+another from within controller code. However, these methods only accept private, 
+internal path arguments which could be completely different from the actual, publicly 
+exposed URL paths. This is especially true for applications with complex dispatch 
+logic, such as when C<:Chained> and C<:Regex> dispatch types are in play.
+
+If you need to be able to resolve the controller action associated with a real, 
+public URL, there isn't any straightforward way to do it. This actually makes sense 
+when you think about; dispatch rules apply to the request as a whole (not just the 
+URL), so the only way to observe the ultimate result of a fresh request from the 
+outside is to actually perform one.
+
+In many cases where this would come up you can just call 
+C<< $c->response->redirect($public_url) >>, which simply tells the client to make a 
+new request. If this isn't an option, and you really need to do it within the same 
+request, there are ways to "fake it" and get I<reasonably> close to what it would be.
+
+=head1 A public redispatch recipe 
+
+Since dispatch logic applies to a request, you must either create a new, simulated 
+request object, or modify the existing request object for the new URL you want to 
+dispatch to. The following method does the latter, along with some extra string 
+normalization (copied from L<RapidApp> code base):
+
+
+  sub redispatch_public_path {
+    my ($c, @args) = @_;
+    
+    my $path = join('/', at args);
+    $path =~ s/^\///; #<-- strip leading /
+    $path =~ s/\/$//; #<-- strip trailing leading /
+    $path =~ s/\/+/\//g; #<-- strip any double //
+    $path ||= '';
+    
+    $c->log->debug("Redispatching as path: $path") if ($c->debug);
+    
+    # Overwrite the 'path' in the request object:
+    $c->request->path($path);
+    
+    # Now call prepare_action again, now with the updated path:
+    $c->prepare_action;
+    
+    # Now forward to the new action. If there is no action,
+    # call $c->dispatch just for the sake of error handling
+    return $c->action ? $c->forward( $c->action ) : $c->dispatch;
+  }
+
+
+=head1 Caveats
+
+Keep in mind that this is only a I<simulated> public redispatch because the idea of 
+a I<real> redispatch - without a real request - doesn't actually make sense. You can't 
+know the result of a request that didn't happen just like you can't know if 
+Schrodinger's cat is still alive without opening the box.
+
+Before using this code, you should take a step back and ask yourself if you actually 
+really need it. There is a good chance the better solution is to rethink the aspects 
+of your design that led you to want to do it in the first place. There are legitimate 
+reasons to do this in certain situations (otherwise I wouldn't even be writing this 
+article), but it should never be your first choice.
+
+
+=head1 Author
+
+Henry Van Styn L<vanstyn at cpan.org|email:vanstyn at cpan.org>
+
+=cut




More information about the Catalyst-commits mailing list