Fix NAME in POD
[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 " . blessed($self)) 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::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
101 merged in with any arguments in the ViewPort attribute of the current
102 Catalyst action (also accessible through the controller config), add
103 it to the main FocusStack (C<$c-E<gt>stash-E<gt>{focus_stack}>) and
104 return the instantiated viewport.
105
106 TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing
107
108 =head2 pop_viewport
109
110 =head2 pop_viewport_to $vp
111
112 Shortcut to subs of the same name in the main FocusStack (C<$c-E<gt>stash-E<gt>{focus_stack}>)
113
114 =head2 redirect_to $c, $to, $captures, $args, $attrs
115
116 If C<$to> is a string then redirects to the action of the same name  in the current
117  controller (C<$c-E<gt>controller> not C<$self>).
118
119 If C<$to> isa L<Catalyst::Action>
120 it will pass the argument directly to C<$c-E<gt>uri_for>.
121
122 If C<$to> is an ArrayRef with two items it will treat the first as a Controller name
123 and the second as the action name whithin that controller.
124
125 C<$captures>, C<$args>, and C<$attrs> are equivalent to the same arguments in
126 C<uri_for>. If left blank the current request captures and args will be used
127 and C<$attrs> will be passed as an empty HashRef.
128
129 =head1 AUTHORS
130
131 See L<Reaction::Class> for authors.
132
133 =head1 LICENSE
134
135 See L<Reaction::Class> for the license.
136
137 =cut