allow redirect_to a url parameter
[catagits/Reaction.git] / lib / Reaction / UI / Controller.pm
CommitLineData
7adfd53f 1package Reaction::UI::Controller;
2
7f43bb45 3use base qw(Catalyst::Controller); # Reaction::Object);
1810d302 4
7adfd53f 5use Reaction::Class;
747a1feb 6use Scalar::Util 'weaken';
db80cb74 7use namespace::clean -except => [ qw(meta) ];
7adfd53f 8
d0736579 9has context => (is => 'ro', isa => 'Object', weak_ref => 1);
10with 'Catalyst::Component::InstancePerContext';
11
12sub build_per_context_instance {
13 my ($self, $c, @args) = @_;
987fc6e2 14 my $class = ref($self) || $self;
15 my $newself = $class->new($self->_application, {%$self, context => $c, @args});
d0736579 16 return $newself;
17}
18
7adfd53f 19sub push_viewport {
20 my $self = shift;
1810d302 21 my $c = $self->context;
22 my $focus_stack = $c->stash->{focus_stack};
7adfd53f 23 my ($class, @proto_args) = @_;
24 my %args;
7adfd53f 25 if (my $vp_attr = $c->stack->[-1]->attributes->{ViewPort}) {
26 if (ref($vp_attr) eq 'ARRAY') {
27 $vp_attr = $vp_attr->[0];
28 }
29 if (ref($vp_attr) eq 'HASH') {
59e40811 30 $class = $vp_attr->{class} if defined $vp_attr->{class};
504e2c44 31 %args = %{ $self->merge_config_hashes($vp_attr, {@proto_args}) };
7adfd53f 32 } else {
33 $class = $vp_attr;
34 %args = @proto_args;
35 }
36 } else {
37 %args = @proto_args;
38 }
39
40 $args{ctx} = $c;
41
42 if (exists $args{next_action} && !ref($args{next_action})) {
43 $args{next_action} = [ $self, 'redirect_to', $args{next_action} ];
44 }
45 $focus_stack->push_viewport($class, %args);
46}
47
48sub pop_viewport {
1810d302 49 return shift->context->stash->{focus_stack}->pop_viewport;
7adfd53f 50}
51
52sub pop_viewports_to {
53 my ($self, $vp) = @_;
1810d302 54 return $self->context->stash->{focus_stack}->pop_viewports_to($vp);
7adfd53f 55}
56
57sub redirect_to {
08c27c5b 58 my ($self, $c, $to, $cap, $args, $attrs, $domain) = @_;
7adfd53f 59
60 #the confess calls could be changed later to $c->log ?
61 my $action;
9cf5bc0b 62 my $reftype = ref($to);
63 if( $reftype eq '' ){
64 $action = $self->action_for($to);
65 confess("Failed to locate action ${to} in " . blessed($self)) unless $action;
66 } elsif($reftype eq 'ARRAY' && @$to == 2){ #is that overkill / too strict?
67 $action = $c->controller($to->[0])->action_for($to->[1]);
68 confess("Failed to locate action $to->[1] in $to->[0]" ) unless $action;
69 } elsif( blessed $to && $to->isa('Catalyst::Action') ){
70 $action = $to;
7adfd53f 71 } else{
9cf5bc0b 72 confess("Failed to locate action from ${to}");
7adfd53f 73 }
74
75 $cap ||= $c->req->captures;
76 $args ||= $c->req->args;
77 $attrs ||= {};
78 my $uri = $c->uri_for($action, $cap, @$args, $attrs);
08c27c5b 79 $uri->host($domain) if $domain;
7adfd53f 80 $c->res->redirect($uri);
81}
82
747a1feb 83sub make_context_closure {
84 my($self, $closure) = @_;
85 my $ctx = $self->context;
db80cb74 86 weaken($ctx);
747a1feb 87 return sub { $closure->($ctx, @_) };
88}
89
7adfd53f 901;
f2756356 91
92__END__;
93
94=head1 NAME
95
63bb30b4 96Reaction::UI::Controller - Reaction Base Controller Class
97
98=head1 SYNOPSIS
99
100 package MyApp::Controller::Foo;
101 use strict;
102 use warnings;
103 use parent 'Reaction::UI::Controller';
104
105 use aliased 'Reaction::UI::ViewPort';
106
107 sub foo: Chained('/base') Args(0) {
108 my ($self, $ctx) = @_;
109
110 $ctx->push_viewport(ViewPort,
111 layout => 'foo',
112 );
113 }
114
115 1;
f2756356 116
117=head1 DESCRIPTION
118
119Base Reaction Controller class. Inherits from:
120
121=over 4
122
123=item L<Catalyst::Controller>
124=item L<Catalyst::Component::ACCEPT_CONTEXT>
125=item L<Reaction::Object>
126
127=back
128
129=head1 METHODS
130
131=head2 push_viewport $vp_class, %args
132
f1cd5548 133Creates a new instance of the L<Reaction::UI::ViewPort> class
134($vp_class) using the rest of the arguments given (%args). Defaults of
135the action can be overridden by using the C<ViewPort> key in the
136controller configuration. For example to override the default number
137of items in a CRUD list action:
138
139__PACKAGE__->config(
140 action => {
141 list => { ViewPort => { per_page => 50 } },
142 }
143 );
144
145The ViewPort is added to the L<Reaction::UI::Window>'s FocusStack in
146the stash, and also returned to the calling code.
147
148Related items:
149
150=over
151
152=item L<Reaction::UI::Controller::Root>
153=item L<Reaction::UI::Window>
154
155=back
f2756356 156
157TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing
158
159=head2 pop_viewport
160
161=head2 pop_viewport_to $vp
162
f1cd5548 163Call L<Reaction::UI::FocusStack/pop_viewport> or
164L<Reaction::UI::FocusStack/pop_viewport_to> on
165the C<< $c->stash->{focus_stack} >>.
f2756356 166
167=head2 redirect_to $c, $to, $captures, $args, $attrs
168
f1cd5548 169Construct a URI and redirect to it.
170
171$to can be:
172
173=over
f2756356 174
f1cd5548 175=item The name of an action in the current controller.
f2756356 176
f1cd5548 177=item A L<Catalyst::Action> instance.
178
179=item An arrayref of controller name and the name of an action in that
180controller.
181
182=back
f2756356 183
f1cd5548 184$captures and $args default to the current requests $captures and
185$args if not supplied.
f2756356 186
b4e081f8 187=head2 make_context_closure
188
189The purpose of this method is to prevent memory leaks.
190It weakens the context object, often denoted $c, and passes it as the
191first argument to the sub{} that is passed to the make_context_closure method.
192In other words,
193
194=over 4
195
196make_context_closure returns sub { $sub_you_gave_it->($weak_c, @_)
197
198=back
199
200To further expound up this useful construct consider code written before
201make_context_closure was created:
202
203 on_apply_callback =>
204 sub {
205 $self->after_search( $c, @_ );
206 }
207 ),
208
209This could be rewritten as:
210
211 on_apply_callback => $self->make_context_closure(
212 sub {
213 my $weak_c = shift;
214 $self->after_search( $weak_c, @_ );
215 }
216 ),
217
218Or even more succintly:
219
220 on_apply_callback => $self->make_context_closure(
221 sub {
222 $self->after_search( @_ );
223 }
224 ),
225
f2756356 226=head1 AUTHORS
227
228See L<Reaction::Class> for authors.
229
230=head1 LICENSE
231
232See L<Reaction::Class> for the license.
233
234=cut