X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FReaction%2FUI%2FController.pm;h=8ed781f70e8c4ad474b2f7fcb1d8c7973eea3d17;hb=a0ff2c8198d7cfcdefad1cbbaf339bd849a9c2c0;hp=a6ff6ef45487e3543ef41d2a68db244489328214;hpb=504e2c4437db6f0962d28334a7e2db036a1deaad;p=catagits%2FReaction.git diff --git a/lib/Reaction/UI/Controller.pm b/lib/Reaction/UI/Controller.pm index a6ff6ef..8ed781f 100644 --- a/lib/Reaction/UI/Controller.pm +++ b/lib/Reaction/UI/Controller.pm @@ -1,12 +1,19 @@ package Reaction::UI::Controller; -use base qw( - Catalyst::Controller - Catalyst::Component::ACCEPT_CONTEXT - Reaction::Object -); +use base qw(Catalyst::Controller); # Reaction::Object); use Reaction::Class; +use Scalar::Util 'weaken'; +use namespace::clean -except => [ qw(meta) ]; + +has context => (is => 'ro', isa => 'Object', weak_ref => 1); +with 'Catalyst::Component::InstancePerContext'; + +sub build_per_context_instance { + my ($self, $c, @args) = @_; + my $newself = $self->new($self->_application, {%$self, context => $c, @args}); + return $newself; +} sub push_viewport { my $self = shift; @@ -19,9 +26,7 @@ sub push_viewport { $vp_attr = $vp_attr->[0]; } if (ref($vp_attr) eq 'HASH') { - if (my $conf_class = delete $vp_attr->{class}) { - $class = $conf_class; - } + $class = $vp_attr->{class} if defined $vp_attr->{class}; %args = %{ $self->merge_config_hashes($vp_attr, {@proto_args}) }; } else { $class = $vp_attr; @@ -53,17 +58,17 @@ sub redirect_to { #the confess calls could be changed later to $c->log ? my $action; - if(!ref $to){ - $action = $self->action_for($to); - confess("Failed to locate action ${to} in " . $self->blessed) unless $action; - } - elsif( blessed $to && $to->isa('Catalyst::Action') ){ - $action = $to; - } elsif(ref $action eq 'ARRAY' && @$action == 2){ #is that overkill / too strict? - $action = $c->controller($to->[0])->action_for($to->[1]); - confess("Failed to locate action $to->[1] in $to->[0]" ) unless $action; + my $reftype = ref($to); + if( $reftype eq '' ){ + $action = $self->action_for($to); + confess("Failed to locate action ${to} in " . blessed($self)) unless $action; + } elsif($reftype eq 'ARRAY' && @$to == 2){ #is that overkill / too strict? + $action = $c->controller($to->[0])->action_for($to->[1]); + confess("Failed to locate action $to->[1] in $to->[0]" ) unless $action; + } elsif( blessed $to && $to->isa('Catalyst::Action') ){ + $action = $to; } else{ - confess("Failed to locate action from ${to}"); + confess("Failed to locate action from ${to}"); } $cap ||= $c->req->captures; @@ -73,13 +78,39 @@ sub redirect_to { $c->res->redirect($uri); } +sub make_context_closure { + my($self, $closure) = @_; + my $ctx = $self->context; + weaken($ctx); + return sub { $closure->($ctx, @_) }; +} + 1; __END__; =head1 NAME -Reaction::UI::Widget::Controller +Reaction::UI::Controller - Reaction Base Controller Class + +=head1 SYNOPSIS + + package MyApp::Controller::Foo; + use strict; + use warnings; + use parent 'Reaction::UI::Controller'; + + use aliased 'Reaction::UI::ViewPort'; + + sub foo: Chained('/base') Args(0) { + my ($self, $ctx) = @_; + + $ctx->push_viewport(ViewPort, + layout => 'foo', + ); + } + + 1; =head1 DESCRIPTION @@ -97,10 +128,29 @@ Base Reaction Controller class. Inherits from: =head2 push_viewport $vp_class, %args -Will create a new instance of $vp_class with the arguments of %args merged in with -any arguments in the ViewPort attribute of the current Catalyst action -(also accessible through the controller config), add it to the main FocusStack -(C<$c-Estash-E{focus_stack}>) and return the instantiated viewport. +Creates a new instance of the L class +($vp_class) using the rest of the arguments given (%args). Defaults of +the action can be overridden by using the C key in the +controller configuration. For example to override the default number +of items in a CRUD list action: + +__PACKAGE__->config( + action => { + list => { ViewPort => { per_page => 50 } }, + } + ); + +The ViewPort is added to the L's FocusStack in +the stash, and also returned to the calling code. + +Related items: + +=over + +=item L +=item L + +=back TODO: explain how next_action as a scalar gets converted to the redirect arrayref thing @@ -108,22 +158,68 @@ TODO: explain how next_action as a scalar gets converted to the redirect arrayre =head2 pop_viewport_to $vp -Shortcut to subs of the same name in the main FocusStack (C<$c-Estash-E{focus_stack}>) +Call L or +L on +the C<< $c->stash->{focus_stack} >>. =head2 redirect_to $c, $to, $captures, $args, $attrs -If C<$to> is a string then redirects to the action of the same name in the current - controller (C<$c-Econtroller> not C<$self>). +Construct a URI and redirect to it. + +$to can be: + +=over + +=item The name of an action in the current controller. + +=item A L instance. + +=item An arrayref of controller name and the name of an action in that +controller. + +=back + +$captures and $args default to the current requests $captures and +$args if not supplied. + +=head2 make_context_closure + +The purpose of this method is to prevent memory leaks. +It weakens the context object, often denoted $c, and passes it as the +first argument to the sub{} that is passed to the make_context_closure method. +In other words, + +=over 4 + +make_context_closure returns sub { $sub_you_gave_it->($weak_c, @_) + +=back + +To further expound up this useful construct consider code written before +make_context_closure was created: + + on_apply_callback => + sub { + $self->after_search( $c, @_ ); + } + ), + +This could be rewritten as: -If C<$to> isa L -it will pass the argument directly to C<$c-Euri_for>. + on_apply_callback => $self->make_context_closure( + sub { + my $weak_c = shift; + $self->after_search( $weak_c, @_ ); + } + ), -If C<$to> is an ArrayRef with two items it will treat the first as a Controller name -and the second as the action name whithin that controller. +Or even more succintly: -C<$captures>, C<$args>, and C<$attrs> are equivalent to the same arguments in -C. If left blank the current request captures and args will be used -and C<$attrs> will be passed as an empty HashRef. + on_apply_callback => $self->make_context_closure( + sub { + $self->after_search( @_ ); + } + ), =head1 AUTHORS