Get rid of deprecated methods in Class::MOP (and depend on newest Moose)
[catagits/Reaction.git] / lib / Reaction / UI / Controller.pm
CommitLineData
7adfd53f 1package Reaction::UI::Controller;
2
d0736579 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) = @_;
14 my $newself = $self->new($self->_application, {%$self, context => $c, @args});
aca8cf99 15 weaken $newself->{context}; #stopgap till cat 5.8
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') {
30 if (my $conf_class = delete $vp_attr->{class}) {
31 $class = $conf_class;
32 }
504e2c44 33 %args = %{ $self->merge_config_hashes($vp_attr, {@proto_args}) };
7adfd53f 34 } else {
35 $class = $vp_attr;
36 %args = @proto_args;
37 }
38 } else {
39 %args = @proto_args;
40 }
41
42 $args{ctx} = $c;
43
44 if (exists $args{next_action} && !ref($args{next_action})) {
45 $args{next_action} = [ $self, 'redirect_to', $args{next_action} ];
46 }
47 $focus_stack->push_viewport($class, %args);
48}
49
50sub pop_viewport {
1810d302 51 return shift->context->stash->{focus_stack}->pop_viewport;
7adfd53f 52}
53
54sub pop_viewports_to {
55 my ($self, $vp) = @_;
1810d302 56 return $self->context->stash->{focus_stack}->pop_viewports_to($vp);
7adfd53f 57}
58
59sub redirect_to {
60 my ($self, $c, $to, $cap, $args, $attrs) = @_;
61
62 #the confess calls could be changed later to $c->log ?
63 my $action;
9cf5bc0b 64 my $reftype = ref($to);
65 if( $reftype eq '' ){
66 $action = $self->action_for($to);
67 confess("Failed to locate action ${to} in " . blessed($self)) unless $action;
68 } elsif($reftype eq 'ARRAY' && @$to == 2){ #is that overkill / too strict?
69 $action = $c->controller($to->[0])->action_for($to->[1]);
70 confess("Failed to locate action $to->[1] in $to->[0]" ) unless $action;
71 } elsif( blessed $to && $to->isa('Catalyst::Action') ){
72 $action = $to;
7adfd53f 73 } else{
9cf5bc0b 74 confess("Failed to locate action from ${to}");
7adfd53f 75 }
76
77 $cap ||= $c->req->captures;
78 $args ||= $c->req->args;
79 $attrs ||= {};
80 my $uri = $c->uri_for($action, $cap, @$args, $attrs);
81 $c->res->redirect($uri);
82}
83
747a1feb 84sub make_context_closure {
85 my($self, $closure) = @_;
86 my $ctx = $self->context;
db80cb74 87 weaken($ctx);
747a1feb 88 return sub { $closure->($ctx, @_) };
89}
90
7adfd53f 911;
f2756356 92
93__END__;
94
95=head1 NAME
96
63bb30b4 97Reaction::UI::Controller - Reaction Base Controller Class
98
99=head1 SYNOPSIS
100
101 package MyApp::Controller::Foo;
102 use strict;
103 use warnings;
104 use parent 'Reaction::UI::Controller';
105
106 use aliased 'Reaction::UI::ViewPort';
107
108 sub foo: Chained('/base') Args(0) {
109 my ($self, $ctx) = @_;
110
111 $ctx->push_viewport(ViewPort,
112 layout => 'foo',
113 );
114 }
115
116 1;
f2756356 117
118=head1 DESCRIPTION
119
120Base Reaction Controller class. Inherits from:
121
122=over 4
123
124=item L<Catalyst::Controller>
125=item L<Catalyst::Component::ACCEPT_CONTEXT>
126=item L<Reaction::Object>
127
128=back
129
130=head1 METHODS
131
132=head2 push_viewport $vp_class, %args
133
f1cd5548 134Creates a new instance of the L<Reaction::UI::ViewPort> class
135($vp_class) using the rest of the arguments given (%args). Defaults of
136the action can be overridden by using the C<ViewPort> key in the
137controller configuration. For example to override the default number
138of items in a CRUD list action:
139
140__PACKAGE__->config(
141 action => {
142 list => { ViewPort => { per_page => 50 } },
143 }
144 );
145
146The ViewPort is added to the L<Reaction::UI::Window>'s FocusStack in
147the stash, and also returned to the calling code.
148
149Related items:
150
151=over
152
153=item L<Reaction::UI::Controller::Root>
154=item L<Reaction::UI::Window>
155
156=back
f2756356 157
158TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing
159
160=head2 pop_viewport
161
162=head2 pop_viewport_to $vp
163
f1cd5548 164Call L<Reaction::UI::FocusStack/pop_viewport> or
165L<Reaction::UI::FocusStack/pop_viewport_to> on
166the C<< $c->stash->{focus_stack} >>.
f2756356 167
168=head2 redirect_to $c, $to, $captures, $args, $attrs
169
f1cd5548 170Construct a URI and redirect to it.
171
172$to can be:
173
174=over
f2756356 175
f1cd5548 176=item The name of an action in the current controller.
f2756356 177
f1cd5548 178=item A L<Catalyst::Action> instance.
179
180=item An arrayref of controller name and the name of an action in that
181controller.
182
183=back
f2756356 184
f1cd5548 185$captures and $args default to the current requests $captures and
186$args if not supplied.
f2756356 187
188=head1 AUTHORS
189
190See L<Reaction::Class> for authors.
191
192=head1 LICENSE
193
194See L<Reaction::Class> for the license.
195
196=cut