checking in more pod, some fixes for weird bugs, a manual for migration, an extra...
[catagits/Reaction.git] / lib / Reaction / UI / Controller / Collection / CRUD.pm
1 package Reaction::UI::Controller::Collection::CRUD;
2
3 use strict;
4 use warnings;
5 use base 'Reaction::UI::Controller::Collection';
6 use Reaction::Class;
7
8 use aliased 'Reaction::UI::ViewPort::Action';
9 use aliased 'Reaction::UI::ViewPort::ListView';
10
11 sub _build_action_viewport_map {
12   my $self = shift;
13   my $map = $self->next::method(@_);
14   $map->{list} = ListView if exists $map->{list};
15
16   #my %allowed = map { $_ => undef }
17   #  ( @{$self->default_member_actions}, @{$self->default_collection_actions} );
18   my @local_actions = qw/create update delete delete_all/;
19   #$map->{$_} = Action for grep { exists $allowed{$_} } @local_actions;
20
21   $map->{$_} = Action for @local_actions;
22   return $map;
23 }
24
25 sub _build_default_member_actions {
26   [ @{shift->next::method(@_)}, qw/update delete/ ];
27 }
28
29 sub _build_default_collection_actions {
30   [ @{shift->next::method(@_)}, qw/create delete_all/ ];
31 }
32
33 sub get_model_action {
34   my ($self, $c, $name, $target) = @_;
35   return $target->action_for($name, ctx => $c);
36 }
37
38 sub create :Chained('base') :PathPart('create') :Args(0) {
39   my ($self, $c) = @_;
40   my $vp_args = {
41     on_apply_callback => sub { $self->after_create_callback($c => @_); },
42     on_close_callback => sub { $self->on_create_close_callback($c => @_) }
43   };
44   $self->basic_model_action( $c, $vp_args);
45 }
46
47 sub delete_all :Chained('base') :PathPart('delete_all') :Args(0) {
48   my ($self, $c) = @_;
49   $self->basic_model_action( $c, {
50     on_close_callback => sub { $self->on_delete_all_close_callback($c => @_) }
51   });
52 }
53
54 sub on_delete_all_close_callback {
55   my($self, $c) = @_;
56   $self->redirect_to($c, 'list');
57 }
58
59 sub after_create_callback {
60   my ($self, $c, $vp, $result) = @_;
61   return $self->redirect_to
62     ( $c, 'update', [ @{$c->req->captures}, $result->id ] );
63 }
64
65 sub on_create_close_callback {
66   my($self, $c, $vp) = @_;
67   $self->redirect_to( $c, 'list' );
68 }
69
70 sub update :Chained('object') :Args(0) {
71   my ($self, $c) = @_;
72   my $vp_args = {
73     on_close_callback => sub { $self->on_update_close_callback($c => @_ ) }
74   };
75   $self->basic_model_action( $c, $vp_args);
76 }
77
78 sub on_update_close_callback {
79   my($self, $c) = @_;
80   #this needs a better solution. currently thinking about it
81   my @cap = @{$c->req->captures};
82   pop(@cap); # object id
83   $self->redirect_to($c, 'list', \@cap);
84 }
85
86 sub delete :Chained('object') :Args(0) {
87   my ($self, $c) = @_;
88   my $vp_args = {
89     on_close_callback => sub { $self->on_update_close_callback($c => @_) }
90   };
91   $self->basic_model_action( $c, $vp_args);
92 }
93
94 sub basic_model_action {
95   my ($self, $c, $vp_args) = @_;
96
97   my $target = exists $c->stash->{object} ?
98     $c->stash->{object} : $self->get_collection($c);
99
100   my $action_name = join('', map{ ucfirst } split('_', $c->stack->[-1]->name));
101   my $model = $self->get_model_action($c, $action_name, $target);
102   return $self->basic_page($c, { model => $model, %{$vp_args||{}} });
103 }
104
105 1;
106
107 __END__
108
109 =head1 NAME
110
111 Reaction::UI::Controller::CRUD - Basic CRUD functionality for Reaction::InterfaceModel data
112
113 =head1 DESCRIPTION
114
115 Controller class which extends L<Reaction::UI::Controller::Collection> to 
116 provide basic Create / Update / Delete / DeleteAll actions.
117
118 Building on the base of the Collection controller this controller allows you to
119 easily create complex and highly flexible CRUD functionality for your 
120 InterfaceModel models by providing a simple way to render and process your
121 custom InterfaceModel Actions and customize built-ins.
122
123 =head1 METHODS
124
125 =head2 get_model_action $c, $action_name, $target_im
126
127 Get an instance of the C<$action_name> 
128 L<InterfaceModel::Action|Reaction::InterfaceModel::Action> for model C<$target>
129 This action is suitable for passing to an 
130 C<Action|Reaction::UI::ViewPort::Action> viewport
131
132 =head2 after_create_callback $c, $vp, $result
133
134 When a <create> action is applied, move the user to the new object's,
135 C<update> page.
136
137 =head2 basic_model_action $c, \%vp_args
138
139 Extension to C<basic_page> which automatically instantiates an 
140 L<InterfaceModel::Action|Reaction::InterfaceModel::Action> with the right
141 data target using C<get_model_action>
142
143 =head2 _build_action_viewport_map
144
145 Map C<create>, C<update>, C<delete> and C<delete_all> to use the
146 L<Action|Reaction::UI::ViewPort::Action> viewport by default and have C<list>
147 use L<ListView|Reaction::UI::ViewPort::ListView> by default.
148
149 =head2 _build_default_member_actions
150
151 Add C<update> and C<delete> to the list of default actions.
152
153 =head2 _build_default_collection_actions
154
155 Add C<create> and C<delete_all> to the list of default actions.
156
157 =head1 ACTIONS
158
159 =head2 create
160
161 Chaned to C<base>. Create a new member of the collection represented by 
162 this controller. By default it attaches the C<after_create_callback> to
163 DWIM after apply operations.
164
165 See L<Create|Reaction::InterfaceModel::Action::DBIC::ResultSet::Create>
166  for more info.
167
168 =head2 delete_all
169
170 Chained to B<base>, delete all the members of the B<collection>. In most cases
171 this is very much like a C<TRUNCATE> operation.
172
173 See L<DeleteAll|Reaction::InterfaceModel::Action::DBIC::ResultSet::DeleteAll>
174  for more info.
175
176 =head2 update
177
178 Chained to C<object>, update a single object.
179
180 See L<Update|Reaction::InterfaceModel::Action::DBIC::Result::Update>
181  for more info.
182
183 =head2 delete
184
185 Chained to C<object>, delete a single object.
186
187 See L<Delete|Reaction::InterfaceModel::Action::DBIC::Result::Delete>
188  for more info.
189
190 =head1 SEE ALSO
191
192 L<Reaction::UI::Controller::Collection>, L<Reaction::UI::Controller>
193
194 =head1 AUTHORS
195
196 See L<Reaction::Class> for authors.
197
198 =head1 LICENSE
199
200 See L<Reaction::Class> for the license.
201
202 =cut