diff options
Diffstat (limited to 'lib/Reaction/UI/Controller/Role')
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/Create.pm | 145 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/Delete.pm | 145 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/DeleteAll.pm | 145 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/List.pm | 121 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/Object.pm | 108 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/Simple.pm | 134 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/Update.pm | 145 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/Action/View.pm | 111 | ||||
-rw-r--r-- | lib/Reaction/UI/Controller/Role/GetCollection.pm | 104 |
9 files changed, 1158 insertions, 0 deletions
diff --git a/lib/Reaction/UI/Controller/Role/Action/Create.pm b/lib/Reaction/UI/Controller/Role/Action/Create.pm new file mode 100644 index 0000000..f227ef8 --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/Create.pm @@ -0,0 +1,145 @@ +package Reaction::UI::Controller::Role::Action::Create; + +use Moose::Role -traits => 'MethodAttributes'; +use Reaction::UI::ViewPort::Action; + +requires qw/get_collection make_context_closure setup_viewport/; + +sub create :Action :Args(0) { + my ($self, $c) = @_; + my $target = $c->stash->{collection} || $self->get_collection($c); + my %vp_args = ( model => $target->action_for('Create') ); + + if( $self->can('on_create_apply_callback') ){ + my $apply = sub { $self->on_create_apply_callback( @_) }; + $vp_args{on_apply_callback} = $self->make_context_closure( $apply ); + } + if( $self->can('on_create_close_callback') ){ + my $close = sub { $self->on_create_close_callback( @_) }; + $vp_args{on_close_callback} = $self->make_context_closure( $close ); + } + + $self->setup_viewport( $c, \%vp_args ); +} + +around _build_action_viewport_map => sub { + my $orig = shift; + my $map = shift->$orig( @_ ); + $map->{create} = 'Reaction::UI::ViewPort::Action'; + return $map; +}; + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::Create - Create action + +=head1 DESCRIPTION + +Provides a C<create> action, which sets up an L<Action Viewport|Reaction::UI::Viewport::Action> +by calling C<action_for> on either the object located in the C<collection> slot +of the C<stash> or on the object returned by the method C<get_collection>. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::Create' + ); + + __PACKAGE__->config( action => { + create => { Chained => 'base' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + + sub on_create_apply_callback{ #optional callback + my($self, $c, $vp, $result) = @_; + ... + } + + sub on_create_close_callback{ #optional callback + my($self, $c, $vp) = @_; + ... + } + +=head1 ROLES CONSUMED + +This role also consumes the following roles: + +=over4 + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=back + +=head1 REQUIRED METHODS + +The following methods must be provided by the consuming class: + +=over4 + +=item C<get_collection> + +=item C<make_context_closure> + +=back + +=head1 ACTIONS + +=head2 create + +Chain endpoint with no args, sets up the viewport with the appropriate action. +If the methods C<on_create_apply_callback> and C<on_create_close_callback> are +present in the consuming class, they will be used as callbacks in the viewport. + +=head1 METHODS + +=head2 _build_action_viewport_map + +Extends to set the C<create> key in the map to L<Reaction::UI::ViewPort::Action> + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/Delete.pm b/lib/Reaction/UI/Controller/Role/Action/Delete.pm new file mode 100644 index 0000000..4dc1985 --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/Delete.pm @@ -0,0 +1,145 @@ +package Reaction::UI::Controller::Role::Action::Delete; + +use Moose::Role -traits => 'MethodAttributes'; +use Reaction::UI::ViewPort::Action; + +requires qw/make_context_closure setup_viewport/; + +sub delete :Action :Args(0) { + my ($self, $c) = @_; + my $target = $c->stash->{object}; + my %vp_args = ( model => $target->action_for('Delete') ); + + if( $self->can('on_delete_apply_callback') ){ + my $apply = sub { $self->on_delete_apply_callback( @_) }; + $vp_args{on_apply_callback} = $self->make_context_closure( $apply ); + } + if( $self->can('on_delete_close_callback') ){ + my $close = sub { $self->on_delete_close_callback( @_) }; + $vp_args{on_close_callback} = $self->make_context_closure( $close ); + } + + $self->setup_viewport( $c, \%vp_args ); +} + +around _build_action_viewport_map => sub { + my $orig = shift; + my $map = shift->$orig( @_ ); + $map->{delete} = 'Reaction::UI::ViewPort::Action'; + return $map; +}; + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::Delete - Delete action + +=head1 DESCRIPTION + +Provides a C<delete> action, which sets up an L<Action Viewport|Reaction::UI::Viewport::Action> +by calling C<action_for> on the object located in the C<object> slot of the +C<stash>. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::Object', + 'Reaction::UI::Controller::Role::Action::Delete' + ); + + __PACKAGE__->config( action => { + object => { Chained => 'base' }, + delete => { Chained => 'object' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + + sub on_delete_apply_callback{ #optional callback + my($self, $c, $vp, $result) = @_; + ... + } + + sub on_delete_close_callback{ #optional callback + my($self, $c, $vp) = @_; + ... + } + +=head1 ROLES CONSUMED + +This role also consumes the following roles: + +=over4 + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=back + +=head1 REQUIRED METHODS + +The following methods must be provided by the consuming class: + +=over4 + +=item C<make_context_closure> + +=back + +=head1 ACTIONS + +=head2 delete + +Chain endpoint with no args, sets up the viewport with the appropriate action. +If the methods C<on_delete_apply_callback> and C<on_delete_close_callback> are +present in the consuming class, they will be used as callbacks in the viewport. + +=head1 METHODS + +=head2 _build_action_viewport_map + +Extends to set the C<delete> key in the map to L<Reaction::UI::ViewPort::Action> + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/DeleteAll.pm b/lib/Reaction/UI/Controller/Role/Action/DeleteAll.pm new file mode 100644 index 0000000..797a835 --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/DeleteAll.pm @@ -0,0 +1,145 @@ +package Reaction::UI::Controller::Role::Action::DeleteAll; + +use Moose::Role -traits => 'MethodAttributes'; +use Reaction::UI::ViewPort::Action; + +requires qw/get_collection make_context_closure setup_viewport/; + +sub delete_all :Action :Args(0) { + my ($self, $c) = @_; + my $target = $c->stash->{collection} || $self->get_collection($c); + my %vp_args = ( model => $target->action_for('DeleteAll') ); + + if( $self->can('on_delete_all_apply_callback') ){ + my $apply = sub { $self->on_delete_all_apply_callback( @_) }; + $vp_args{on_apply_callback} = $self->make_context_closure( $apply ); + } + if( $self->can('on_delete_all_close_callback') ){ + my $close = sub { $self->on_delete_all_close_callback( @_) }; + $vp_args{on_close_callback} = $self->make_context_closure( $close ); + } + + $self->setup_viewport( $c, \%vp_args ); +} + +around _build_action_viewport_map => sub { + my $orig = shift; + my $map = shift->$orig( @_ ); + $map->{delete_all} = 'Reaction::UI::ViewPort::Action'; + return $map; +}; + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::DeleteAll - Delete All action + +=head1 DESCRIPTION + +Provides a C<delete_all> action, which sets up an L<Action Viewport|Reaction::UI::Viewport::Action> +by calling C<action_for> on either the object located in the C<collection> slot +of the C<stash> or on the object returned by the method C<get_collection>. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::DeleteAll' + ); + + __PACKAGE__->config( action => { + delete_all => { Chained => 'base' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + + sub on_delete_all_apply_callback{ #optional callback + my($self, $c, $vp, $result) = @_; + ... + } + + sub on_delete_all_close_callback{ #optional callback + my($self, $c, $vp) = @_; + ... + } + +=head1 ROLES CONSUMED + +This role also consumes the following roles: + +=over4 + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=back + +=head1 REQUIRED METHODS + +The following methods must be provided by the consuming class: + +=over4 + +=item C<get_collection> + +=item C<make_context_closure> + +=back + +=head1 ACTIONS + +=head2 delete_all + +Chain endpoint with no args, sets up the viewport with the appropriate action. +If the methods C<on_delete_all_apply_callback> and C<on_delete_all_close_callback> are +present in the consuming class, they will be used as callbacks in the viewport. + +=head1 METHODS + +=head2 _build_action_viewport_map + +Extends to set the C<delete_all> key in the map to L<Reaction::UI::ViewPort::Action> + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/List.pm b/lib/Reaction/UI/Controller/Role/Action/List.pm new file mode 100644 index 0000000..be15fd8 --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/List.pm @@ -0,0 +1,121 @@ +package Reaction::UI::Controller::Role::Action::List; + +use Moose::Role -traits => 'MethodAttributes'; +use Reaction::UI::ViewPort::Collection; + +requires qw/get_collection setup_viewport/; + +sub list :Action :Args(0) { + my ($self, $c) = @_; + my $collection = $c->stash->{collection} || $self->get_collection($c); + $self->setup_viewport($c, { collection => $collection }); +} + +around _build_action_viewport_map => sub { + my $orig = shift; + my $map = shift->$orig( @_ ); + $map->{list} = 'Reaction::UI::ViewPort::Collection'; + return $map; +}; + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::List - List action + +=head1 DESCRIPTION + +Provides a C<list> action, which sets up an L<Collection Viewport|Reaction::UI::Viewport::Collection> +using the collection contained in the C<collection> slot of the stash, if +present, or using the object returned by the method C<get_collection>. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::List' + ); + + + __PACKAGE__->config( action => { + list => { Chained => 'base' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + +=head1 ROLES CONSUMED + +This role also consumes the following roles: + +=over4 + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=back + +=head1 REQUIRED METHODS + +The following methods must be provided by the consuming class: + +=over4 + +=item C<get_collection> + +=back + +=head1 ACTIONS + +=head2 list + +Chain endpoint with no args, sets up the viewport with the appropriate action. + +=head1 METHODS + +=head2 _build_action_viewport_map + +Extends to set the C<list> key in the map to L<Reaction::UI::ViewPort::Action> + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/Object.pm b/lib/Reaction/UI/Controller/Role/Action/Object.pm new file mode 100644 index 0000000..95dbfbd --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/Object.pm @@ -0,0 +1,108 @@ +package Reaction::UI::Controller::Role::Action::Object; + +use Moose::Role -traits => 'MethodAttributes'; + +requires 'get_collection'; + +sub object :Action :CaptureArgs(1) { + my ($self, $c, $key) = @_; + if( my $object = $self->get_collection($c)->find($key) ){ + $c->stash(object => $object); + return $object; + } + $c->res->status(404); + return; +} + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::Object + +=head1 DESCRIPTION + +Provides an C<object> action, which attempts to find an item in a collection +and store it in the stash. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::Object', + ); + + __PACKAGE__->config( action => { + object => { Chained => 'base', PathPart => 'id' }, + foo_action => { Chained => 'object' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + + sub foo_action :Args(0){ + my($self, $c) = @_; + $c->stash->{object}; #object is here.... + } + +=head1 REQUIRED METHODS + +The following methods must be provided by the consuming class: + +=over4 + +=item C<get_collection> + +=back + +=head1 ACTIONS + +=head2 object + +Chain link, captures one argument. Attempts to find a single object by passing +the captured argument to the C<find> method of the collection returned by +C<get_collection>. If the object is found it is stored in the stash under the +C<object> key. + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/Simple.pm b/lib/Reaction/UI/Controller/Role/Action/Simple.pm new file mode 100644 index 0000000..bf5ba16 --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/Simple.pm @@ -0,0 +1,134 @@ +package Reaction::UI::Controller::Role::Action::Simple; + +use Moose::Role -traits => 'MethodAttributes'; + +requires 'push_viewport'; +requires 'merge_config_hashes'; + +has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); +has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1); + +sub _build_action_viewport_map { {} } + +sub _build_action_viewport_args { {} } + +sub setup_viewport { + my ($self, $c, $vp_args) = @_; + my $action_name = $c->stack->[-1]->name; + my $vp = $self->action_viewport_map->{$action_name}, + my $args = $self->merge_config_hashes( + $vp_args || {}, + $self->action_viewport_args->{$action_name} || {} , + ); + return $self->push_viewport($vp, %$args); +} + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::Simple + +=head1 DESCRIPTION + +Provides a C<setup_viewport> method, which makes it easier to setup and +configure a viewport in controller actions. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with 'Reaction::UI::Controller::Role::Action::Simple'; + + __PACKAGE__->config( + action_viewport_map => { bar => 'Reaction::UI::Viewport::Object' }, + action_viewport_args => { location => 'custom-location' }, + ); + + sub bar :Local { + my($self, $c) = @_; + my $obj = $self->get_collection($c)->find( $some_key ); + $self->setup_viewport($c, { model => $obj }); + } + +=head1 ATTRIBUTES + +=head2 action_viewport_map + +=over 4 + +=item B<_build_action_viewport_map> - Returns empty hashref by default. + +=item B<has_action_viewport_map> - Auto generated predicate + +=item B<clear_action_viewport_map>- Auto generated clearer method + +=back + +Read-write lazy building hashref. The keys should match action names in the +Controller and the value should be the ViewPort class that this action should +use. + +=head2 action_viewport_args + +Read-write lazy building hashref. Additional ViewPort arguments for the action +named as the key in the controller. + +=over 4 + +=item B<_build_action_viewport_args> - Returns empty hashref by default. + +=item B<has_action_viewport_args> - Auto generated predicate + +=item B<clear_action_viewport_args>- Auto generated clearer method + +=back + +=head1 METHODS + +=head2 setup_viewport $c, \%vp_args + +Accepts two arguments, context, and a hashref of viewport arguments. It will +automatically determine the action name using the catalyst stack and call +C<push_viewport> with the ViewPort class name contained in the +C<action_viewport_map> with a set of options determined by merging C<$vp_args> +and the arguments contained in C<action_viewport_args>, if any. + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/Update.pm b/lib/Reaction/UI/Controller/Role/Action/Update.pm new file mode 100644 index 0000000..6788e9c --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/Update.pm @@ -0,0 +1,145 @@ +package Reaction::UI::Controller::Role::Action::Update; + +use Moose::Role -traits => 'MethodAttributes'; +use Reaction::UI::ViewPort::Action; + +requires qw/make_context_closure setup_viewport/; + +sub update :Action :Args(0) { + my ($self, $c) = @_; + my $target = $c->stash->{object}; + my %vp_args = ( model => $target->action_for('Update') ); + + if( $self->can('on_update_apply_callback') ){ + my $apply = sub { $self->on_update_apply_callback( @_) }; + $vp_args{on_apply_callback} = $self->make_context_closure( $apply ); + } + if( $self->can('on_update_close_callback') ){ + my $close = sub { $self->on_update_close_callback( @_) }; + $vp_args{on_close_callback} = $self->make_context_closure( $close ); + } + + $self->setup_viewport( $c, \%vp_args ); +} + +around _build_action_viewport_map => sub { + my $orig = shift; + my $map = shift->$orig( @_ ); + $map->{update} = 'Reaction::UI::ViewPort::Action'; + return $map; +}; + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::Update - Update action + +=head1 DESCRIPTION + +Provides a C<update> action, which sets up an L<Action Viewport|Reaction::UI::Viewport::Action> +by calling C<action_for> on the object located in the C<object> slot of the +C<stash>. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::Object', + 'Reaction::UI::Controller::Role::Action::Update' + ); + + __PACKAGE__->config( action => { + object => { Chained => 'base' }, + update => { Chained => 'object' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + + sub on_update_apply_callback{ #optional callback + my($self, $c, $vp, $result) = @_; + ... + } + + sub on_update_close_callback{ #optional callback + my($self, $c, $vp) = @_; + ... + } + +=head1 ROLES CONSUMED + +This role also consumes the following roles: + +=over4 + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=back + +=head1 REQUIRED METHODS + +The following methods must be provided by the consuming class: + +=over4 + +=item C<make_context_closure> + +=back + +=head1 ACTIONS + +=head2 update + +Chain endpoint with no args, sets up the viewport with the appropriate action. +If the methods C<on_update_apply_callback> and C<on_update_close_callback> are +present in the consuming class, they will be used as callbacks in the viewport. + +=head1 METHODS + +=head2 _build_action_viewport_map + +Extends to set the C<delete> key in the map to L<Reaction::UI::ViewPort::Action> + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/Action/View.pm b/lib/Reaction/UI/Controller/Role/Action/View.pm new file mode 100644 index 0000000..ce7bb8f --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/Action/View.pm @@ -0,0 +1,111 @@ +package Reaction::UI::Controller::Role::Action::View; + +use Moose::Role -traits => 'MethodAttributes'; +use Reaction::UI::ViewPort::Object; + +requires 'setup_viewport'; + +sub view :Action :Args(0) { + my ($self, $c) = @_; + $self->setup_viewport($c, { model => $c->stash->{object} }); +} + +around _build_action_viewport_map => sub { + my $orig = shift; + my $map = shift->$orig( @_ ); + $map->{view} = 'Reaction::UI::ViewPort::Object'; + return $map; +}; + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::Action::View - View action + +=head1 DESCRIPTION + +Provides a C<view> action, which sets up an L<Object Viewport|Reaction::UI::Viewport::Object> +using the object located in the C<object> slot of the C<stash>. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with( + 'Reaction::UI::Controller::Role::GetCollection', + 'Reaction::UI::Controller::Role::Action::Simple', + 'Reaction::UI::Controller::Role::Action::Object', + 'Reaction::UI::Controller::Role::Action::View' + ); + + __PACKAGE__->config( action => { + object => { Chained => 'base' }, + view => { Chained => 'object' }, + } ); + + sub base :Chained('/base') :CaptureArgs(0) { + ... + } + + +=head1 ROLES CONSUMED + +This role also consumes the following roles: + +=over4 + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=back + +=head1 ACTIONS + +=head2 view + +Chain endpoint with no args, sets up the viewport with the appropriate viewport. + +=head1 METHODS + +=head2 _build_action_viewport_map + +Extends to set the C<view> key in the map to L<Reaction::UI::ViewPort::Object> + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::GetCollection> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut diff --git a/lib/Reaction/UI/Controller/Role/GetCollection.pm b/lib/Reaction/UI/Controller/Role/GetCollection.pm new file mode 100644 index 0000000..8f40ce2 --- /dev/null +++ b/lib/Reaction/UI/Controller/Role/GetCollection.pm @@ -0,0 +1,104 @@ +package Reaction::UI::Controller::Role::GetCollection; + +use Moose::Role -traits => 'MethodAttributes'; + +has model_name => (isa => 'Str', is => 'rw', required => 1); +has collection_name => (isa => 'Str', is => 'rw', required => 1); + +sub get_collection { + my ($self, $c) = @_; + my $model = $c->model( $self->model_name ); + confess "Failed to find Catalyst model named: " . $self->model_name + unless $model; + my $collection = $self->collection_name; + if( my $meth = $model->can( $collection ) ){ + return $model->$meth; + } elsif ( my $meta = $model->can('meta') ){ + if ( my $attr = $model->$meta->find_attribute_by_name($collection) ) { + my $reader = $attr->get_read_method; + return $model->$reader; + } + } + confess "Failed to find collection $collection"; +} + +1; + +__END__; + +=head1 NAME + +Reaction::UI::Controller::Role::GetCollection + +=head1 DESCRIPTION + +Provides a C<get_collection> method, which fetches an C<Collection> object +from a specified model. + +=head1 SYNOPSYS + + package MyApp::Controller::Foo; + + use base 'Reaction::Controller'; + use Reaction::Class; + + with 'Reaction::UI::Controller::Role::GetCollection'; + + __PACKAGE__->config( model_name => 'MyAppIM', collection_name => 'foos' ); + + sub bar :Local { + my($self, $c) = @_; + my $obj = $self->get_collection($c)->find( $some_key ); + } + +=head1 ATTRIBUTES + +=head2 model_name + +The name of the model this controller will use as it's data source. Should be a +name that can be passed to C<$C-E<gt>model> + +=head2 collection_name + +The name of the collection whithin the model that this Controller will be +utilizing. + +=head1 METHODS + +=head2 get_collection $c + +Returns an instance of the collection this controller uses. + +=head1 SEE ALSO + +=over4 + +=item L<Reaction::UI::Controller> + +=item L<Reaction::UI::Controller::Role::Action::Simple> + +=item L<Reaction::UI::Controller::Role::Action::Object> + +=item L<Reaction::UI::Controller::Role::Action::List> + +=item L<Reaction::UI::Controller::Role::Action::View> + +=item L<Reaction::UI::Controller::Role::Action::Create> + +=item L<Reaction::UI::Controller::Role::Action::Update> + +=item L<Reaction::UI::Controller::Role::Action::Delete> + +=item L<Reaction::UI::Controller::Role::Action::DeleteAll> + +=back + +=head1 AUTHORS + +See L<Reaction::Class> for authors. + +=head1 LICENSE + +See L<Reaction::Class> for the license. + +=cut |