File Coverage

blib/lib/Catalyst/Plugin/RedirectTo.pm
Criterion Covered Total %
statement 18 21 85.7
branch 6 14 42.8
condition n/a
subroutine 3 3 100.0
pod 2 2 100.0
total 29 40 72.5


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::RedirectTo;
2              
3 1     1   3067 use Moose::Role;
  1         2  
  1         8  
4              
5             requires 'response', 'uri_for', 'uri_for_action';
6              
7             our $VERSION = '0.002';
8             our $DEFAULT_REDIRECT_STATUS = 303;
9              
10             my $normalize_status = sub {
11             my @args = @_;
12             my $code = ref($args[-1]) eq 'SCALAR' ?
13             ${ pop @args } : $DEFAULT_REDIRECT_STATUS;
14              
15             die "$code is not a redirect HTTP status" unless $code =~m/^3\d\d$/;
16              
17             return ($code, @args);
18             };
19              
20             sub redirect_to {
21 4     4 1 434019 my $c = shift;
22 4         15 my ($code, @args) = $normalize_status->(@_);
23 4         79 $c->response->redirect(
24             $c->uri_for(@args), $code);
25             }
26              
27             sub redirect_to_action {
28 1     1 1 20328 my $c = shift;
29 1         6 my ($code, $action_proto, @args) = $normalize_status->(@_);
30              
31             # If its already an action object just use it.
32 1 50       7 return $c->uri_for($action_proto, @args)
33             if Scalar::Util::blessed($action_proto);
34              
35 1         9 my $controller = $c->controller;
36 1         88 my $action;
37 1 50       6 if($action_proto =~/\//) {
38 1 50       5 my $path = $action_proto=~m/^\// ? $action_proto : $controller->action_for($action_proto)->private_path;
39 1 50       4 die "$action_proto is not an action for controller ${\$controller->catalyst_component_name}" unless $path;
  0         0  
40 1 50       3 die "$path is not a private path" unless $action = $c->dispatcher->get_action_by_path($path);
41             } else {
42 0 0       0 die "$action_proto is not an action for controller ${\$controller->catalyst_component_name}"
  0         0  
43             unless $action = $controller->action_for($action_proto);
44             }
45 1 50       66 die "Could not create a URI from '$action_proto' with the given arguments" unless $action;
46 1         11 my $url = $c->uri_for($action, @args);
47 1         717 $c->response->redirect($url, $code);
48             }
49              
50             1;
51              
52             =head1 NAME
53              
54             Catalyst::Plugin::RedirectTo - Easier redirects to action objects or private paths.
55              
56             =head1 SYNOPSIS
57              
58             Use the plugin in your application class:
59              
60             package MyApp;
61             use Catalyst 'RedirectTo';
62              
63             MyApp->setup;
64              
65             Then you can use it in your controllers:
66              
67             package MyApp::Controller::Example;
68              
69             use base 'Catalyst::Controller';
70              
71             sub does_redirect_to :Local {
72             my ($self, $c) = @_;
73             $c->redirect_to( $self->action_for('target'), [100] );
74             }
75              
76             sub does_redirect_to_action :Local {
77             my ($self, $c) = @_;
78             $c->redirect_to_action( 'target', [100] );
79             }
80              
81             sub target :Local Args(1) {
82             my ($self, $c, $id) = @_;
83             $c->response->content_type('text/plain');
84             $c->response->body("This is the target action for $id");
85             }
86              
87             =head1 DESCRIPTION
88              
89             Currently if you want to setup a redirect in L<Catalyst> to an existing action the
90             proper form is somewhat verbose:
91              
92             $c->response->redirect(
93             $c->uri_for(
94             $c->controller(...)->action_for(...), \@args, \%q
95             )
96             );
97              
98             Which is verbose enough that i probably encourages people to do the wrong thing
99             and use a hard coded link path in the redirect request. This might later bite
100             you if you need to change your controllers and URL hierarchy.
101              
102             Also, for historical reasons the default redirect code is 302, which is considered
103             a temporary redirect, rather than 303 which is a better default for the common use
104             case of a form POST that generates a new resource. Which means to do the right
105             thing you really need:
106              
107             $c->response->redirect(
108             $c->uri_for(
109             $c->controller(...)->action_for(...), \@args, \%q
110             ),
111             303
112             );
113              
114             This plugin seeks to relieve some of the effort involved in doing the right thing.
115             It does this by creating a context method which encapulates the redirect response
116             setup (and sets a 303 by default, since that is the common case today) with a call
117             to 'uri_for' (or 'uri_for_action'). So instead of the above you can just do:
118              
119             $c->redirect_to($c->controller(...)->action_for(...), \@args, \%q);
120              
121             or even:
122              
123             $c->redirect_to_action('controller/action', \@args, \%q);
124              
125             Which hopefully is a good encapsulation of 'the right thing to do'!
126              
127             B<NOTE:> Please be aware that setting up a redirect does not automatically detach or
128             complete the action. You still should either return the redirect or call 'detach'
129             if you want to stop action processing.
130              
131             =head1 METHODS
132              
133             This plugin adds the following methods to your context
134              
135             =head2 redirect_to ($action_obj, \@args, \%query, \$code)
136              
137             Example:
138              
139             $c->redirect_to( $action_obj, \@args, \%query, \$code);
140              
141             Is shorthand for:
142              
143             $c->response->redirect(
144             $c->uri_for( $action_obj, \@args, \%query), $code);
145              
146             $code will default to 303 (not 302 as does $c->res->redirect) as this is commonly
147             supported in modern browsers, so unless you have a specific need for an alternative
148             response code, you should be able to just leave it off.
149              
150             For example:
151              
152             $c->redirect_to($self->action_for($action_name), \@args);
153              
154             Basically all the arguments to this method will be sent to ->uri_for, unless the
155             last argument is a scalar ref, in which case it will be used to set the HTTP status
156             code. $code must be '3xx' (a valid current or future redirect status).
157              
158             Does not detach or return the current action (just like the existing method)!
159              
160             B<NOTE:> Please notice that if you want to set a status code other than 303, that
161             code must be added to the argument list as a scalar ref. This is needed to
162             distinguish from an argument that gets passed to 'uri_for'.
163              
164             =head2 redirect_to_action
165              
166             Same as 'redirect_to' but submits the arguments to 'uri_for_action' instead.
167              
168             =head1 AUTHOR
169              
170             John Napiorkowski L<email:jjnapiork@cpan.org>
171            
172             =head1 SEE ALSO
173            
174             L<Catalyst>, L<Catalyst::Response>
175              
176             =head1 COPYRIGHT & LICENSE
177            
178             Copyright 2015, John Napiorkowski L<email:jjnapiork@cpan.org>
179            
180             This library is free software; you can redistribute it and/or modify it under
181             the same terms as Perl itself.
182            
183             =cut