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