960669591dc732f040e4f4a8ecfc0698ef2a30b3
[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::ListView';
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 => ListView,
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 $attr  = $model->meta->find_attribute_by_name( $self->collection_name );
33   my $reader = $attr->get_read_method;
34   return $model->$reader;
35 }
36
37 sub base :Action :CaptureArgs(0) {
38   my ($self, $c) = @_;
39 }
40
41 sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
42   my ($self, $c, $key) = @_;
43   my $object = $self->get_collection($c)->find($key);
44   confess "Object? what object?" unless $object; # should be a 404.
45   $c->stash(object => $object);
46 }
47
48 sub list :Chained('base') :PathPart('') :Args(0) {
49   my ($self, $c) = @_;
50   $c->forward(basic_page => [{ collection => $self->get_collection($c) }]);
51 }
52
53 sub view :Chained('object') :Args(0) {
54   my ($self, $c) = @_;
55   $c->forward(basic_page => [{ model => $c->stash->{object} }]);
56 }
57
58 sub basic_page : Private {
59   my ($self, $c, $vp_args) = @_;
60   my $action_name = $c->stack->[-2]->name;
61   return $self->push_viewport
62     (
63      $self->action_viewport_map->{$action_name},
64      %{ $vp_args || {} },
65      %{ $self->action_viewport_args->{$action_name} || {} },
66     );
67 }
68
69 1;
70
71
72 __END__;
73
74 =head1 NAME
75
76 Reaction::UI::Widget::Controller
77
78 =head1 DESCRIPTION
79
80 Controller class used to make displaying collections easier.
81 Inherits from L<Reaction::UI::Controller>.
82
83 =head1 ATTRIBUTES
84
85 =head2 model_name
86
87 The name of the model this controller will use as it's data source. Should be a name
88 that can be passed to C<$C-E<gt>model>
89
90 =head2 collection_name
91
92 The name of the collection whithin the model that this Controller will be utilizing.
93
94 =head2 action_viewport_map
95
96 =over 4
97
98 =item B<_build_action_viewport_map> - Provided builder method, see METHODS
99
100 =item B<has_action_viewport_map> - Auto generated predicate
101
102 =item B<clear_action_viewport_map>- Auto generated clearer method
103
104 =back
105
106 Read-write lazy building hashref. The keys should match action names in the Controller
107 and the value should be the ViewPort class that this action should use.
108  See method C<basic_page> for more info.
109
110 =head action_viewport_args
111
112 Read-write lazy building hashref. Additional ViewPort arguments for the action named
113 as the key in the controller.  See method C<basic_page> for more info.
114
115 =over 4
116
117 =item B<_build_action_viewport_args> - Provided builder method, see METHODS
118
119 =item B<has_action_viewport_args> - Auto generated predicate
120
121 =item B<clear_action_viewport_args>- Auto generated clearer method
122
123 =back
124
125 =head1 METHODS
126
127 =head2 get_collection $c
128
129 Returns an instance of the collection this controller uses.
130
131 =head2 _build_action_viewport_map
132
133 Provided builder for C<action_viewport_map>. Returns a hash with two items:
134
135     list => 'Reaction::UI::ViewPort::ListView',
136     view => 'Reaction::UI::ViewPort::Object',
137
138 =head2 _build_action_viewport_args
139
140 Returns an empty hashref.
141
142 =head1 ACTIONS
143
144 =head2 base
145
146 Chain link, no-op.
147
148 =head2 list
149
150 Chain link, chained to C<base> forwards to basic page passing one custom argument,
151 C<collection> which includes an instance of the current collection.
152
153 The default ViewPort for this action is C<Reaction::UI::ViewPort::ListView> and can be
154 changed by altering the C<action_viewport_map> attribute hash.
155
156 =head2 object
157
158 Chain link, chained to C<base>, captures one argument, 'id'. Attempts to find a single
159 object by searching for a member of the current collection which has a Primary Key or
160 Unique constraint matching that argument. If the object is found it is stored in the
161  stash under the C<object> key.
162
163 =head2 view
164
165 Chain link, chained to C<object>. Forwards to C<basic page> with one custom vp argument
166  of C<object>, which is the object located in the previous chain link of the same name.
167
168 The default ViewPort for this action is C<Reaction::UI::ViewPort::Object> and can be
169 changed by altering the C<action_viewport_map> attribute hash.
170
171 =head2 basic_page
172
173 Private action, accepts one argument, a hashref of viewport arguments (C<$vp_args>).
174  It will automatically determine the action name using the catalyst stack and call
175 C<push_viewport> with the ViewPort class name contained in the C<action_viewport_map>
176 and arguments of C<$vp_args> and the arguments contained in C<action_viewport_args>,
177 if any.
178
179 =head1 AUTHORS
180
181 See L<Reaction::Class> for authors.
182
183 =head1 LICENSE
184
185 See L<Reaction::Class> for the license.
186
187 =cut