Fix the POD test
[catagits/Reaction.git] / lib / Reaction / UI / Controller / Collection.pm
CommitLineData
89b70ba7 1package Reaction::UI::Controller::Collection;
2
3use strict;
4use warnings;
5use base 'Reaction::UI::Controller';
6use Reaction::Class;
7
8cc0103d 8use aliased 'Reaction::UI::ViewPort::Collection::Grid';
c8fbb8ad 9use aliased 'Reaction::UI::ViewPort::Object';
89b70ba7 10
37728bba 11has model_name => (isa => 'Str', is => 'rw', required => 1);
12has collection_name => (isa => 'Str', is => 'rw', required => 1);
89b70ba7 13
37728bba 14has action_viewport_map => (isa => 'HashRef', is => 'rw', lazy_build => 1);
89b70ba7 15has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1);
16
37728bba 17has default_member_actions => (
18 isa => 'ArrayRef',
19 is => 'rw',
20 lazy_build => 1
21);
22
23has default_collection_actions => (
24 isa => 'ArrayRef',
25 is => 'rw',
26 lazy_build => 1
27);
28
29sub _build_default_member_actions { ['view'] }
30
31sub _build_default_collection_actions { [] }
32
89b70ba7 33sub _build_action_viewport_map {
37728bba 34 my $self = shift;
35 my %map;
36 $map{list} = Grid;
b3cb974a 37 $map{view} = Object; #if grep {$_ eq 'view'} @{$self->default_member_actions};
37728bba 38 return \%map;
89b70ba7 39}
40
41sub _build_action_viewport_args {
37728bba 42 my $self = shift;
43 my $args = { list => { Member => {} } };
44
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;
50 }
51
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;
57 }
58
59 return $args;
60}
61
62sub _build_member_action_prototype {
63 my ($self, $label, $action_name) = @_;
64 return {
65 label => $label,
66 uri => sub {
67 my $action = $self->action_for($action_name);
68 $_[1]->uri_for($action, [ @{$_[1]->req->captures}, $_[0]->__id ]);
69 },
70 };
71}
72
73sub _build_collection_action_prototype {
74 my ($self, $label, $action_name) = @_;
75 return {
76 label => $label,
77 uri => sub {
78 my $action = $self->action_for($action_name);
79 $_[1]->uri_for($action, $_[1]->req->captures);
80 },
81 };
89b70ba7 82}
83
89b70ba7 84#XXX candidate for futre optimization, should cache reader?
85sub get_collection {
86 my ($self, $c) = @_;
87 my $model = $c->model( $self->model_name );
09d2d18d 88 confess "Failed to find Catalyst model named: " . $self->model_name
89 unless $model;
0ccdac9b 90 my $collection = $self->collection_name;
91 if( my $meth = $model->can( $collection ) ){
92 return $model->$meth;
09d2d18d 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;
97 }
0ccdac9b 98 }
99 confess "Failed to find collection $collection";
89b70ba7 100}
101
b3832dbc 102sub base :Action :CaptureArgs(0) {
89b70ba7 103 my ($self, $c) = @_;
89b70ba7 104}
105
106sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
107 my ($self, $c, $key) = @_;
1810d302 108 my $object = $self->get_collection($c)->find($key);
cb92a3a3 109 $c->detach("/error_404") unless $object;
1810d302 110 $c->stash(object => $object);
89b70ba7 111}
112
b3832dbc 113sub list :Chained('base') :PathPart('') :Args(0) {
114 my ($self, $c) = @_;
b68d6a35 115 $self->basic_page($c, { collection => $self->get_collection($c) });
b3832dbc 116}
117
89b70ba7 118sub view :Chained('object') :Args(0) {
119 my ($self, $c) = @_;
b68d6a35 120 $self->basic_page($c, { model => $c->stash->{object} });
89b70ba7 121}
122
aee256be 123sub basic_page {
89b70ba7 124 my ($self, $c, $vp_args) = @_;
aee256be 125 my $action_name = $c->stack->[-1]->name;
380db949 126 my $vp = $self->action_viewport_map->{$action_name},
127 my $args = $self->merge_config_hashes
89b70ba7 128 (
380db949 129 $vp_args || {},
130 $self->action_viewport_args->{$action_name} || {} ,
89b70ba7 131 );
380db949 132 return $self->push_viewport($vp, %$args);
89b70ba7 133}
134
1351;
b3832dbc 136
b3832dbc 137__END__;
138
139=head1 NAME
140
7d3fe0d2 141Reaction::UI::Controller
b3832dbc 142
143=head1 DESCRIPTION
144
145Controller class used to make displaying collections easier.
146Inherits from L<Reaction::UI::Controller>.
147
148=head1 ATTRIBUTES
149
150=head2 model_name
151
0ccdac9b 152The name of the model this controller will use as it's data source. Should be a
7d3fe0d2 153name that can be passed to C<$C-E<gt>model>
b3832dbc 154
155=head2 collection_name
156
0ccdac9b 157The name of the collection whithin the model that this Controller will be
7d3fe0d2 158utilizing.
b3832dbc 159
160=head2 action_viewport_map
161
162=over 4
163
164=item B<_build_action_viewport_map> - Provided builder method, see METHODS
165
166=item B<has_action_viewport_map> - Auto generated predicate
167
168=item B<clear_action_viewport_map>- Auto generated clearer method
169
170=back
171
0ccdac9b 172Read-write lazy building hashref. The keys should match action names in the
173Controller and the value should be the ViewPort class that this action should
7d3fe0d2 174use. See method C<basic_page> for more info.
b3832dbc 175
de5b3fab 176=head2 action_viewport_args
b3832dbc 177
0ccdac9b 178Read-write lazy building hashref. Additional ViewPort arguments for the action
7d3fe0d2 179named as the key in the controller. See method C<basic_page> for more info.
b3832dbc 180
181=over 4
182
183=item B<_build_action_viewport_args> - Provided builder method, see METHODS
184
185=item B<has_action_viewport_args> - Auto generated predicate
186
187=item B<clear_action_viewport_args>- Auto generated clearer method
188
189=back
190
b3cb974a 191=head2 default_member_actions
192
193Read-write lazy building arrayref. The names of the member actions (the actions
194that apply to each member of the collection and typically have an object as a
195target e.g. update,delete) to be enabled by default. By default, this is only
196'view'
197
198=over 4
199
f7c1ee8a 200=item B<_build_defualt_member_actions> - Provided builder method, see METHODS
b3cb974a 201
202=item B<has_default_member_actions> - Auto generated predicate
203
204=item B<clear_default_member_actions>- Auto generated clearer method
205
206=back
207
208=head2 default_collection_actions
209
210Read-write lazy building arrayref. The names of the collection actions (the
211actions that apply to the entire collection and typically have a collection as
212a target e.g. create, delete_all) to be enabled by default. By default, this
213is only empty.
214
215=over 4
216
f7c1ee8a 217=item B<_build_defualt_member_actions> - Provided builder method, see METHODS
b3cb974a 218
219=item B<has_default_member_actions> - Auto generated predicate
220
221=item B<clear_default_member_actions>- Auto generated clearer method
222
223=back
224
b3832dbc 225=head1 METHODS
226
227=head2 get_collection $c
228
229Returns an instance of the collection this controller uses.
230
231=head2 _build_action_viewport_map
232
b3cb974a 233Provided builder for C<action_viewport_map>. Returns a hash containing:
b3832dbc 234
b3cb974a 235 list => 'Reaction::UI::ViewPort::Collection::Grid',
b3832dbc 236 view => 'Reaction::UI::ViewPort::Object',
237
238=head2 _build_action_viewport_args
239
b3cb974a 240By default will reurn a hashref containing action prototypes for all default
241member and collection actions. The prototype URI generators are generated by
242C<_build_member_action_prototype> and C<_build_collection_action_prototype>
243respectively and labels are the result of replacing underscores in the name
244with spaces and capitalizing the first letter. If you plan to use custom
245actions that are not supported by this scheme or you would like to customize
246the values it is suggested you wrap / override this method.
247
248Default output for a controller having only 'view' enabled:
249
250 { list => {
251 action_prototypes => {},
252 Member => {
253 action_prototypes => {
254 view => {label => 'View', uri => sub{...} },
255 },
256 },
257 },
258 }
259
260=head2 _build_member_action_prototype $label, $action_name
261
262Creates an action prototype suitable for creating action links in
263L<Reaction::UI::ViewPort::Role::Actions>. C<$action_name> should be the name of
264a Catalyst action in this controller.The prototype will generate a URI
265based on the action, current captures.
266
267=head2 _build_collection_action_prototype $label, $action_name
b3832dbc 268
7d3fe0d2 269=head2 basic_page $c, \%vp_args
270
271Accepts two arguments, context, and a hashref of viewport arguments. It will
272automatically determine the action name using the catalyst stack and call
0ccdac9b 273C<push_viewport> with the ViewPort class name contained in the
7d3fe0d2 274C<action_viewport_map> with a set of options determined by merging C<$vp_args>
275and the arguments contained in C<action_viewport_args>, if any.
276
b3832dbc 277=head1 ACTIONS
278
279=head2 base
280
281Chain link, no-op.
282
283=head2 list
284
7d3fe0d2 285Chain link, chained to C<base>. C<list> fetches the collection for the model
286and calls C<basic_page> with a single argument, C<collection>.
b3832dbc 287
7d3fe0d2 288The default ViewPort for this action is C<Reaction::UI::ViewPort::ListView> and
289can be changed by altering the C<action_viewport_map> attribute hash.
b3832dbc 290
291=head2 object
292
0ccdac9b 293Chain link, chained to C<base>, captures one argument, 'id'. Attempts to find
7d3fe0d2 294a single object by searching for a member of the current collection which has a
295Primary Key or Unique constraint matching that argument. If the object is found
296it is stored in the stash under the C<object> key.
b3832dbc 297
298=head2 view
299
7d3fe0d2 300Chain link, chained to C<object>. Calls C<basic page> with one argument,
301C<model>, which contains an instance of the object fetched by the C<object>
302action link.
b3832dbc 303
0ccdac9b 304The default ViewPort for this action is C<Reaction::UI::ViewPort::Object> and
7d3fe0d2 305can be changed by altering the C<action_viewport_map> attribute hash.
b3832dbc 306
de5b3fab 307=head1 SEE ALSO
b3832dbc 308
7d3fe0d2 309L<Reaction::UI::Controller>
b3832dbc 310
311=head1 AUTHORS
312
313See L<Reaction::Class> for authors.
314
315=head1 LICENSE
316
317See L<Reaction::Class> for the license.
318
319=cut