1 package Reaction::UI::Controller;
4 use Scalar::Util 'weaken';
5 use namespace::clean -except => [ qw(meta) ];
7 BEGIN { extends 'Catalyst::Controller'; }
9 has context => (is => 'ro', isa => 'Object', weak_ref => 1);
11 'Catalyst::Component::InstancePerContext',
12 'Reaction::UI::Controller::Role::RedirectTo'
15 sub build_per_context_instance {
16 my ($self, $c, @args) = @_;
17 my $class = ref($self) || $self;
18 my $newself = $class->new($self->_application, {%{$self || {}}, context => $c, @args});
24 my $c = $self->context;
25 my $focus_stack = $c->stash->{focus_stack};
26 my ($class, @proto_args) = @_;
28 if (my $vp_attr = $c->stack->[-1]->attributes->{ViewPort}) {
29 if (ref($vp_attr) eq 'ARRAY') {
30 $vp_attr = $vp_attr->[0];
32 if (ref($vp_attr) eq 'HASH') {
33 $class = $vp_attr->{class} if defined $vp_attr->{class};
34 %args = %{ $self->merge_config_hashes($vp_attr, {@proto_args}) };
45 if (exists $args{next_action} && !ref($args{next_action})) {
46 $args{next_action} = [ $self, 'redirect_to', $args{next_action} ];
48 $focus_stack->push_viewport($class, %args);
52 return shift->context->stash->{focus_stack}->pop_viewport;
55 sub pop_viewports_to {
57 return $self->context->stash->{focus_stack}->pop_viewports_to($vp);
60 sub make_context_closure {
61 my($self, $closure) = @_;
62 my $ctx = $self->context;
64 return sub { $closure->($ctx, @_) };
73 Reaction::UI::Controller - Reaction Base Controller Class
77 package MyApp::Controller::Foo;
80 use parent 'Reaction::UI::Controller';
82 use aliased 'Reaction::UI::ViewPort';
84 sub foo: Chained('/base') Args(0) {
85 my ($self, $ctx) = @_;
87 $ctx->push_viewport(ViewPort,
96 Base Reaction Controller class, subclass of L<Catalyst::Controller>.
102 =item L<Catalyst::Component::InstancePerContext>
104 =item L<Reaction::UI::Controller::Role::RedirectTo>
106 Please not that this functionality is now deprecated.
112 =head2 push_viewport $vp_class, %args
114 Creates a new instance of the L<Reaction::UI::ViewPort> class
115 ($vp_class) using the rest of the arguments given (%args). Defaults of
116 the action can be overridden by using the C<ViewPort> key in the
117 controller configuration. For example to override the default number
118 of items in a CRUD list action:
122 list => { ViewPort => { per_page => 50 } },
126 The ViewPort is added to the L<Reaction::UI::Window>'s FocusStack in
127 the stash, and also returned to the calling code.
133 =item L<Reaction::UI::Controller::Root>
134 =item L<Reaction::UI::Window>
138 TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing
142 =head2 pop_viewport_to $vp
144 Call L<Reaction::UI::FocusStack/pop_viewport> or
145 L<Reaction::UI::FocusStack/pop_viewport_to> on
146 the C<< $c->stash->{focus_stack} >>.
148 =head2 redirect_to $c, $to, $captures, $args, $attrs
150 Construct a URI and redirect to it.
156 =item The name of an action in the current controller.
158 =item A L<Catalyst::Action> instance.
160 =item An arrayref of controller name and the name of an action in that
165 $captures and $args default to the current requests $captures and
166 $args if not supplied.
168 =head2 make_context_closure
170 The purpose of this method is to prevent memory leaks.
171 It weakens the context object, often denoted $c, and passes it as the
172 first argument to the sub{} that is passed to the make_context_closure method.
177 make_context_closure returns sub { $sub_you_gave_it->($weak_c, @_)
181 To further expound up this useful construct consider code written before
182 make_context_closure was created:
186 $self->after_search( $c, @_ );
190 This could be rewritten as:
192 on_apply_callback => $self->make_context_closure(
195 $self->after_search( $weak_c, @_ );
199 Or even more succintly:
201 on_apply_callback => $self->make_context_closure(
203 $self->after_search( @_ );
209 See L<Reaction::Class> for authors.
213 See L<Reaction::Class> for the license.