X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FReaction%2FUI%2FController%2FCollection.pm;h=7597d0fa75363e9cf786913b4aa231d9d2090ade;hb=7ece76fce1b940dd3ba81166254d971d8ff1d991;hp=683473e4fbbf2c5b5f9b696eae9790a83eb213d3;hpb=0ccdac9b6e6c486a66a213d48ab9e31eaec2cad4;p=catagits%2FReaction.git diff --git a/lib/Reaction/UI/Controller/Collection.pm b/lib/Reaction/UI/Controller/Collection.pm index 683473e..7597d0f 100644 --- a/lib/Reaction/UI/Controller/Collection.pm +++ b/lib/Reaction/UI/Controller/Collection.pm @@ -5,36 +5,96 @@ use warnings; use base 'Reaction::UI::Controller'; use Reaction::Class; -use aliased 'Reaction::UI::ViewPort::ListView'; +use aliased 'Reaction::UI::ViewPort::Collection::Grid'; use aliased 'Reaction::UI::ViewPort::Object'; -has 'model_name' => (isa => 'Str', is => 'rw', required => 1); -has 'collection_name' => (isa => 'Str', is => 'rw', required => 1); +has model_name => (isa => 'Str', is => 'rw', required => 1); +has collection_name => (isa => 'Str', is => 'rw', required => 1); -has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); +has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1); has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1); +has default_member_actions => ( + isa => 'ArrayRef', + is => 'rw', + lazy_build => 1 +); + +has default_collection_actions => ( + isa => 'ArrayRef', + is => 'rw', + lazy_build => 1 +); + +sub _build_default_member_actions { ['view'] } + +sub _build_default_collection_actions { [] } + sub _build_action_viewport_map { - return { - list => ListView, - view => Object, - }; + my $self = shift; + my %map; + $map{list} = Grid; + $map{view} = Object; #if grep {$_ eq 'view'} @{$self->default_member_actions}; + return \%map; } sub _build_action_viewport_args { - return { }; + my $self = shift; + my $args = { list => { Member => {} } }; + + my $m_protos = $args->{list}{Member}{action_prototypes} = {}; + for my $action_name( @{ $self->default_member_actions }){ + my $label = join(' ', map { ucfirst } split(/_/, $action_name)); + my $proto = $self->_build_member_action_prototype($label, $action_name); + $m_protos->{$action_name} = $proto; + } + + my $c_protos = $args->{list}{action_prototypes} = {}; + for my $action_name( @{ $self->default_collection_actions }){ + my $label = join(' ', map { ucfirst } split(/_/, $action_name)); + my $proto = $self->_build_collection_action_prototype($label, $action_name); + $c_protos->{$action_name} = $proto; + } + + return $args; +} + +sub _build_member_action_prototype { + my ($self, $label, $action_name) = @_; + return { + label => $label, + uri => sub { + my $action = $self->action_for($action_name); + $_[1]->uri_for($action, [ @{$_[1]->req->captures}, $_[0]->__id ]); + }, + }; +} + +sub _build_collection_action_prototype { + my ($self, $label, $action_name) = @_; + return { + label => $label, + uri => sub { + my $action = $self->action_for($action_name); + $_[1]->uri_for($action, $_[1]->req->captures); + }, + }; } #XXX candidate for futre optimization, should cache reader? 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 $attr = $model->meta->find_attribute_by_name($collection) ) { - my $reader = $attr->get_read_method; - return $model->$reader; + } 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"; } @@ -52,7 +112,8 @@ sub object :Chained('base') :PathPart('id') :CaptureArgs(1) { sub list :Chained('base') :PathPart('') :Args(0) { my ($self, $c) = @_; - $self->basic_page($c, { collection => $self->get_collection($c) }); + my $collection = $c->stash->{collection} || $self->get_collection($c); + $self->basic_page($c, { collection => $collection }); } sub view :Chained('object') :Args(0) { @@ -63,17 +124,17 @@ sub view :Chained('object') :Args(0) { sub basic_page { my ($self, $c, $vp_args) = @_; my $action_name = $c->stack->[-1]->name; - return $self->push_viewport + my $vp = $self->action_viewport_map->{$action_name}, + my $args = $self->merge_config_hashes ( - $self->action_viewport_map->{$action_name}, - %{ $vp_args || {} }, - %{ $self->action_viewport_args->{$action_name} || {} }, + $vp_args || {}, + $self->action_viewport_args->{$action_name} || {} , ); + return $self->push_viewport($vp, %$args); } 1; - __END__; =head1 NAME @@ -113,7 +174,7 @@ 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. See method C for more info. -=head action_viewport_args +=head2 action_viewport_args Read-write lazy building hashref. Additional ViewPort arguments for the action named as the key in the controller. See method C for more info. @@ -128,6 +189,40 @@ named as the key in the controller. See method C for more info. =back +=head2 default_member_actions + +Read-write lazy building arrayref. The names of the member actions (the actions +that apply to each member of the collection and typically have an object as a +target e.g. update,delete) to be enabled by default. By default, this is only +'view' + +=over 4 + +=item B<_build_default_member_actions> - Provided builder method, see METHODS + +=item B - Auto generated predicate + +=item B- Auto generated clearer method + +=back + +=head2 default_collection_actions + +Read-write lazy building arrayref. The names of the collection actions (the +actions that apply to the entire collection and typically have a collection as +a target e.g. create, delete_all) to be enabled by default. By default, this +is only empty. + +=over 4 + +=item B<_build_default_member_actions> - Provided builder method, see METHODS + +=item B - Auto generated predicate + +=item B- Auto generated clearer method + +=back + =head1 METHODS =head2 get_collection $c @@ -136,14 +231,41 @@ Returns an instance of the collection this controller uses. =head2 _build_action_viewport_map -Provided builder for C. Returns a hash with two items: +Provided builder for C. Returns a hash containing: - list => 'Reaction::UI::ViewPort::ListView', + list => 'Reaction::UI::ViewPort::Collection::Grid', view => 'Reaction::UI::ViewPort::Object', =head2 _build_action_viewport_args -Returns an empty hashref. +By default will reurn a hashref containing action prototypes for all default +member and collection actions. The prototype URI generators are generated by +C<_build_member_action_prototype> and C<_build_collection_action_prototype> +respectively and labels are the result of replacing underscores in the name +with spaces and capitalizing the first letter. If you plan to use custom +actions that are not supported by this scheme or you would like to customize +the values it is suggested you wrap / override this method. + +Default output for a controller having only 'view' enabled: + + { list => { + action_prototypes => {}, + Member => { + action_prototypes => { + view => {label => 'View', uri => sub{...} }, + }, + }, + }, + } + +=head2 _build_member_action_prototype $label, $action_name + +Creates an action prototype suitable for creating action links in +L. C<$action_name> should be the name of +a Catalyst action in this controller.The prototype will generate a URI +based on the action, current captures. + +=head2 _build_collection_action_prototype $label, $action_name =head2 basic_page $c, \%vp_args @@ -183,7 +305,7 @@ action link. The default ViewPort for this action is C and can be changed by altering the C attribute hash. -=SEE ALSO +=head1 SEE ALSO L