Make pod valid.
[catagits/Reaction.git] / lib / Reaction / UI / Controller / Collection.pm
1 package Reaction::UI::Controller::Collection;
2
3 use strict;
4 use warnings;
5 use base 'Reaction::UI::Controller';
6 use Reaction::Class;
7
8 use aliased 'Reaction::UI::ViewPort::Collection::Grid';
9 use aliased 'Reaction::UI::ViewPort::Object';
10
11 has 'model_name'      => (isa => 'Str', is => 'rw', required => 1);
12 has 'collection_name' => (isa => 'Str', is => 'rw', required => 1);
13
14 has action_viewport_map  => (isa => 'HashRef', is => 'rw', lazy_build => 1);
15 has action_viewport_args => (isa => 'HashRef', is => 'rw', lazy_build => 1);
16
17 sub _build_action_viewport_map {
18   return {
19           list => Grid,
20           view => Object,
21          };
22 }
23
24 sub _build_action_viewport_args {
25   return { };
26 }
27
28 #XXX candidate for futre optimization, should cache reader?
29 sub get_collection {
30   my ($self, $c) = @_;
31   my $model = $c->model( $self->model_name );
32   my $collection = $self->collection_name;
33   if( my $meth = $model->can( $collection ) ){
34     return $model->$meth;
35   } elsif ( my $attr = $model->meta->find_attribute_by_name($collection) ) {
36     my $reader = $attr->get_read_method;
37     return $model->$reader;
38   }
39   confess "Failed to find collection $collection";
40 }
41
42 sub base :Action :CaptureArgs(0) {
43   my ($self, $c) = @_;
44 }
45
46 sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
47   my ($self, $c, $key) = @_;
48   my $object = $self->get_collection($c)->find($key);
49   $c->detach("/error_404") unless $object;
50   $c->stash(object => $object);
51 }
52
53 sub list :Chained('base') :PathPart('') :Args(0) {
54   my ($self, $c) = @_;
55   $self->basic_page($c, { collection => $self->get_collection($c) });
56 }
57
58 sub view :Chained('object') :Args(0) {
59   my ($self, $c) = @_;
60   $self->basic_page($c, { model => $c->stash->{object} });
61 }
62
63 sub basic_page {
64   my ($self, $c, $vp_args) = @_;
65   my $action_name = $c->stack->[-1]->name;
66   my $vp = $self->action_viewport_map->{$action_name},
67   my $args = $self->merge_config_hashes
68     (
69      $vp_args || {},
70      $self->action_viewport_args->{$action_name} || {} ,
71     );
72   return $self->push_viewport($vp, %$args);
73 }
74
75 1;
76
77
78 __END__;
79
80 =head1 NAME
81
82 Reaction::UI::Controller
83
84 =head1 DESCRIPTION
85
86 Controller class used to make displaying collections easier.
87 Inherits from L<Reaction::UI::Controller>.
88
89 =head1 ATTRIBUTES
90
91 =head2 model_name
92
93 The name of the model this controller will use as it's data source. Should be a
94 name that can be passed to C<$C-E<gt>model>
95
96 =head2 collection_name
97
98 The name of the collection whithin the model that this Controller will be
99 utilizing.
100
101 =head2 action_viewport_map
102
103 =over 4
104
105 =item B<_build_action_viewport_map> - Provided builder method, see METHODS
106
107 =item B<has_action_viewport_map> - Auto generated predicate
108
109 =item B<clear_action_viewport_map>- Auto generated clearer method
110
111 =back
112
113 Read-write lazy building hashref. The keys should match action names in the
114 Controller and the value should be the ViewPort class that this action should
115 use. See method C<basic_page> for more info.
116
117 =head2 action_viewport_args
118
119 Read-write lazy building hashref. Additional ViewPort arguments for the action
120 named as the key in the controller.  See method C<basic_page> for more info.
121
122 =over 4
123
124 =item B<_build_action_viewport_args> - Provided builder method, see METHODS
125
126 =item B<has_action_viewport_args> - Auto generated predicate
127
128 =item B<clear_action_viewport_args>- Auto generated clearer method
129
130 =back
131
132 =head1 METHODS
133
134 =head2 get_collection $c
135
136 Returns an instance of the collection this controller uses.
137
138 =head2 _build_action_viewport_map
139
140 Provided builder for C<action_viewport_map>. Returns a hash with two items:
141
142     list => 'Reaction::UI::ViewPort::ListView',
143     view => 'Reaction::UI::ViewPort::Object',
144
145 =head2 _build_action_viewport_args
146
147 Returns an empty hashref.
148
149 =head2 basic_page $c, \%vp_args
150
151 Accepts two arguments, context, and a hashref of viewport arguments. It will
152 automatically determine the action name using the catalyst stack and call
153 C<push_viewport> with the ViewPort class name contained in the
154 C<action_viewport_map> with a set of options determined by merging C<$vp_args>
155 and the arguments contained in C<action_viewport_args>, if any.
156
157 =head1 ACTIONS
158
159 =head2 base
160
161 Chain link, no-op.
162
163 =head2 list
164
165 Chain link, chained to C<base>. C<list> fetches the collection for the model
166 and calls C<basic_page> with a single argument, C<collection>.
167
168 The default ViewPort for this action is C<Reaction::UI::ViewPort::ListView> and
169 can be changed by altering the C<action_viewport_map> attribute hash.
170
171 =head2 object
172
173 Chain link, chained to C<base>, captures one argument, 'id'. Attempts to find
174 a single object by searching for a member of the current collection which has a
175 Primary Key or Unique constraint matching that argument. If the object is found
176 it is stored in the stash under the C<object> key.
177
178 =head2 view
179
180 Chain link, chained to C<object>. Calls C<basic page> with one argument,
181 C<model>, which contains an instance of the object fetched by the C<object>
182 action link.
183
184 The default ViewPort for this action is C<Reaction::UI::ViewPort::Object> and
185 can be changed by altering the C<action_viewport_map> attribute hash.
186
187 =head1 SEE ALSO
188
189 L<Reaction::UI::Controller>
190
191 =head1 AUTHORS
192
193 See L<Reaction::Class> for authors.
194
195 =head1 LICENSE
196
197 See L<Reaction::Class> for the license.
198
199 =cut