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