minor style cleanups and non-destructive config merging in Controller
[catagits/Reaction.git] / lib / Reaction / UI / Controller.pm
1 package Reaction::UI::Controller;
2
3 use base qw(
4   Catalyst::Controller
5   Catalyst::Component::ACCEPT_CONTEXT
6   Reaction::Object
7 );
8
9 use Reaction::Class;
10
11 sub push_viewport {
12   my $self = shift;
13   my $c = $self->context;
14   my $focus_stack = $c->stash->{focus_stack};
15   my ($class, @proto_args) = @_;
16   my %args;
17   if (my $vp_attr = $c->stack->[-1]->attributes->{ViewPort}) {
18     if (ref($vp_attr) eq 'ARRAY') {
19       $vp_attr = $vp_attr->[0];
20     }
21     if (ref($vp_attr) eq 'HASH') {
22       if (my $conf_class = delete $vp_attr->{class}) {
23         $class = $conf_class;
24       }
25       %args = %{ $self->merge_config_hashes($vp_attr, {@proto_args}) };
26     } else {
27       $class = $vp_attr;
28       %args = @proto_args;
29     }
30   } else {
31     %args = @proto_args;
32   }
33
34   $args{ctx} = $c;
35
36   if (exists $args{next_action} && !ref($args{next_action})) {
37     $args{next_action} = [ $self, 'redirect_to', $args{next_action} ];
38   }
39   $focus_stack->push_viewport($class, %args);
40 }
41
42 sub pop_viewport {
43   return shift->context->stash->{focus_stack}->pop_viewport;
44 }
45
46 sub pop_viewports_to {
47   my ($self, $vp) = @_;
48   return $self->context->stash->{focus_stack}->pop_viewports_to($vp);
49 }
50
51 sub redirect_to {
52   my ($self, $c, $to, $cap, $args, $attrs) = @_;
53
54   #the confess calls could be changed later to $c->log ?
55   my $action;
56   if(!ref $to){
57       $action = $self->action_for($to);
58       confess("Failed to locate action ${to} in " . $self->blessed) unless $action;
59   }
60   elsif( blessed $to && $to->isa('Catalyst::Action') ){
61       $action = $to;
62   } elsif(ref $action eq 'ARRAY' && @$action == 2){ #is that overkill / too strict?
63       $action = $c->controller($to->[0])->action_for($to->[1]);
64       confess("Failed to locate action $to->[1] in $to->[0]" ) unless $action;
65   } else{
66       confess("Failed to locate action from ${to}");
67   }
68
69   $cap ||= $c->req->captures;
70   $args ||= $c->req->args;
71   $attrs ||= {};
72   my $uri = $c->uri_for($action, $cap, @$args, $attrs);
73   $c->res->redirect($uri);
74 }
75
76 1;
77
78 __END__;
79
80 =head1 NAME
81
82 Reaction::UI::Widget::Controller
83
84 =head1 DESCRIPTION
85
86 Base Reaction Controller class. Inherits from:
87
88 =over 4
89
90 =item L<Catalyst::Controller>
91 =item L<Catalyst::Component::ACCEPT_CONTEXT>
92 =item L<Reaction::Object>
93
94 =back
95
96 =head1 METHODS
97
98 =head2 push_viewport $vp_class, %args
99
100 Will create a new instance of $vp_class with the arguments of %args merged in with
101 any arguments in the ViewPort attribute of the current Catalyst action
102 (also accessible through the controller config), add it to the main FocusStack
103 (C<$c-E<gt>stash-E<gt>{focus_stack}>) and return the instantiated viewport.
104
105 TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing
106
107 =head2 pop_viewport
108
109 =head2 pop_viewport_to $vp
110
111 Shortcut to subs of the same name in the main FocusStack (C<$c-E<gt>stash-E<gt>{focus_stack}>)
112
113 =head2 redirect_to $c, $to, $captures, $args, $attrs
114
115 If C<$to> is a string then redirects to the action of the same name  in the current
116  controller (C<$c-E<gt>controller> not C<$self>).
117
118 If C<$to> isa L<Catalyst::Action>
119 it will pass the argument directly to C<$c-E<gt>uri_for>.
120
121 If C<$to> is an ArrayRef with two items it will treat the first as a Controller name
122 and the second as the action name whithin that controller.
123
124 C<$captures>, C<$args>, and C<$attrs> are equivalent to the same arguments in
125 C<uri_for>. If left blank the current request captures and args will be used
126 and C<$attrs> will be passed as an empty HashRef.
127
128 =head1 AUTHORS
129
130 See L<Reaction::Class> for authors.
131
132 =head1 LICENSE
133
134 See L<Reaction::Class> for the license.
135
136 =cut