1 package Reaction::UI::Controller::Collection;
5 use base 'Reaction::UI::Controller';
8 use aliased 'Reaction::UI::ViewPort::Collection::Grid';
9 use aliased 'Reaction::UI::ViewPort::Object';
11 has model_name => (isa => 'Str', is => 'rw', required => 1);
12 has collection_name => (isa => 'Str', is => 'rw', required => 1);
14 has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1);
15 has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1);
17 has default_member_actions => (
23 has default_collection_actions => (
29 sub _build_default_member_actions { ['view'] }
31 sub _build_default_collection_actions { [] }
33 sub _build_action_viewport_map {
37 $map{view} = Object; #if grep {$_ eq 'view'} @{$self->default_member_actions};
41 sub _build_action_viewport_args {
43 my $args = { list => { Member => {} } };
45 my $m_protos = $args->{list}{Member}{action_prototypes} = {};
46 for my $action_name( @{ $self->default_member_actions }){
47 my $label = ucfirst(join(' ', split(/_/, $action_name)));
48 my $proto = $self->_build_member_action_prototype($label, $action_name);
49 $m_protos->{$action_name} = $proto;
52 my $c_protos = $args->{list}{action_prototypes} = {};
53 for my $action_name( @{ $self->default_collection_actions }){
54 my $label = ucfirst(join(' ', split(/_/, $action_name)));
55 my $proto = $self->_build_collection_action_prototype($label, $action_name);
56 $c_protos->{$action_name} = $proto;
62 sub _build_member_action_prototype {
63 my ($self, $label, $action_name) = @_;
67 my $action = $self->action_for($action_name);
68 $_[1]->uri_for($action, [ @{$_[1]->req->captures}, $_[0]->__id ]);
73 sub _build_collection_action_prototype {
74 my ($self, $label, $action_name) = @_;
78 my $action = $self->action_for($action_name);
79 $_[1]->uri_for($action, $_[1]->req->captures);
84 #XXX candidate for futre optimization, should cache reader?
87 my $model = $c->model( $self->model_name );
88 confess "Failed to find Catalyst model named: " . $self->model_name
90 my $collection = $self->collection_name;
91 if( my $meth = $model->can( $collection ) ){
93 } elsif ( my $meta = $model->can('meta') ){
94 if ( my $attr = $model->$meta->find_attribute_by_name($collection) ) {
95 my $reader = $attr->get_read_method;
96 return $model->$reader;
99 confess "Failed to find collection $collection";
102 sub base :Action :CaptureArgs(0) {
106 sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
107 my ($self, $c, $key) = @_;
108 my $object = $self->get_collection($c)->find($key);
109 $c->detach("/error_404") unless $object;
110 $c->stash(object => $object);
113 sub list :Chained('base') :PathPart('') :Args(0) {
115 my $collection = $c->stash->{collection} || $self->get_collection($c);
116 $self->basic_page($c, { collection => $collection });
119 sub view :Chained('object') :Args(0) {
121 $self->basic_page($c, { model => $c->stash->{object} });
125 my ($self, $c, $vp_args) = @_;
126 my $action_name = $c->stack->[-1]->name;
127 my $vp = $self->action_viewport_map->{$action_name},
128 my $args = $self->merge_config_hashes
131 $self->action_viewport_args->{$action_name} || {} ,
133 return $self->push_viewport($vp, %$args);
142 Reaction::UI::Controller
146 Controller class used to make displaying collections easier.
147 Inherits from L<Reaction::UI::Controller>.
153 The name of the model this controller will use as it's data source. Should be a
154 name that can be passed to C<$C-E<gt>model>
156 =head2 collection_name
158 The name of the collection whithin the model that this Controller will be
161 =head2 action_viewport_map
165 =item B<_build_action_viewport_map> - Provided builder method, see METHODS
167 =item B<has_action_viewport_map> - Auto generated predicate
169 =item B<clear_action_viewport_map>- Auto generated clearer method
173 Read-write lazy building hashref. The keys should match action names in the
174 Controller and the value should be the ViewPort class that this action should
175 use. See method C<basic_page> for more info.
177 =head2 action_viewport_args
179 Read-write lazy building hashref. Additional ViewPort arguments for the action
180 named as the key in the controller. See method C<basic_page> for more info.
184 =item B<_build_action_viewport_args> - Provided builder method, see METHODS
186 =item B<has_action_viewport_args> - Auto generated predicate
188 =item B<clear_action_viewport_args>- Auto generated clearer method
192 =head2 default_member_actions
194 Read-write lazy building arrayref. The names of the member actions (the actions
195 that apply to each member of the collection and typically have an object as a
196 target e.g. update,delete) to be enabled by default. By default, this is only
201 =item B<_build_defualt_member_actions> - Provided builder method, see METHODS
203 =item B<has_default_member_actions> - Auto generated predicate
205 =item B<clear_default_member_actions>- Auto generated clearer method
209 =head2 default_collection_actions
211 Read-write lazy building arrayref. The names of the collection actions (the
212 actions that apply to the entire collection and typically have a collection as
213 a target e.g. create, delete_all) to be enabled by default. By default, this
218 =item B<_build_defualt_member_actions> - Provided builder method, see METHODS
220 =item B<has_default_member_actions> - Auto generated predicate
222 =item B<clear_default_member_actions>- Auto generated clearer method
228 =head2 get_collection $c
230 Returns an instance of the collection this controller uses.
232 =head2 _build_action_viewport_map
234 Provided builder for C<action_viewport_map>. Returns a hash containing:
236 list => 'Reaction::UI::ViewPort::Collection::Grid',
237 view => 'Reaction::UI::ViewPort::Object',
239 =head2 _build_action_viewport_args
241 By default will reurn a hashref containing action prototypes for all default
242 member and collection actions. The prototype URI generators are generated by
243 C<_build_member_action_prototype> and C<_build_collection_action_prototype>
244 respectively and labels are the result of replacing underscores in the name
245 with spaces and capitalizing the first letter. If you plan to use custom
246 actions that are not supported by this scheme or you would like to customize
247 the values it is suggested you wrap / override this method.
249 Default output for a controller having only 'view' enabled:
252 action_prototypes => {},
254 action_prototypes => {
255 view => {label => 'View', uri => sub{...} },
261 =head2 _build_member_action_prototype $label, $action_name
263 Creates an action prototype suitable for creating action links in
264 L<Reaction::UI::ViewPort::Role::Actions>. C<$action_name> should be the name of
265 a Catalyst action in this controller.The prototype will generate a URI
266 based on the action, current captures.
268 =head2 _build_collection_action_prototype $label, $action_name
270 =head2 basic_page $c, \%vp_args
272 Accepts two arguments, context, and a hashref of viewport arguments. It will
273 automatically determine the action name using the catalyst stack and call
274 C<push_viewport> with the ViewPort class name contained in the
275 C<action_viewport_map> with a set of options determined by merging C<$vp_args>
276 and the arguments contained in C<action_viewport_args>, if any.
286 Chain link, chained to C<base>. C<list> fetches the collection for the model
287 and calls C<basic_page> with a single argument, C<collection>.
289 The default ViewPort for this action is C<Reaction::UI::ViewPort::ListView> and
290 can be changed by altering the C<action_viewport_map> attribute hash.
294 Chain link, chained to C<base>, captures one argument, 'id'. Attempts to find
295 a single object by searching for a member of the current collection which has a
296 Primary Key or Unique constraint matching that argument. If the object is found
297 it is stored in the stash under the C<object> key.
301 Chain link, chained to C<object>. Calls C<basic page> with one argument,
302 C<model>, which contains an instance of the object fetched by the C<object>
305 The default ViewPort for this action is C<Reaction::UI::ViewPort::Object> and
306 can be changed by altering the C<action_viewport_map> attribute hash.
310 L<Reaction::UI::Controller>
314 See L<Reaction::Class> for authors.
318 See L<Reaction::Class> for the license.